Compare commits
14 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b77aac8c57 | |||
| 518a42b20a | |||
| 023c077b2b | |||
| 4912ede42c | |||
| cf3931f529 | |||
| d142010786 | |||
| 8d3a454a6b | |||
| b089cb39e6 | |||
| 72c6b590f1 | |||
| b074b9d453 | |||
| 1fe82c18af | |||
| 04a5641650 | |||
| a25df4368e | |||
| d14ee65af4 |
36 changed files with 640 additions and 81 deletions
11
.imdone/DONE/Components/update-theme.md
Normal file
11
.imdone/DONE/Components/update-theme.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#DONE update theme
|
||||
<!--
|
||||
order:-10
|
||||
completed:2025-02-10T17:02:46+11:00
|
||||
archived:true
|
||||
archivedAt:2025-02-10T17:02:46+11:00
|
||||
originalPath:Components\ThemeDialog.razor
|
||||
originalLine:76
|
||||
-->
|
||||
|
||||
|
||||
11
.imdone/DONE/Components/upload-the-profile-pic.md
Normal file
11
.imdone/DONE/Components/upload-the-profile-pic.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#DONE upload the profile pic
|
||||
<!--
|
||||
order:0
|
||||
completed:2025-02-10T16:51:21+11:00
|
||||
archived:true
|
||||
archivedAt:2025-02-10T16:51:21+11:00
|
||||
originalPath:Components\EditProfilePicDialog.razor
|
||||
originalLine:60
|
||||
-->
|
||||
|
||||
|
||||
61
.imdone/DONE/backlog.md
Normal file
61
.imdone/DONE/backlog.md
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
|
||||
## Must Haves
|
||||
- {check} View [latest statuslog entries](https://api.omg.lol/statuslog/latest)
|
||||
- {check} View [all statuses of a single person](https://api.omg.lol/address/adam/statuses) (get [profile picture](https://profiles.cache.lol/adam/picture) and [statuslog bio](https://api.omg.lol/address/adam/statuses/bio)) Note: I'm calling this the profile page (even though omg.lol profile is a different thing)
|
||||
- {check} [Log in](https://home.omg.lol/oauth/authorize?client_id=ea14dafd3e92cbcf93750c35cd81a031&scope=everything&redirect_uri=https://neatnik.net/adam/bucket/omgloloauth/&response_type=code) and [Authenticate](https://api.omg.lol/#token-get-oauth-exchange-an-authorization-code-for-an-access-token) (then [get all addresses](https://api.omg.lol/account/application/addresses) so we can pick one for other interactions)
|
||||
- {check} Post a [new status](https://api.omg.lol/#token-post-statuslog-share-a-new-status) (checkbox for posting to mastodon)
|
||||
- {check} Log out
|
||||
- {check} Light/Dark themes (based on system theme)
|
||||
|
||||
## Should Haves
|
||||
- {check} Share statuses, etc.
|
||||
- {check} Have a character counter on statuses and a warning if going over length for posting to Mastodon.
|
||||
- {check} Be a share target for creating statuses
|
||||
- {check} View the [address directory](https://api.omg.lol/directory) (showing profile pics and linking to profile page)
|
||||
- {check} Link to it via the account menu (There's not a lot of room in the nav)
|
||||
- {check} View the [now garden](https://api.omg.lol/now/garden) (also, perhaps cache the now garden and link to the now page on a person's profile)
|
||||
- {check} Updated profile page. Shows:
|
||||
- {check} [profile picture](https://profiles.cache.lol/adam/picture)
|
||||
- {check} [statuslog bio](https://api.omg.lol/address/adam/statuses/bio) text
|
||||
- {check} [all statuses](https://api.omg.lol/address/adam/statuses)
|
||||
- {check} Link to now page (if present in [now garden](https://api.omg.lol/now/garden))
|
||||
- {check} Link to profile page (aka web page)
|
||||
- {check} Link to person's some.pics
|
||||
- {check} Link to person's pastebin
|
||||
|
||||
## Want to Haves
|
||||
- {check} [Some.pics feed](https://api.omg.lol/pics) (plus seeing the some.pics of individuals, link on profile)
|
||||
- {check} Be a share target for pictures
|
||||
- {check} [Ephemeral feed](https://eph.emer.al/)
|
||||
- {check} plus posting - ~~if/when an API becomes available~~ (Thanks Adam 😁)
|
||||
- {check} Upload pics
|
||||
- {check} Edit some.pics
|
||||
- {check} delete pics
|
||||
- {check} Edit statuses
|
||||
- {check} delete statuses
|
||||
- {check} Update / manage [now page](https://api.omg.lol/#now-page)
|
||||
- {square} pull to refresh
|
||||
- {check} Follow people (i.e. locally bookmark their statuslog profile)
|
||||
- {check} A combined feed of all statuses and pics of everyone you're following
|
||||
|
||||
## Nice to Haves
|
||||
- {check} Update profile picture
|
||||
- {check} Update / manage statuslog bio
|
||||
- {check} Update / manage [profile/web page](https://api.omg.lol/#web)
|
||||
- {check} including [themes](https://api.omg.lol/#theme)
|
||||
- {check} Update / manage [pastebin](https://api.omg.lol/#pastebin)
|
||||
- {check} share and copy items
|
||||
- {check} view as markup
|
||||
- {check} visible in profile page
|
||||
- {check} visible in feed
|
||||
|
||||
## Current Bugs
|
||||
- {check} ~~Sharing to app multiple times throws an exception~~
|
||||
- {check} ~~Need to update "Loading", "Logging in" and "nothing here" pages to match the splash screen (ish)~~
|
||||
- {check} ~~Empty bio on person/statuses (just remove the div if the bio is empty)~~
|
||||
- {check} ~~Need warnings on pics with no description~~
|
||||
- {check} ~~respond appears on statuses with no external link~~
|
||||
- {check} ~~statuses / pics don't refresh on update/delete~~
|
||||
- {check} ~~own now page isn't showing properly in profile~~
|
||||
- {check} ~~statuses with long words or urls won't wrap.~~
|
||||
- {check} ~~Ephemeral scraping doesn't send a user agent string, so no longer works.~~
|
||||
12
.imdone/DONE/test.md
Normal file
12
.imdone/DONE/test.md
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#DONE test
|
||||
<!--
|
||||
created:2025-02-10T20:44:27+11:00
|
||||
order:-20
|
||||
completed:2025-02-10T20:44:57+11:00
|
||||
archived:true
|
||||
archivedAt:2025-02-10T20:44:57+11:00
|
||||
originalPath:backlog.md
|
||||
originalLine:64
|
||||
-->
|
||||
|
||||
|
||||
16
.imdone/actions/board.js
Normal file
16
.imdone/actions/board.js
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
const path = require('path')
|
||||
|
||||
module.exports = function () {
|
||||
const project = this.project
|
||||
return [
|
||||
{
|
||||
title: "Open in vscode", // This is what displays in the main menu
|
||||
keys: ['alt+o'], // This is the keyboard shortcut
|
||||
icon: "code", // This is the font awesome icon that displays in the main menu
|
||||
action (task) {
|
||||
const url = `vscode://file/${path.join(project.path, task.path)}:${task.line}`
|
||||
project.openUrl(url)
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
4
.imdone/actions/card.js
Normal file
4
.imdone/actions/card.js
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
module.exports = function (task) {
|
||||
const project = this.project
|
||||
return []
|
||||
}
|
||||
101
.imdone/config.yml
Normal file
101
.imdone/config.yml
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
keepEmptyPriority: false
|
||||
languages:
|
||||
.razor:
|
||||
name: razor
|
||||
symbol: "//"
|
||||
block:
|
||||
start: "@*"
|
||||
end: "*@"
|
||||
ignore: "*"
|
||||
code:
|
||||
include_lists:
|
||||
- TODO
|
||||
- DOING
|
||||
- DONE
|
||||
- PLANNING
|
||||
- FIXME
|
||||
- ARCHIVE
|
||||
- HACK
|
||||
- CHANGED
|
||||
- XXX
|
||||
- IDEA
|
||||
- NOTE
|
||||
- REVIEW
|
||||
- WAITING
|
||||
lists:
|
||||
- name: NOTE
|
||||
hidden: false
|
||||
id: 9886o1muwm6yiizyq
|
||||
- name: Past Due Reminders
|
||||
hidden: true
|
||||
ignore: false
|
||||
filter: 'remind = /./ and remind < "${now}" and list != DONE -remind'
|
||||
id: 9886o1muwm6yiizyr
|
||||
- name: What's Due?
|
||||
hidden: true
|
||||
ignore: false
|
||||
filter: 'dueDate < "${in 15 days}" AND list != DONE +dueDate +order'
|
||||
id: 9886o1muwm6yiizys
|
||||
- name: WAITING
|
||||
hidden: false
|
||||
ignore: false
|
||||
id: 9886o10uwm6yovnxl
|
||||
- name: TODO
|
||||
hidden: false
|
||||
id: 9886o1muwm6yiizyt
|
||||
- name: DOING
|
||||
hidden: false
|
||||
id: 9886o1muwm6yiizyu
|
||||
- name: DONE
|
||||
hidden: false
|
||||
ignore: true
|
||||
id: 9886o1muwm6yiizyv
|
||||
- name: Recently Completed
|
||||
filter: 'completedDate > "${14 days ago}" -completed'
|
||||
hidden: false
|
||||
id: 9886o1muwm6yiizyw
|
||||
settings:
|
||||
'0': object Object
|
||||
openIn: default
|
||||
openCodeIn: default
|
||||
journalType: Single File
|
||||
journalPath: null
|
||||
appendNewCardsTo: backlog.md
|
||||
newCardSyntax: MARKDOWN
|
||||
replaceSpacesWith: '-'
|
||||
plugins: {}
|
||||
journalTemplate: null
|
||||
markdownOnly: false
|
||||
kudosProbability: 0.33
|
||||
views: []
|
||||
name: Neighbourhood.omg.lol
|
||||
cards:
|
||||
colors:
|
||||
- color: red
|
||||
filter: tags = "BUG"
|
||||
- color: black
|
||||
filter: tags = "Someday"
|
||||
- color: green
|
||||
filter: tags = "WantToHave"
|
||||
template: |
|
||||
|
||||
<!--
|
||||
created:${timestamp}
|
||||
-->
|
||||
trackChanges: false
|
||||
metaNewLine: true
|
||||
addCompletedMeta: true
|
||||
addCheckBoxTasks: false
|
||||
doneList: DONE
|
||||
tokenPrefix: '#'
|
||||
taskPrefix: ''
|
||||
tagPrefix: '#'
|
||||
metaSep: ':'
|
||||
orderMeta: true
|
||||
maxLines: 6
|
||||
addNewCardsToTop: true
|
||||
showTagsAndMeta: false
|
||||
defaultList: TODO
|
||||
computed: !<tag:yaml.org,2002:js/undefined> ''
|
||||
archiveCompleted: true
|
||||
archiveFolder: .imdone/DONE
|
||||
124
.imdone/properties/card.js
Normal file
124
.imdone/properties/card.js
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
let updatedAt = new Date()
|
||||
|
||||
module.exports = function ({ line, source, totals }) {
|
||||
const project = this.project
|
||||
|
||||
const emoji = {
|
||||
due: dueEmoji(totals),
|
||||
recent: recentEmoji(totals),
|
||||
wip: wipEmoji(totals),
|
||||
chart: EMOJI.CHART
|
||||
}
|
||||
|
||||
// These are the properties that are available to use in your cards
|
||||
// Use ${property_name} to permanently insert the value of the property
|
||||
// Use {{property_name}} to insert the value of the property at runtime
|
||||
return {
|
||||
date: `${new Date().toISOString().substring(0, 10)}`,
|
||||
sourceLink: `[${source.path}:${line}](${source.path}:${line})`,
|
||||
cardTotal: cardTotal(totals),
|
||||
allTopics: project.allTopics, // This is an array of all the topics in the project
|
||||
topicTable: getTopicTable(project), // This is a markdown table with the count of tasks for each topic/list intersection
|
||||
emoji,
|
||||
icons
|
||||
}
|
||||
}
|
||||
|
||||
const icons = {
|
||||
filter: `<span class="icon is-small fa-xs"><svg aria-hidden="true" focusable="false" data-prefix="fa" data-icon="search" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="svg-inline--fa fa-search fa-w-16"><path fill="currentColor" d="M505 442.7L405.3 343c-4.5-4.5-10.6-7-17-7H372c27.6-35.3 44-79.7 44-128C416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c48.3 0 92.7-16.4 128-44v16.3c0 6.4 2.5 12.5 7 17l99.7 99.7c9.4 9.4 24.6 9.4 33.9 0l28.3-28.3c9.4-9.4 9.4-24.6.1-34zM208 336c-70.7 0-128-57.2-128-128 0-70.7 57.2-128 128-128 70.7 0 128 57.2 128 128 0 70.7-57.2 128-128 128z" class=""></path></svg></span><span data-v-fd981bec="" class="icon is-small fa-xs"><svg aria-hidden="true" focusable="false" data-prefix="fa" data-icon="chevron-down" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" class="svg-inline--fa fa-chevron-down fa-w-14"><path fill="currentColor" d="M207.029 381.476L12.686 187.132c-9.373-9.373-9.373-24.569 0-33.941l22.667-22.667c9.357-9.357 24.522-9.375 33.901-.04L224 284.505l154.745-154.021c9.379-9.335 24.544-9.317 33.901.04l22.667 22.667c9.373 9.373 9.373 24.569 0 33.941L240.971 381.476c-9.373 9.372-24.569 9.372-33.942 0z" class=""></path></svg></span>`
|
||||
,openFile: `<span class="icon is-medium"><svg version="1.1" width="16" height="16" viewBox="0 0 16 16" aria-hidden="true" class="octicon octicon-link"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></span>`
|
||||
,kebab: `<span class="icon is-medium"><svg version="1.1" width="3" height="16" viewBox="0 0 3 16" aria-hidden="true" class="octicon octicon-kebab-vertical"><path data-v-5bf4cb66="" fill-rule="evenodd" d="M0 2.5a1.5 1.5 0 1 0 3 0 1.5 1.5 0 0 0-3 0zm0 5a1.5 1.5 0 1 0 3 0 1.5 1.5 0 0 0-3 0zM1.5 14a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3z"></path></svg></span>`
|
||||
,clone: `<span class="icon copy-button is-medium" style=""><svg aria-hidden="true" focusable="false" data-prefix="fa" data-icon="clone" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="svg-inline--fa fa-clone fa-w-16 fa-lg"><path fill="currentColor" d="M464 0c26.51 0 48 21.49 48 48v288c0 26.51-21.49 48-48 48H176c-26.51 0-48-21.49-48-48V48c0-26.51 21.49-48 48-48h288M176 416c-44.112 0-80-35.888-80-80V128H48c-26.51 0-48 21.49-48 48v288c0 26.51 21.49 48 48 48h288c26.51 0 48-21.49 48-48v-48H176z" class=""></path></svg></span>`
|
||||
,editCard: `<span class="icon is-medium"><svg version="1.1" width="14" height="16" viewBox="0 0 14 16" aria-hidden="true" class="octicon octicon-pencil"><path fill-rule="evenodd" d="M0 12v3h3l8-8-3-3-8 8zm3 2H1v-2h1v1h1v1zm10.3-9.3L12 6 9 3l1.3-1.3a.996.996 0 0 1 1.41 0l1.59 1.59c.39.39.39 1.02 0 1.41z"></path></svg></span>`
|
||||
}
|
||||
|
||||
const EMOJI = {
|
||||
BAD: ':rotating_light:',
|
||||
GREAT: ':rocket:',
|
||||
SLEEP: ':sleeping:',
|
||||
GOOD: ':2nd_place_medal:',
|
||||
CHART: '<span style="font-size: 1.5em;">:chart:</span>'
|
||||
}
|
||||
|
||||
function formatEmoji(emoji) {
|
||||
return `<span style="font-size: 1.5em;">${emoji}</span>`
|
||||
}
|
||||
|
||||
function dueEmoji(totals) {
|
||||
const due = totals["What's Due?"]
|
||||
let emoji = EMOJI.GOOD
|
||||
if (due >= 3) {
|
||||
emoji = EMOJI.BAD
|
||||
} else if (due === 0) {
|
||||
emoji = EMOJI.GREAT
|
||||
}
|
||||
return formatEmoji(emoji)
|
||||
}
|
||||
|
||||
function recentEmoji(totals) {
|
||||
const recentlyCompleted = totals['Recently Completed']
|
||||
let emoji = EMOJI.GOOD
|
||||
if (recentlyCompleted >= 3) {
|
||||
emoji = EMOJI.GREAT
|
||||
} else if (recentlyCompleted === 0) {
|
||||
emoji = EMOJI.BAD
|
||||
}
|
||||
return formatEmoji(emoji)
|
||||
}
|
||||
|
||||
function wipEmoji(totals) {
|
||||
const doing = totals['DOING']
|
||||
let emoji = EMOJI.GOOD
|
||||
if (doing >= 3) {
|
||||
emoji = EMOJI.BAD
|
||||
} else if (doing === 0) {
|
||||
emoji = EMOJI.SLEEP
|
||||
} else if (doing === 1) {
|
||||
emoji = EMOJI.GREAT
|
||||
}
|
||||
return formatEmoji(emoji)
|
||||
}
|
||||
|
||||
function cardTotal(totals) {
|
||||
let count = 0
|
||||
Object.keys(totals).forEach((list) => {
|
||||
count += totals[list]
|
||||
})
|
||||
return count
|
||||
}
|
||||
|
||||
function getTopicTable(project) {
|
||||
console.log('project.updatedAt', project.updatedAt)
|
||||
console.log('updatedAt', updatedAt)
|
||||
if (project.updatedAt < updatedAt) return ''
|
||||
|
||||
updatedAt = project.updatedAt
|
||||
const lists = project.allLists.filter(list => !list.filter)
|
||||
const topicTable = project.allTopics.map((topic) => {
|
||||
return {
|
||||
name: topic,
|
||||
lists: [
|
||||
...lists.map((list) => {
|
||||
return {
|
||||
name: list.name,
|
||||
count: list.tasks.filter((task) => task.topics.includes(topic)).length
|
||||
}
|
||||
})
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
//convert topic table into a markdown table with topic name on the left and list names on the top and the count for each topic/list intersection
|
||||
const table = `
|
||||
| Topic | ${lists.map((list) => list.name).join(' | ')} |
|
||||
| --- | ${lists.map(() => ' --- ').join(' | ')} |
|
||||
${topicTable.map((topic) => {
|
||||
const topicLink = `imdone://${project.path}?filter=topics="${encodeURIComponent(topic.name)}"`;
|
||||
return `| [[${topic.name}]] | ${topic.lists.map((list) => `[${list.count}](${topicLink})`).join(' | ')} |`;
|
||||
}).join('\n')}
|
||||
`;
|
||||
|
||||
console.log(table);
|
||||
return table
|
||||
}
|
||||
|
||||
0
.imdone/style.css
Normal file
0
.imdone/style.css
Normal file
4
.imdone/tags.yml
Normal file
4
.imdone/tags.yml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
tags:
|
||||
- BUG
|
||||
- Someday
|
||||
- WantToHave
|
||||
8
.imdoneignore
Normal file
8
.imdoneignore
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
.vs
|
||||
bin
|
||||
obj
|
||||
*.user
|
||||
.imdone
|
||||
Resources
|
||||
.git
|
||||
.vscode
|
||||
|
|
@ -1,13 +1,9 @@
|
|||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Neighbourhood.omg.lol.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
|
||||
namespace Neighbourhood.omg.lol
|
||||
{
|
||||
|
|
@ -15,6 +11,7 @@ namespace Neighbourhood.omg.lol
|
|||
HttpClient _client;
|
||||
JsonSerializerOptions _serializerOptions;
|
||||
public const string BaseUrl = "https://api.omg.lol";
|
||||
private string? apiToken = null;
|
||||
|
||||
public ApiService(string? token = null) {
|
||||
_client = new HttpClient();
|
||||
|
|
@ -94,7 +91,7 @@ namespace Neighbourhood.omg.lol
|
|||
/// <param name="file">A FileResult for the file to send in the body of the request as binary data</param>
|
||||
/// <param name="cancellationToken">A cancellation token</param>
|
||||
/// <returns>The returned data if successful, otherwise default</returns>
|
||||
private async Task<TResponse?> Request<TResponse, TData>(string uri, HttpMethod method, TData? data = default, FileResult? file = null, CancellationToken cancellationToken = default)
|
||||
private async Task<TResponse?> Request<TResponse, TData>(string uri, HttpMethod method, TData? data = default, FileResult? file = null, bool useAuthToken = true, CancellationToken cancellationToken = default)
|
||||
where TResponse : IOmgLolResponseData
|
||||
{
|
||||
TResponse? responseData = default;
|
||||
|
|
@ -118,6 +115,12 @@ namespace Neighbourhood.omg.lol
|
|||
string json = JsonSerializer.Serialize(data, _serializerOptions);
|
||||
request.Content = new StringContent(json, Encoding.UTF8, "application/json");
|
||||
}
|
||||
|
||||
if(useAuthToken) {
|
||||
if (apiToken == null) apiToken = Task.Run(() => SecureStorage.GetAsync("accounttoken")).GetAwaiter().GetResult();
|
||||
if (apiToken != null) request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", apiToken);
|
||||
}
|
||||
|
||||
HttpResponseMessage response = await _client.SendAsync(request, cancellationToken: cancellationToken);
|
||||
responseData = await DecodeResponse<TResponse>(response, cancellationToken);
|
||||
|
||||
|
|
@ -131,9 +134,9 @@ namespace Neighbourhood.omg.lol
|
|||
}
|
||||
|
||||
// GET request
|
||||
private async Task<TResponse?> Get<TResponse>(string uri, CancellationToken cancellationToken = default)
|
||||
private async Task<TResponse?> Get<TResponse>(string uri, bool useAuthToken = true, CancellationToken cancellationToken = default)
|
||||
where TResponse : IOmgLolResponseData
|
||||
=> await Request<TResponse, object>(uri, HttpMethod.Get, cancellationToken: cancellationToken);
|
||||
=> await Request<TResponse, object>(uri, HttpMethod.Get, useAuthToken: useAuthToken, cancellationToken: cancellationToken);
|
||||
|
||||
// POST request
|
||||
private async Task<TResponse?> Post<TResponse, TData>(string uri, TData data, CancellationToken cancellationToken = default)
|
||||
|
|
@ -242,7 +245,9 @@ namespace Neighbourhood.omg.lol
|
|||
await PostBinary<BasicResponseData>($"/address/{address}/pfp", fileResult: image);
|
||||
|
||||
public async Task<List<Paste>> GetPastes(string address) =>
|
||||
(await Get<PastesResponseData>($"/address/{address}/pastebin"))?.Pastebin ?? new List<Paste>();
|
||||
(await Get<PastesResponseData>($"/address/{address}/pastebin", useAuthToken: false))?.Pastebin ?? new List<Paste>();
|
||||
public async Task<List<Paste>> GetMyPastes(string address) =>
|
||||
(await Get<PastesResponseData>($"/address/{address}/pastebin", useAuthToken: true))?.Pastebin ?? new List<Paste>();
|
||||
|
||||
public async Task<BasicResponseData?> DeletePaste(string address, string title) =>
|
||||
await Delete<BasicResponseData>($"/address/{address}/pastebin/{title}");
|
||||
|
|
@ -259,7 +264,7 @@ namespace Neighbourhood.omg.lol
|
|||
/// <param name="token">The api token</param>
|
||||
public void AddToken(string? token = null) {
|
||||
if (token == null) token = Task.Run(() => SecureStorage.GetAsync("accounttoken")).GetAwaiter().GetResult();
|
||||
if (token != null) _client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
|
||||
if (token != null) apiToken = token;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ namespace Neighbourhood.omg.lol {
|
|||
public List<MarkupString>? EphemeralMessages { get; set; }
|
||||
public List<string>? AddressDirectory { get; set; }
|
||||
|
||||
public List<StatusOrPic>? Feed { get; set; }
|
||||
public List<FeedItem>? Feed { get; set; }
|
||||
|
||||
public Dictionary<string, Theme>? Themes { get; set; }
|
||||
|
||||
|
|
@ -289,7 +289,12 @@ namespace Neighbourhood.omg.lol {
|
|||
public async Task<List<Paste>?> GetPastes(string address, bool forceRefresh = false) {
|
||||
CachedAddress = address;
|
||||
if (forceRefresh || this.CachedAddressPastes == null || this.CachedAddressPastes.Count == 0) {
|
||||
CachedAddressPastes = (await api.GetPastes(address)) ?? new List<Paste>();
|
||||
if (AddressNames?.Contains(address) ?? false) {
|
||||
CachedAddressPastes = (await api.GetMyPastes(address)) ?? new List<Paste>();
|
||||
}
|
||||
else {
|
||||
CachedAddressPastes = (await api.GetPastes(address)) ?? new List<Paste>();
|
||||
}
|
||||
}
|
||||
return CachedAddressPastes;
|
||||
}
|
||||
|
|
@ -311,12 +316,13 @@ namespace Neighbourhood.omg.lol {
|
|||
await GetPastes(SelectedAddressName, forceRefresh: true);
|
||||
}
|
||||
|
||||
public async Task<IOrderedEnumerable<StatusOrPic>> GetFeed(bool forceRefresh = false) {
|
||||
public async Task<IOrderedEnumerable<FeedItem>> GetFeed(bool forceRefresh = false) {
|
||||
if(forceRefresh || Feed == null || Feed.Count == 0) {
|
||||
Feed = new List<StatusOrPic>();
|
||||
Feed = new List<FeedItem>();
|
||||
foreach(string address in Following ?? new List<string>()) {
|
||||
Feed.AddRange((await GetStatuses(address, forceRefresh))?.Select(s => new StatusOrPic { Status = s }) ?? new List<StatusOrPic>());
|
||||
Feed.AddRange((await GetPics(address, forceRefresh))?.Select(p => new StatusOrPic { Pic = p }) ?? new List<StatusOrPic>());
|
||||
Feed.AddRange((await GetStatuses(address, forceRefresh))?.Select(s => new FeedItem { Status = s }) ?? new List<FeedItem>());
|
||||
Feed.AddRange((await GetPics(address, forceRefresh))?.Select(p => new FeedItem { Pic = p }) ?? new List<FeedItem>());
|
||||
Feed.AddRange((await GetPastes(address, forceRefresh))?.Select(p => new FeedItem { Paste = p }) ?? new List<FeedItem>());
|
||||
}
|
||||
}
|
||||
return Feed.OrderByDescending(s => s.CreatedTime);
|
||||
|
|
|
|||
|
|
@ -124,6 +124,7 @@
|
|||
Content = string.Empty;
|
||||
Listed = false;
|
||||
confirmDelete = false;
|
||||
loading = false;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,11 +57,8 @@
|
|||
loading = true;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
|
||||
//TODO: upload the profile pic
|
||||
//PutPicResponseData? response = await api.PutPic(State.SelectedAddressName!, Base64File!);
|
||||
if (Base64File != null && File != null)
|
||||
{
|
||||
// using var fileStream = await File.OpenReadAsync();
|
||||
BasicResponseData? response = await api.PostProfilePic(Address!, File);
|
||||
if (response != null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -34,6 +34,10 @@
|
|||
<i class="fa-duotone fa-seedling"></i>
|
||||
<span>/Now</span>
|
||||
</a>
|
||||
<a class="indent row" href="/person/@State.SelectedAddressName#pastebin">
|
||||
<i class="fa-solid fa-clipboard"></i>
|
||||
<span>Pastebin</span>
|
||||
</a>
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
catch (Exception) { }
|
||||
}
|
||||
<li>
|
||||
<a class="chip medium no-border no-margin" href="/person/@address">
|
||||
<a class="chip medium no-border tiny-margin transparent" href="/person/@address">
|
||||
<img class="circle avatar responsive" src="https://profiles.cache.lol/@linkAddress/picture">
|
||||
<span>@displayAddress</span>
|
||||
</a>
|
||||
|
|
|
|||
|
|
@ -35,13 +35,16 @@ else {
|
|||
<div class="responsive page-container">
|
||||
<div id="feed" class="page no-padding active">
|
||||
@if (feed != null){
|
||||
foreach (StatusOrPic item in feed) {
|
||||
foreach (FeedItem item in feed) {
|
||||
if (item.IsStatus) {
|
||||
<StatusCard Status="@item.Status"></StatusCard>
|
||||
}
|
||||
else if (item.IsPic) {
|
||||
<PicCard Pic="@item.Pic"></PicCard>
|
||||
}
|
||||
else if (item.IsPaste) {
|
||||
<PasteCard Paste="@item.Paste"></PasteCard>
|
||||
}
|
||||
}
|
||||
}
|
||||
<LoadingCard id="feedLoading" icon="fa-solid fa-list-timeline"></LoadingCard>
|
||||
|
|
@ -75,7 +78,7 @@ else {
|
|||
}
|
||||
|
||||
@code {
|
||||
private IOrderedEnumerable<StatusOrPic>? feed;
|
||||
private IOrderedEnumerable<FeedItem>? feed;
|
||||
|
||||
protected override async Task OnInitializedAsync() {
|
||||
await base.OnInitializedAsync();
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@
|
|||
<PasteList @ref="PasteList" PastesFunc="@(async(refresh) => await State.GetPastes(Address, refresh))" Editable="@IsMe"></PasteList>
|
||||
@if (IsMe) {
|
||||
<button class="fab circle extra large-elevate" data-ui="#paste-modal">
|
||||
<i class="fa-solid fa-clipboard"></i>
|
||||
<i class="fa-solid fa-clipboard-medical"></i>
|
||||
</button>
|
||||
<EditPasteDialog id="paste-modal"></EditPasteDialog>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,13 @@
|
|||
@inject IJSRuntime JS
|
||||
@using CommunityToolkit.Maui.Alerts
|
||||
@inject IJSRuntime JS
|
||||
|
||||
<article class="paste">
|
||||
@* TODO: link to paste view *@
|
||||
@* TODO link to paste view
|
||||
* <!--
|
||||
* order:-178.75
|
||||
* -->
|
||||
*@
|
||||
|
||||
<nav>
|
||||
<h5 class="mono"><a href="/pastes/tbc">@Paste.Title</a></h5>
|
||||
<div class="max"></div>
|
||||
|
|
@ -13,12 +19,12 @@
|
|||
{
|
||||
<button class="transparent circle" title="View Markup" @onclick="() => { MarkupView = true; InvokeAsync(StateHasChanged); }"><i class="fa-solid fa-browser"></i></button>
|
||||
}
|
||||
<button class="transparent circle" title="Copy to Clipboard" @onclick="() => Clipboard.Default.SetTextAsync(Paste.Content)"><i class="fa-solid fa-copy"></i></button>
|
||||
<button class="transparent circle" title="Copy to Clipboard" @onclick="() => CopyPaste()"><i class="fa-solid fa-copy"></i></button>
|
||||
<button class="transparent circle" @onclick="ShareClick">
|
||||
<i class="fa-solid fa-share-nodes"></i>
|
||||
</button>
|
||||
</nav>
|
||||
<small class="nowrap gray-5-fg"><i class="fa-solid fa-clock tiny"></i> @Paste.RelativeTime</small>
|
||||
<small class="nowrap chip no-border"><i class="fa-solid fa-clock tiny"></i> @Paste.RelativeTime</small>
|
||||
@if(MarkupView){
|
||||
<div class="padding">
|
||||
@Utilities.MdToHtmlMarkup(Paste.Content)
|
||||
|
|
@ -59,4 +65,12 @@
|
|||
Subject = Paste!.Title
|
||||
});
|
||||
}
|
||||
|
||||
public async Task CopyPaste() {
|
||||
if(Paste != null && !string.IsNullOrEmpty(Paste?.Content)) {
|
||||
await Clipboard.Default.SetTextAsync(Paste?.Content);
|
||||
var toast = Toast.Make("Copied to clipboard");
|
||||
await toast.Show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,10 @@
|
|||
|
||||
private List<Pic>? pics;
|
||||
|
||||
// TODO: There is a noticable rendering delay between the pics loading and the page rendering
|
||||
//TODO There is a noticable rendering delay between the pics loading and the page rendering
|
||||
// <!--
|
||||
// order:-145
|
||||
// -->
|
||||
protected override async Task OnInitializedAsync() {
|
||||
await base.OnInitializedAsync();
|
||||
if (PicsFunc == null) return;
|
||||
|
|
|
|||
|
|
@ -73,7 +73,6 @@
|
|||
}
|
||||
|
||||
public async Task UseTheme() {
|
||||
// todo: update theme
|
||||
onthemechanged?.Invoke(activeTheme);
|
||||
activeTheme = null;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using CommunityToolkit.Maui;
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
|
|
@ -7,7 +8,10 @@ namespace Neighbourhood.omg.lol {
|
|||
public static MauiApp CreateMauiApp() {
|
||||
var builder = MauiApp.CreateBuilder();
|
||||
builder
|
||||
.UseMauiApp<App>();
|
||||
.UseMauiApp<App>()
|
||||
.UseMauiCommunityToolkit(options => {
|
||||
options.SetShouldEnableSnackbarOnWindows(true);
|
||||
});
|
||||
|
||||
builder.Services.AddMauiBlazorWebView();
|
||||
builder.Services.AddTransient<LoginWebViewPage>();
|
||||
|
|
|
|||
|
|
@ -4,6 +4,5 @@
|
|||
public string Email { get; set; } = string.Empty;
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public TimeData Created { get; set; } = TimeData.Empty;
|
||||
//TODO: api_key and settings
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
namespace Neighbourhood.omg.lol.Models {
|
||||
public class StatusOrPic {
|
||||
public class FeedItem {
|
||||
public Status? Status { get; set; }
|
||||
public Pic? Pic { get; set; }
|
||||
public Paste? Paste { get; set; }
|
||||
|
||||
public bool IsStatus { get => Status != null; }
|
||||
public bool IsPic { get => Pic != null; }
|
||||
public bool IsPaste { get => Paste != null; }
|
||||
|
||||
public DateTimeOffset? CreatedTime { get => Status?.CreatedTime ?? Pic?.CreatedTime; }
|
||||
public DateTimeOffset? CreatedTime { get => Status?.CreatedTime ?? Pic?.CreatedTime ?? Paste?.ModifiedTime; }
|
||||
}
|
||||
}
|
||||
|
|
@ -43,22 +43,22 @@
|
|||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0-ios|AnyCPU'">
|
||||
<ApplicationId>au.death.lol.omg.neighbourhood</ApplicationId>
|
||||
<ApplicationDisplayVersion>0.9.7</ApplicationDisplayVersion>
|
||||
<ApplicationVersion>7</ApplicationVersion>
|
||||
<ApplicationDisplayVersion>0.9.9</ApplicationDisplayVersion>
|
||||
<ApplicationVersion>9</ApplicationVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0-maccatalyst|AnyCPU'">
|
||||
<ApplicationId>au.death.lol.omg.neighbourhood</ApplicationId>
|
||||
<ApplicationDisplayVersion>0.9.7</ApplicationDisplayVersion>
|
||||
<ApplicationVersion>7</ApplicationVersion>
|
||||
<ApplicationDisplayVersion>0.9.9</ApplicationDisplayVersion>
|
||||
<ApplicationVersion>9</ApplicationVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0-android34.0|AnyCPU'">
|
||||
<ApplicationId>au.death.lol.omg.neighbourhood</ApplicationId>
|
||||
<ApplicationDisplayVersion>0.9.7</ApplicationDisplayVersion>
|
||||
<ApplicationDisplayVersion>0.9.9</ApplicationDisplayVersion>
|
||||
<AndroidKeyStore>True</AndroidKeyStore>
|
||||
<AndroidSigningKeyStore>D:\_assets\neighbourhood.omg.lol\neighbourhood.omg.lol.keystore</AndroidSigningKeyStore>
|
||||
<ApplicationVersion>7</ApplicationVersion>
|
||||
<ApplicationVersion>9</ApplicationVersion>
|
||||
<AndroidSigningStorePass>a!zobzizl</AndroidSigningStorePass>
|
||||
<AndroidSigningKeyAlias>neighbourhood.omg.lol</AndroidSigningKeyAlias>
|
||||
<AndroidSigningKeyPass>a!zobzizl</AndroidSigningKeyPass>
|
||||
|
|
@ -66,32 +66,32 @@
|
|||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0-windows10.0.19041.0|AnyCPU'">
|
||||
<ApplicationId>au.death.lol.omg.neighbourhood</ApplicationId>
|
||||
<ApplicationDisplayVersion>0.9.7</ApplicationDisplayVersion>
|
||||
<ApplicationVersion>7</ApplicationVersion>
|
||||
<ApplicationDisplayVersion>0.9.9</ApplicationDisplayVersion>
|
||||
<ApplicationVersion>9</ApplicationVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net8.0-ios|AnyCPU'">
|
||||
<ApplicationId>au.death.lol.omg.neighbourhood</ApplicationId>
|
||||
<ApplicationDisplayVersion>0.9.7</ApplicationDisplayVersion>
|
||||
<ApplicationVersion>7</ApplicationVersion>
|
||||
<ApplicationDisplayVersion>0.9.9</ApplicationDisplayVersion>
|
||||
<ApplicationVersion>9</ApplicationVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net8.0-maccatalyst|AnyCPU'">
|
||||
<ApplicationId>au.death.lol.omg.neighbourhood</ApplicationId>
|
||||
<ApplicationDisplayVersion>0.9.7</ApplicationDisplayVersion>
|
||||
<ApplicationVersion>7</ApplicationVersion>
|
||||
<ApplicationDisplayVersion>0.9.9</ApplicationDisplayVersion>
|
||||
<ApplicationVersion>9</ApplicationVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net8.0-android34.0|AnyCPU'">
|
||||
<ApplicationId>au.death.lol.omg.neighbourhood</ApplicationId>
|
||||
<ApplicationDisplayVersion>0.9.7</ApplicationDisplayVersion>
|
||||
<ApplicationVersion>7</ApplicationVersion>
|
||||
<ApplicationDisplayVersion>0.9.9</ApplicationDisplayVersion>
|
||||
<ApplicationVersion>9</ApplicationVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net8.0-windows10.0.19041.0|AnyCPU'">
|
||||
<ApplicationId>au.death.lol.omg.neighbourhood</ApplicationId>
|
||||
<ApplicationDisplayVersion>0.9.7</ApplicationDisplayVersion>
|
||||
<ApplicationVersion>7</ApplicationVersion>
|
||||
<ApplicationDisplayVersion>0.9.9</ApplicationDisplayVersion>
|
||||
<ApplicationVersion>9</ApplicationVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
@ -125,6 +125,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommunityToolkit.Maui" Version="9.0.2" />
|
||||
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
||||
<PackageReference Include="Markdig" Version="0.37.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="8.0.7" />
|
||||
|
|
@ -137,7 +138,7 @@
|
|||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Maui.Essentials" Version="8.0.70" />
|
||||
<PackageReference Include="PSC.Blazor.Components.MarkdownEditor" Version="8.0.4" />
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.4" />
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.5" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="au.death.lol.omg.neighbourhood" android:versionCode="7" android:versionName="0.9.7">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="au.death.lol.omg.neighbourhood" android:versionCode="9" android:versionName="0.9.9">
|
||||
<application android:allowBackup="true" android:icon="@mipmap/icon_background" android:supportsRtl="true" android:label="omg.lol"></application>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
|
|
|||
|
|
@ -56,11 +56,15 @@ namespace Neighbourhood.omg.lol {
|
|||
}
|
||||
else if (intent.Type.Equals(Intent.ActionSendMultiple)) //Multiple files
|
||||
{
|
||||
// TODO: we don't really support this at the moment.
|
||||
//System.Collections.IList? uriList;
|
||||
//if (OperatingSystem.IsAndroidVersionAtLeast(33))
|
||||
//NOTE we don't really support recieving multiple files from a share request at the moment.
|
||||
// <!--
|
||||
// order:0
|
||||
// -->
|
||||
|
||||
// System.Collections.IList? uriList;
|
||||
// if (OperatingSystem.IsAndroidVersionAtLeast(33))
|
||||
// uriList = intent.GetParcelableArrayListExtra(Intent.ExtraStream, Java.Lang.Class.FromType(typeof(Android.Net.Uri)));
|
||||
//else uriList = intent.GetParcelableArrayListExtra(Intent.ExtraStream);
|
||||
// else uriList = intent.GetParcelableArrayListExtra(Intent.ExtraStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@
|
|||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
|
||||
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||
IgnorableNamespaces="uap rescap">
|
||||
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
|
||||
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
|
||||
IgnorableNamespaces="uap rescap com desktop">
|
||||
|
||||
<Identity Name="maui-package-name-placeholder" Publisher="CN=User Name" Version="0.0.0.0" />
|
||||
|
||||
|
|
@ -36,6 +38,26 @@
|
|||
<uap:DefaultTile Square71x71Logo="$placeholder$.png" Wide310x150Logo="$placeholder$.png" Square310x310Logo="$placeholder$.png" />
|
||||
<uap:SplashScreen Image="$placeholder$.png" />
|
||||
</uap:VisualElements>
|
||||
|
||||
<Extensions>
|
||||
|
||||
<!-- Specify which CLSID to activate when notification is clicked -->
|
||||
<desktop:Extension Category="windows.toastNotificationActivation">
|
||||
<desktop:ToastNotificationActivation ToastActivatorCLSID="6e919706-2634-4d97-a93c-2213b2acc334" />
|
||||
</desktop:Extension>
|
||||
|
||||
<!-- Register COM CLSID -->
|
||||
<com:Extension Category="windows.comServer">
|
||||
<com:ComServer>
|
||||
<com:ExeServer Executable="Neighbourhood.omg.lol\Neighbourhood.omg.lol.exe" DisplayName="$targetnametoken$" Arguments="----AppNotificationActivated:">
|
||||
<!-- Example path to executable: CommunityToolkit.Maui.Sample\CommunityToolkit.Maui.Sample.exe -->
|
||||
<com:Class Id="6e919706-2634-4d97-a93c-2213b2acc334" />
|
||||
</com:ExeServer>
|
||||
</com:ComServer>
|
||||
</com:Extension>
|
||||
|
||||
</Extensions>
|
||||
|
||||
</Application>
|
||||
</Applications>
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
<key>XSAppIconAssets</key>
|
||||
<string>Assets.xcassets/icon.appiconset</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.9.7</string>
|
||||
<string>0.9.9</string>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>14.2</string>
|
||||
</dict>
|
||||
|
|
|
|||
63
backlog.md
Normal file
63
backlog.md
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
- [Pull to refresh #WantToHave](#TODO:)
|
||||
<!--
|
||||
order:-177.5
|
||||
-->
|
||||
- [Be a share target for pastes? #WantToHave](#TODO:)
|
||||
<!--
|
||||
order:-171.25
|
||||
-->
|
||||
- [Update / manage [PURLs](https://api.omg.lol/#purls) #WantToHave](#TODO:)
|
||||
<!--
|
||||
order:-172.5
|
||||
-->
|
||||
- [Combined status / pics posting (upload pic in new status dialog and paste in link) #WantToHave](#TODO:)
|
||||
<!--
|
||||
order:-171.875
|
||||
-->
|
||||
- [Update / manage [Weblog](https://api.omg.lol/#weblog) (should probably wait for [Neato](https://neato.pub/)) #WantToHave](#WAITING:)
|
||||
<!--
|
||||
order:0
|
||||
-->
|
||||
|
||||
- [Account settings #Someday](#TODO:)
|
||||
<!--
|
||||
order:-80
|
||||
-->
|
||||
- [Address preferences #Someday](#TODO:)
|
||||
<!--
|
||||
order:-90
|
||||
-->
|
||||
- [DNS Records #Someday](#TODO:)
|
||||
<!--
|
||||
order:-100
|
||||
-->
|
||||
- [Switchboard #Someday](#TODO:)
|
||||
<!--
|
||||
order:-110
|
||||
-->
|
||||
- [Email forwarding #Someday](#TODO:)
|
||||
<!--
|
||||
order:-120
|
||||
-->
|
||||
- [Keys #Someday](#TODO:)
|
||||
<!--
|
||||
order:-130
|
||||
-->
|
||||
- [Proofs #Someday](#TODO:)
|
||||
<!--
|
||||
order:-140
|
||||
-->
|
||||
|
||||
- [Slow rendering, especially pics, due to large amount of data #BUG](#TODO:)
|
||||
<!--
|
||||
order:-150
|
||||
-->
|
||||
- [Sharing to app while the sharing page is already open does literally nothing #BUG](#TODO:)
|
||||
- Not an issue? Only an issue when you have the app and the sharing app open side-by-side, which is rare?
|
||||
<!--
|
||||
order:-160
|
||||
-->
|
||||
- [Can't select svgs as pics. #BUG](#TODO:)
|
||||
<!--
|
||||
order:-170
|
||||
-->
|
||||
|
|
@ -38,7 +38,6 @@
|
|||
position: sticky;
|
||||
top: 0;
|
||||
height: env(safe-area-inset-top);
|
||||
background-color: #f7f7f7;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,33 +9,99 @@ body.dark {
|
|||
--on-background: var(--gray-1);
|
||||
--surface: var(--gray-9);
|
||||
--on-surface: var(--gray-4);
|
||||
--on-surface-variant: var(--gray-6);
|
||||
}
|
||||
|
||||
.author { color: inherit }
|
||||
@media (prefers-color-scheme: light) {
|
||||
body.dark {
|
||||
--primary: #6750a4;
|
||||
--on-primary: #ffffff;
|
||||
--primary-container: #e9ddff;
|
||||
--on-primary-container: #22005d;
|
||||
--secondary: #625b71;
|
||||
--on-secondary: #ffffff;
|
||||
--secondary-container: var(--gray-4);
|
||||
--on-secondary-container: #1e192b;
|
||||
--tertiary: #7e5260;
|
||||
--on-tertiary: #ffffff;
|
||||
--tertiary-container: #ffd9e3;
|
||||
--on-tertiary-container: #31101d;
|
||||
--error: #ba1a1a;
|
||||
--on-error: #ffffff;
|
||||
--error-container: #ffdad6;
|
||||
--on-error-container: #410002;
|
||||
--background: var(--gray-0);
|
||||
--on-background: var(--gray-8);
|
||||
--surface: var(--gray-2);
|
||||
--on-surface: var(--gray-9);
|
||||
--surface-variant: var(--gray-1);
|
||||
--on-surface-variant: var(--gray-7);
|
||||
--outline: #7a757f;
|
||||
--outline-variant: #cac4cf;
|
||||
--shadow: #000000;
|
||||
--scrim: #000000;
|
||||
--inverse-surface: var(--gray-1);
|
||||
--inverse-on-surface: var(--gray-9);
|
||||
--inverse-primary: #cfbcff;
|
||||
--surface-dim: #ddd8dd;
|
||||
--surface-bright: #fdf8fd;
|
||||
--surface-container-lowest: #ffffff;
|
||||
--surface-container-low: var(--gray-3);
|
||||
--surface-container: var(--gray-3);
|
||||
--surface-container-high: #ece7eb;
|
||||
--surface-container-highest: #e6e1e6;
|
||||
--overlay: rgb(0 0 0 / .5);
|
||||
--active: rgb(0 0 0 / .1);
|
||||
--elevate1: 0 .125rem .125rem 0 rgb(0 0 0 / .32);
|
||||
--elevate2: 0 .25rem .5rem 0 rgb(0 0 0 / .4);
|
||||
--elevate3: 0 .375rem .75rem 0 rgb(0 0 0 / .48);
|
||||
--secondary-container: var(--gray-4);
|
||||
}
|
||||
}
|
||||
|
||||
.status nav, .status nav .chip { color: var(--gray-7) }
|
||||
body, nav:is(.left,.right) {
|
||||
background-color: var(--background);
|
||||
}
|
||||
|
||||
article {
|
||||
background-color: var(--surface);
|
||||
}
|
||||
|
||||
.author {
|
||||
color: inherit
|
||||
}
|
||||
|
||||
.status nav, .status nav .chip {
|
||||
color: var(--gray-7)
|
||||
}
|
||||
|
||||
.avatar::after {
|
||||
background-color: var(--surface-container-low);
|
||||
border: 1px dashed var(--gray-4)
|
||||
background-color: var(--surface);
|
||||
border: 1px dashed var(--on-surface)
|
||||
}
|
||||
|
||||
article.ephemeral { border: 2px dashed var(--gray-7) }
|
||||
article.ephemeral {
|
||||
border: 2px dashed var(--outline)
|
||||
}
|
||||
|
||||
article.now {
|
||||
background-color: var(--green-2);
|
||||
color: var(--black)
|
||||
}
|
||||
article.now {
|
||||
background-color: var(--green-2);
|
||||
color: var(--black)
|
||||
}
|
||||
|
||||
a.row.indent { border-left: 1px solid var(--outline) }
|
||||
a.row.indent {
|
||||
border-left: 1px solid var(--outline)
|
||||
}
|
||||
|
||||
.markdown-editor .editor-preview { background: var(--surface) }
|
||||
.markdown-editor .editor-preview {
|
||||
background: var(--surface)
|
||||
}
|
||||
|
||||
menu > details > a:is(:hover,:focus,.active), menu > details > summary:is(:hover,:focus,.active) {
|
||||
background-color: var(--active)
|
||||
}
|
||||
menu > details > a:is(:hover,:focus,.active), menu > details > summary:is(:hover,:focus,.active) {
|
||||
background-color: var(--active)
|
||||
}
|
||||
|
||||
#advanced :is(.field.textarea, textarea), .EasyMDEContainer, article.paste code {
|
||||
background-color: #212121;
|
||||
color: #eff
|
||||
}
|
||||
#advanced :is(.field.textarea, textarea), .EasyMDEContainer, article.paste code {
|
||||
background-color: #212121;
|
||||
color: #eff
|
||||
}
|
||||
|
|
@ -4,10 +4,11 @@
|
|||
.animated[data-emoji|=🫥] { content: url(/vendor/fluent-emoji/1fae5/animated.png) }
|
||||
|
||||
.fa-seedling { color: var(--green-9) !important }
|
||||
.fa-message-smile { color: var(--blue-4) !important }
|
||||
.fa-images { color: var(--yellow-6) !important }
|
||||
.fa-id-card { color: var(--pink-4) !important }
|
||||
.fa-message-smile { color: var(--blue-5) !important }
|
||||
.fa-images { color: var(--orange-5) !important }
|
||||
.fa-id-card { color: var(--red-5) !important }
|
||||
.fa-comment-dots { color: var(--gray-6) !important }
|
||||
.fa-clipboard { color: var(--violet-5) !important }
|
||||
|
||||
i.tiny { ---size: 1em }
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,14 @@
|
|||
--max-article-size: 75rem;
|
||||
}
|
||||
|
||||
#app {
|
||||
position: relative
|
||||
}
|
||||
|
||||
nav:is(.left, .right){
|
||||
margin-block-start: env(safe-area-inset-top);
|
||||
}
|
||||
|
||||
main {
|
||||
position: relative;
|
||||
overflow-x: hidden;
|
||||
|
|
@ -49,6 +57,10 @@ img {
|
|||
max-inline-size: 10rem
|
||||
}
|
||||
|
||||
:is(h1,h2,h3,h4,h5,h6):is(:focus-visible) {
|
||||
outline:none;
|
||||
}
|
||||
|
||||
#bio :is(h1,h2,h3,h4,h5,h6) {
|
||||
text-align: center;
|
||||
display: block
|
||||
|
|
@ -239,4 +251,4 @@ a.row.indent { margin-left: 1rem }
|
|||
|
||||
.markdown-editor > .EasyMDEContainer > .CodeMirror {
|
||||
flex: auto
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,9 @@ nav header { z-index: 101 }
|
|||
|
||||
nav.bottom.s:not(.drawer) :is(button,.button) > menu { z-index: 100 }
|
||||
|
||||
.fab { z-index: 1 }
|
||||
.fab {
|
||||
z-index: 1
|
||||
}
|
||||
|
||||
.avatar::after { z-index: 1 }
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue