Compare commits
10 commits
0c3836b0c8
...
f43e1a7bc1
Author | SHA1 | Date | |
---|---|---|---|
f43e1a7bc1 | |||
f2025df922 | |||
63d844e7a3 | |||
413051ad4c | |||
996e1286cb | |||
df05e8a819 | |||
a8c36eaea8 | |||
2c38dc2733 | |||
8c8634f3c3 | |||
ed5ad5a7b1 |
63 changed files with 1108 additions and 472 deletions
|
@ -1,5 +1,6 @@
|
|||
@inject IJSRuntime JS
|
||||
@inject State State
|
||||
@inject RestService api
|
||||
|
||||
<div class="overlay" data-ui="#@id"></div>
|
||||
<dialog id="@id">
|
||||
|
@ -46,7 +47,6 @@
|
|||
loading = true;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
|
||||
RestService api = new RestService();
|
||||
if(!string.IsNullOrEmpty(Pic.Id)) {
|
||||
await api.PostPicDescription(State.SelectedAddressName, Pic.Id, Description);
|
||||
await State.RefreshPics();
|
||||
|
|
88
Components/EditStatusDialog.razor
Normal file
88
Components/EditStatusDialog.razor
Normal file
|
@ -0,0 +1,88 @@
|
|||
@inject IJSRuntime JS
|
||||
@inject State State
|
||||
@inject RestService api
|
||||
|
||||
<div class="overlay" data-ui="#@id"></div>
|
||||
<dialog id="@id">
|
||||
<div class="row">
|
||||
<div class="min square extra">
|
||||
<button class="transparent square extra no-margin">
|
||||
<object id="status-emoji" class="large emoji @(Emoji == null ? "animated" : string.Empty)" data-emoji="@(Emoji ?? "🫥")">@(Emoji ?? "🫥")</object>
|
||||
<menu class="no-wrap">
|
||||
<script type="module" src="https://cdn.jsdelivr.net/npm/emoji-picker-element@@^1/index.js"></script>
|
||||
<emoji-picker emoji-version="15.1"></emoji-picker>
|
||||
<script>
|
||||
document.querySelector('emoji-picker')
|
||||
.addEventListener('emoji-click', event => {
|
||||
document.getElementById('status-emoji').setAttribute('data-emoji', event.detail.unicode)
|
||||
const input = document.getElementById('status-emoji-input')
|
||||
input.value = event.detail.unicode
|
||||
var event = new Event('change');
|
||||
input.dispatchEvent(event);
|
||||
})
|
||||
</script>
|
||||
</menu>
|
||||
</button>
|
||||
</div>
|
||||
<div class="field textarea label border max">
|
||||
<InputTextArea @bind-Value="Content"></InputTextArea>
|
||||
<label>Status</label>
|
||||
</div>
|
||||
</div>
|
||||
<nav class="right-align no-space">
|
||||
<InputText id="status-emoji-input" class="invisible" @bind-Value="Emoji"></InputText>
|
||||
<button class="transparent link" data-ui="#@id" disabled="@loading">Cancel</button>
|
||||
<button @onclick="PatchStatus" disabled="@loading">
|
||||
@if (loading) {
|
||||
<span>Saving...</span>
|
||||
}
|
||||
else {
|
||||
<i class="fa-solid fa-floppy-disk"></i> <span>Save</span>
|
||||
}
|
||||
</button>
|
||||
</nav>
|
||||
</dialog>
|
||||
|
||||
@code {
|
||||
private Status? _status;
|
||||
|
||||
public Status? Status {
|
||||
get => _status;
|
||||
set {
|
||||
_status = value;
|
||||
Content = _status?.Content;
|
||||
Emoji = _status?.Emoji;
|
||||
InvokeAsync(StateHasChanged);
|
||||
}
|
||||
}
|
||||
public string? Content { get; set; }
|
||||
public string? Emoji { get; set; }
|
||||
private bool loading = false;
|
||||
[Parameter]
|
||||
public string id { get; set; }
|
||||
|
||||
protected override async Task OnInitializedAsync() {
|
||||
Content = Status?.Content;
|
||||
Emoji = Status?.Emoji;
|
||||
}
|
||||
|
||||
public async Task PatchStatus() {
|
||||
loading = true;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
|
||||
if (!string.IsNullOrEmpty(Status?.Id)) {
|
||||
await api.PatchStatus(State.SelectedAddressName, Status.Id, Content, Emoji);
|
||||
await State.RefreshStatuses();
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
await JS.InvokeVoidAsync("ui", "#" + id);
|
||||
// clear input
|
||||
Content = string.Empty;
|
||||
Emoji = string.Empty;
|
||||
Status = null;
|
||||
loading = false;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
@inject IJSRuntime JS
|
||||
@inject State State
|
||||
@inject RestService api
|
||||
@if(Html != null) {
|
||||
<iframe id="@id" frameborder="0" scrolling="no" srcdoc="@Html" onload="() => iframeResize({ license: 'GPLv3' })"></iframe>
|
||||
}
|
||||
|
@ -11,11 +12,6 @@
|
|||
public string id { get; set; }
|
||||
public MarkupString? Html { get; set; }
|
||||
|
||||
protected override void OnInitialized() {
|
||||
base.OnInitialized();
|
||||
State.CurrentPage = Page.Other;
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender) {
|
||||
if(firstRender){
|
||||
await Reload();
|
||||
|
@ -24,7 +20,6 @@
|
|||
|
||||
public async Task Reload() {
|
||||
if (Html == null){
|
||||
RestService api = new RestService();
|
||||
Html = await api.GetHtml(Url);
|
||||
string? HtmlString = Html?.ToString();
|
||||
HtmlString = HtmlString?.Replace("</head>", "<base target='_blank'></head>");
|
||||
|
|
78
Components/Layout/AvatarMenu.razor
Normal file
78
Components/Layout/AvatarMenu.razor
Normal file
|
@ -0,0 +1,78 @@
|
|||
@inject CustomAuthenticationStateProvider AuthStateProvider;
|
||||
@inject State State;
|
||||
<AuthorizeView>
|
||||
<Authorized>
|
||||
<NavLink>
|
||||
<button class="transparent circle small large">
|
||||
<img class="responsive avatar" src="https://profiles.cache.lol/@State.SelectedAddressName/picture" alt="@State.SelectedAddressName">
|
||||
<menu class="no-wrap">
|
||||
<a class="m s row">
|
||||
<i class="emoji medium" data-emoji="👋">👋</i>
|
||||
<span>Hey, @State.Name.</span>
|
||||
</a>
|
||||
@foreach (AddressResponseData address in State.AddressList ?? new List<AddressResponseData>()) {
|
||||
<a class="row @(address == State.SelectedAddress ? "active" : "")" @onclick="() => changeAddress(address)">
|
||||
<img class="tiny circle avatar" src="https://profiles.cache.lol/@address.Address/picture" alt="@address.Address" />
|
||||
<span class="address"><i class="fa-solid fa-fw fa-at tiny"></i>@address.Address</span>
|
||||
</a>
|
||||
if (address.Address == State.SelectedAddressName) {
|
||||
<a class="indent row" href="/person/@State.SelectedAddressName#profile">
|
||||
<i class="fa-solid fa-id-card"></i>
|
||||
<span>Profile</span>
|
||||
</a>
|
||||
<a class="indent row" href="/person/@State.SelectedAddressName#statuses">
|
||||
<i class="fa-solid fa-message-smile"></i>
|
||||
<span>Statuslog</span>
|
||||
</a>
|
||||
<a class="indent row" href="/person/@State.SelectedAddressName#pics">
|
||||
<i class="fa-solid fa-images"></i>
|
||||
<span>Pics</span>
|
||||
</a>
|
||||
<a class="indent row" href="/person/@State.SelectedAddressName#now">
|
||||
<i class="fa-duotone fa-seedling"></i>
|
||||
<span>/Now</span>
|
||||
</a>
|
||||
}
|
||||
}
|
||||
<a class="row" @onclick='() => AuthStateProvider.Logout()'>
|
||||
<i class="fa-solid fa-door-open"></i>
|
||||
<span>Logout</span>
|
||||
</a>
|
||||
</menu>
|
||||
</button>
|
||||
<small class="s m address"><i class="fa-solid fa-fw fa-at tiny"></i>@State.SelectedAddressName</small>
|
||||
</NavLink>
|
||||
<div class="l">
|
||||
Hey, @State.Name. <br />
|
||||
<a class="address" href="/person/@State.SelectedAddressName"><i class="fa-solid fa-fw fa-at tiny"></i>@State.SelectedAddressName</a>
|
||||
</div>
|
||||
</Authorized>
|
||||
<NotAuthorized>
|
||||
<NavLink>
|
||||
<button class="transparent square small large">
|
||||
<img class="responsive" src="/img/prami-neighbourhood.svg">
|
||||
<menu class="no-wrap">
|
||||
<a class="m s row">
|
||||
<i class="emoji medium" data-emoji="👋">👋</i>
|
||||
<span>Hey there.</span>
|
||||
</a>
|
||||
<a class="row" href="/login">
|
||||
<i class="fa-solid fa-door-closed"></i>
|
||||
<span>Login</span>
|
||||
</a>
|
||||
</menu>
|
||||
</button>
|
||||
<small class="s m address">Omg.lol</small>
|
||||
</NavLink>
|
||||
<div class="l">
|
||||
Hey there. <br />
|
||||
<a href="/login">Login?</a>
|
||||
</div>
|
||||
</NotAuthorized>
|
||||
</AuthorizeView>
|
||||
|
||||
@code {
|
||||
public void changeAddress(AddressResponseData address) {
|
||||
State.SelectedAddress = address;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
@inherits LayoutComponentBase
|
||||
@implements IDisposable
|
||||
@inject NavigatorService NavigatorService
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject State State
|
||||
|
@ -11,5 +12,22 @@
|
|||
protected override void OnInitialized() {
|
||||
base.OnInitialized();
|
||||
NavigatorService.NavigationManager = NavigationManager;
|
||||
State.IntentReceived += IntentRecieved;
|
||||
if (!string.IsNullOrEmpty(State.ShareString) || !string.IsNullOrEmpty(State.SharePhoto)) {
|
||||
IntentRecieved();
|
||||
}
|
||||
}
|
||||
|
||||
private void IntentRecieved(object? sender = null, EventArgs? e = null) {
|
||||
if (!string.IsNullOrEmpty(State.ShareString)) {
|
||||
NavigationManager.NavigateTo($"/sharetext");
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(State.SharePhoto)) {
|
||||
NavigationManager.NavigateTo($"/sharepic");
|
||||
}
|
||||
}
|
||||
|
||||
void IDisposable.Dispose() {
|
||||
State.IntentReceived -= IntentRecieved;
|
||||
}
|
||||
}
|
||||
|
|
16
Components/Layout/NavLinks.razor
Normal file
16
Components/Layout/NavLinks.razor
Normal file
|
@ -0,0 +1,16 @@
|
|||
<NavLink class="nav-link" href="/statuslog/latest">
|
||||
<i class="square fa-solid fa-message-smile"></i>
|
||||
<div class="label">Status.lol</div>
|
||||
</NavLink>
|
||||
<NavLink class="nav-link" href="/pics">
|
||||
<i class="square fa-solid fa-images"></i>
|
||||
<div class="label">Some.pics</div>
|
||||
</NavLink>
|
||||
<NavLink class="nav-link" href="/ephemeral">
|
||||
<i class="square fa-light fa-comment-dots"></i>
|
||||
<div class="label">Eph.emer.al</div>
|
||||
</NavLink>
|
||||
<NavLink class="nav-link" href="/now">
|
||||
<i class="square fa-duotone fa-seedling"></i>
|
||||
<div class="label">Now.garden</div>
|
||||
</NavLink>
|
|
@ -1,188 +1,14 @@
|
|||
@inject CustomAuthenticationStateProvider AuthStateProvider;
|
||||
@inject State State;
|
||||
<nav class="left drawer l">
|
||||
<nav class="left drawer l">
|
||||
<header>
|
||||
<nav>
|
||||
<AuthorizeView>
|
||||
<Authorized>
|
||||
<button class="transparent circle large">
|
||||
<img class="responsive avatar" src="https://profiles.cache.lol/@State.SelectedAddressName/picture" alt="@State.SelectedAddressName">
|
||||
<menu class="no-wrap">
|
||||
@foreach (AddressResponseData address in State.AddressList ?? new List<AddressResponseData>()) {
|
||||
<a class="row @(address == State.SelectedAddress ? "active" : "")" @onclick="() => changeAddress(address)">
|
||||
<img class="tiny circle avatar" src="https://profiles.cache.lol/@address.Address/picture" alt="@address.Address" />
|
||||
<span class="address"><i class="fa-solid fa-fw fa-at tiny"></i>@address.Address</span>
|
||||
</a>
|
||||
}
|
||||
<a class="row" @onclick='() => AuthStateProvider.Logout()'>
|
||||
<i class="fa-solid fa-door-open"></i>
|
||||
<span>Logout</span>
|
||||
</a>
|
||||
</menu>
|
||||
</button>
|
||||
<div>
|
||||
Hey, @State.Name. <br />
|
||||
<a class="address" href="/person/@State.SelectedAddressName"><i class="fa-solid fa-fw fa-at tiny"></i>@State.SelectedAddressName</a>
|
||||
</div>
|
||||
</Authorized>
|
||||
<NotAuthorized>
|
||||
<button class="transparent square large">
|
||||
<img class="responsive" src="/img/prami-neighbourhood.svg">
|
||||
<menu class="no-wrap">
|
||||
<a class="row" href="/login">
|
||||
<i class="fa-solid fa-door-closed"></i>
|
||||
<span>Login</span>
|
||||
</a>
|
||||
</menu>
|
||||
</button>
|
||||
<div>
|
||||
Hey there. <br />
|
||||
<a href="/login">Login?</a>
|
||||
</div>
|
||||
</NotAuthorized>
|
||||
</AuthorizeView>
|
||||
<AvatarMenu></AvatarMenu>
|
||||
</nav>
|
||||
</header>
|
||||
<NavLink class="row nav-link" href="/statuslog/latest">
|
||||
<i class="fa-solid fa-message-smile"></i>
|
||||
<div>Status.lol</div>
|
||||
</NavLink>
|
||||
<NavLink class="row nav-link" href="/pics">
|
||||
<i class="fa-solid fa-images"></i>
|
||||
<div>Some.pics</div>
|
||||
</NavLink>
|
||||
<NavLink class="row nav-link" href="/ephemeral">
|
||||
<i class="fa-light fa-comment-dots"></i>
|
||||
<div>Eph.emer.al</div>
|
||||
</NavLink>
|
||||
<NavLink class="row nav-link" href="/now">
|
||||
<i class="fa-duotone fa-seedling"></i>
|
||||
<div>Now.garden</div>
|
||||
</NavLink>
|
||||
<NavLinks></NavLinks>
|
||||
</nav>
|
||||
|
||||
<nav class="left m">
|
||||
<header>
|
||||
<AuthorizeView>
|
||||
<Authorized>
|
||||
<button class="transparent circle">
|
||||
<img class="responsive" src="https://profiles.cache.lol/@State.SelectedAddressName/picture" alt="@State.SelectedAddressName">
|
||||
<menu class="no-wrap">
|
||||
<a class="row">
|
||||
<img class="tiny" data-emoji="👋">
|
||||
<span>Hey, @State.Name.</span>
|
||||
</a>
|
||||
@foreach (AddressResponseData address in State.AddressList ?? new List<AddressResponseData>()) {
|
||||
<a class="row @(address == State.SelectedAddress ? "active" : "")" @onclick="() => changeAddress(address)">
|
||||
<img class="tiny circle" src="https://profiles.cache.lol/@address.Address/picture" alt="@address.Address">
|
||||
<span class="address"><i class="fa-solid fa-fw fa-at tiny"></i>@address.Address</span>
|
||||
</a>
|
||||
}
|
||||
<a class="row" @onclick='() => AuthStateProvider.Logout()'>
|
||||
<i class="fa-solid fa-door-open"></i>
|
||||
<span>Logout</span>
|
||||
</a>
|
||||
</menu>
|
||||
</button>
|
||||
</Authorized>
|
||||
<NotAuthorized>
|
||||
<button class="transparent square">
|
||||
<img class="responsive" src="/img/prami-neighbourhood.svg">
|
||||
<menu class="no-wrap">
|
||||
<a class="row">
|
||||
<i class="medium" data-emoji="👋"></i>
|
||||
<span>Hey there.</span>
|
||||
</a>
|
||||
<a class="row" href="/login">
|
||||
<i class="fa-solid fa-door-closed"></i>
|
||||
<span>Login</span>
|
||||
</a>
|
||||
</menu>
|
||||
</button>
|
||||
</NotAuthorized>
|
||||
</AuthorizeView>
|
||||
</header>
|
||||
<NavLink class="nav-link" href="/statuslog/latest">
|
||||
<i class="fa-solid fa-message-smile"></i>
|
||||
<small>Status.lol</small>
|
||||
</NavLink>
|
||||
<NavLink class="nav-link" href="/pics">
|
||||
<i class="fa-solid fa-image"></i>
|
||||
<small>Some.pics</small>
|
||||
</NavLink>
|
||||
<NavLink class="nav-link" href="/ephemeral">
|
||||
<i class="fa-light fa-comment-dots"></i>
|
||||
<small>Eph.emer.al</small>
|
||||
</NavLink>
|
||||
<NavLink class="nav-link" href="/now">
|
||||
<i class="fa-duotone fa-seedling"></i>
|
||||
<small>Now.garden</small>
|
||||
</NavLink>
|
||||
<nav class="bottom m s scroll">
|
||||
<NavLinks></NavLinks>
|
||||
<AvatarMenu></AvatarMenu>
|
||||
</nav>
|
||||
|
||||
<nav class="bottom s">
|
||||
<NavLink class="nav-link" href="/statuslog/latest">
|
||||
<i class="fa-solid fa-message-smile"></i>
|
||||
<small>Status.lol</small>
|
||||
</NavLink>
|
||||
<NavLink class="nav-link" href="/pics">
|
||||
<i class="fa-solid fa-image"></i>
|
||||
<small>Some.pics</small>
|
||||
</NavLink>
|
||||
<NavLink class="nav-link" href="/ephemeral">
|
||||
<i class="fa-light fa-comment-dots"></i>
|
||||
<small>Eph.emer.al</small>
|
||||
</NavLink>
|
||||
<NavLink class="nav-link" href="/now">
|
||||
<i class="fa-duotone fa-seedling"></i>
|
||||
<small>Now.garden</small>
|
||||
</NavLink>
|
||||
|
||||
<AuthorizeView>
|
||||
<Authorized>
|
||||
<NavLink>
|
||||
<button class="transparent circle small">
|
||||
<img class="responsive" src="https://profiles.cache.lol/@State.SelectedAddressName/picture" alt="@State.SelectedAddressName">
|
||||
<menu>
|
||||
<a class="row">
|
||||
<img class="tiny" data-emoji="👋">
|
||||
<span>Hey, @State.Name.</span>
|
||||
</a>
|
||||
@foreach (AddressResponseData address in State.AddressList ?? new List<AddressResponseData>()) {
|
||||
<a class="row @(address == State.SelectedAddress ? "active" : "")" @onclick="() => changeAddress(address)">
|
||||
<img class="tiny circle" src="https://profiles.cache.lol/@address.Address/picture" alt="@address.Address">
|
||||
<span class="address"><i class="fa-solid fa-fw fa-at tiny"></i>@address.Address</span>
|
||||
</a>
|
||||
}
|
||||
<a class="row" @onclick='() => AuthStateProvider.Logout()'>
|
||||
<i class="fa-solid fa-door-open"></i>
|
||||
<span>Logout</span>
|
||||
</a>
|
||||
</menu>
|
||||
</button>
|
||||
<small class="address"><i class="fa-solid fa-fw fa-at tiny"></i>@State.SelectedAddressName</small>
|
||||
</NavLink>
|
||||
</Authorized>
|
||||
<NotAuthorized>
|
||||
<button class="transparent square">
|
||||
<img class="responsive" src="/img/prami-neighbourhood.svg">
|
||||
<menu>
|
||||
<a class="row">
|
||||
<i class="medium" data-emoji="👋"></i>
|
||||
<span>Hey there.</span>
|
||||
</a>
|
||||
<a class="row" href="/login">
|
||||
<i class="fa-solid fa-door-closed"></i>
|
||||
<span>Login</span>
|
||||
</a>
|
||||
</menu>
|
||||
</button>
|
||||
</NotAuthorized>
|
||||
</AuthorizeView>
|
||||
</nav>
|
||||
|
||||
@code {
|
||||
public void changeAddress(AddressResponseData address) {
|
||||
State.SelectedAddress = address;
|
||||
}
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
@inject IJSRuntime JS
|
||||
@inject State State
|
||||
@inject RestService api
|
||||
@inject NavigationManager navigationManager
|
||||
|
||||
<div class="overlay" data-ui="#@id"></div>
|
||||
<dialog id="@id">
|
||||
<div class="overlay @(Active ? "active" : string.Empty)" data-ui="#@id"></div>
|
||||
<dialog id="@id" class="@(Active ? "active" : string.Empty)" open="@Active">
|
||||
<h5>Share a picture</h5>
|
||||
<div class="row">
|
||||
<button @onclick="PicFromMedia"><i class="fa-solid fa-image"></i> Select a picture</button>
|
||||
|
@ -13,10 +15,12 @@
|
|||
<input type="text">
|
||||
<label>Select a picture</label>
|
||||
</div> *@
|
||||
@if(File != null && Base64File != null && FileSize != null){
|
||||
</div>
|
||||
<div class="row">
|
||||
@if(Base64File != null && FileSize != null){
|
||||
<img class="extra" src="@Base64Url">
|
||||
<small>
|
||||
@File.ContentType (@formatSizeUnits(FileSize))
|
||||
@FileContentType (@formatSizeUnits(FileSize))
|
||||
</small>
|
||||
}
|
||||
|
||||
|
@ -42,27 +46,35 @@
|
|||
|
||||
@code {
|
||||
// private IBrowserFile? File { get; set; }
|
||||
private FileResult? File { get; set; }
|
||||
private string? Base64File { get; set; }
|
||||
private long? FileSize { get; set; }
|
||||
private string? Base64Url {
|
||||
get {
|
||||
if(File == null || Base64File == null) return null;
|
||||
|
||||
return $"data:{File.ContentType};base64,{Base64File}";
|
||||
}
|
||||
}
|
||||
private string Description { get; set; }
|
||||
private bool loading = false;
|
||||
[Parameter]
|
||||
public string? Base64File { get; set; }
|
||||
[Parameter]
|
||||
public long? FileSize { get; set; }
|
||||
[Parameter]
|
||||
public string? FileContentType { get; set; }
|
||||
[Parameter]
|
||||
public string? Description { get; set; }
|
||||
[Parameter]
|
||||
public string id { get; set; }
|
||||
[Parameter]
|
||||
public bool Active { get; set; }
|
||||
|
||||
private bool loading = false;
|
||||
|
||||
private FileResult? File { get; set; }
|
||||
private string? Base64Url {
|
||||
get {
|
||||
if (FileContentType == null || Base64File == null) return null;
|
||||
|
||||
return $"data:{FileContentType};base64,{Base64File}";
|
||||
}
|
||||
}
|
||||
|
||||
public async Task PostPic() {
|
||||
loading = true;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
|
||||
RestService api = new RestService();
|
||||
PutPicResponseData? response = await api.PutPic(State.SelectedAddressName, File);
|
||||
PutPicResponseData? response = await api.PutPic(State.SelectedAddressName, Base64File);
|
||||
if(!string.IsNullOrEmpty(Description) && response != null && !string.IsNullOrEmpty(response.Id)) {
|
||||
await api.PostPicDescription(State.SelectedAddressName, response.Id, Description);
|
||||
await State.RefreshPics();
|
||||
|
@ -78,6 +90,13 @@
|
|||
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender) {
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
if (firstRender) {
|
||||
string tmp = "tmp";
|
||||
}
|
||||
}
|
||||
|
||||
// private async Task ChangeFile(InputFileChangeEventArgs e){
|
||||
// File = e.File;
|
||||
// }
|
||||
|
@ -94,7 +113,7 @@
|
|||
return formatted;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private async Task PicFromMedia(EventArgs e) {
|
||||
File = await MediaPicker.Default.PickPhotoAsync();
|
||||
|
@ -107,7 +126,8 @@
|
|||
}
|
||||
|
||||
private async Task PopulateFileDetails() {
|
||||
FileSize = await State.FileSize(File);
|
||||
Base64File = await State.Base64FromFile(File);
|
||||
FileContentType = File.ContentType;
|
||||
FileSize = await Utilities.FileSize(File);
|
||||
Base64File = await Utilities.Base64FromFile(File);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
@inject IJSRuntime JS
|
||||
@inject State State
|
||||
@inject RestService api
|
||||
@inject NavigationManager navigationManager
|
||||
|
||||
<div class="overlay" data-ui="#@id"></div>
|
||||
<dialog id="@id">
|
||||
<div class="overlay @(Active ? "active" : string.Empty)" data-ui="#@id"></div>
|
||||
<dialog id="@id" class="@(Active ? "active" : string.Empty)" open="@Active">
|
||||
<h5>Share your status</h5>
|
||||
<div class="row">
|
||||
<div class="min square extra">
|
||||
<button class="transparent square extra no-margin">
|
||||
<object id="status-emoji" class="large emoji @(statusEmoji == null ? "animated" : string.Empty)" data-emoji="@(statusEmoji ?? "🫥")">@(statusEmoji ?? "🫥")</object>
|
||||
<object id="status-emoji" class="large emoji @(Emoji == null ? "animated" : string.Empty)" data-emoji="@(Emoji ?? "🫥")">@(Emoji ?? "🫥")</object>
|
||||
<menu class="no-wrap">
|
||||
<script type="module" src="https://cdn.jsdelivr.net/npm/emoji-picker-element@@^1/index.js"></script>
|
||||
<emoji-picker emoji-version="15.1"></emoji-picker>
|
||||
|
@ -25,7 +27,7 @@
|
|||
</button>
|
||||
</div>
|
||||
<div class="field textarea border max">
|
||||
<InputTextArea @bind-Value="statusContent"></InputTextArea>
|
||||
<InputTextArea @bind-Value="Content"></InputTextArea>
|
||||
</div>
|
||||
</div>
|
||||
<nav class="right-align no-space">
|
||||
|
@ -35,7 +37,7 @@
|
|||
<span>Post this to Mastodon</span>
|
||||
</label>
|
||||
}
|
||||
<InputText id="status-emoji-input" class="invisible" @bind-Value="statusEmoji"></InputText>
|
||||
<InputText id="status-emoji-input" class="invisible" @bind-Value="Emoji"></InputText>
|
||||
<button class="transparent link" data-ui="#@id" disabled="@loading">Cancel</button>
|
||||
<button @onclick="PostStatus" disabled="@loading">
|
||||
@if (loading) {
|
||||
|
@ -49,20 +51,25 @@
|
|||
</dialog>
|
||||
|
||||
@code {
|
||||
private string statusContent = string.Empty;
|
||||
private string? statusEmoji = null;
|
||||
private bool postToMastodon = true;
|
||||
private bool loading = false;
|
||||
[Parameter]
|
||||
public string id { get; set; }
|
||||
[Parameter]
|
||||
public bool Active { get; set; }
|
||||
[Parameter]
|
||||
public string Content { get; set; } = string.Empty;
|
||||
[Parameter]
|
||||
public string? Emoji { get; set; } = null;
|
||||
[Parameter]
|
||||
public bool postToMastodon { get; set; } = true;
|
||||
|
||||
private bool loading = false;
|
||||
|
||||
public async Task PostStatus() {
|
||||
await JS.InvokeVoidAsync("console.log", "hey from post status");
|
||||
|
||||
StatusPost post = new StatusPost
|
||||
{
|
||||
Emoji = statusEmoji,
|
||||
Content = statusContent
|
||||
Emoji = Emoji,
|
||||
Content = Content
|
||||
};
|
||||
|
||||
if (State?.SelectedAddress?.Preferences?.Statuslog?.MastodonPosting ?? false){
|
||||
|
@ -70,17 +77,18 @@
|
|||
}
|
||||
|
||||
loading = true;
|
||||
InvokeAsync(StateHasChanged);
|
||||
|
||||
RestService api = new RestService();
|
||||
var result = await api.StatusPost(State.SelectedAddressName, post);
|
||||
await InvokeAsync(StateHasChanged);
|
||||
var result = await api.StatusPost(State!.SelectedAddressName!, post);
|
||||
if(result != null){
|
||||
State.RefreshStatuses().ContinueWith(t => InvokeAsync(StateHasChanged));
|
||||
await State.RefreshStatuses();
|
||||
await InvokeAsync(StateHasChanged);
|
||||
navigationManager.NavigateTo("/statuslog/latest");
|
||||
}
|
||||
|
||||
this.Active = false;
|
||||
await JS.InvokeVoidAsync("ui", "#" + id);
|
||||
statusContent = string.Empty;
|
||||
statusEmoji = null;
|
||||
Content = string.Empty;
|
||||
Emoji = null;
|
||||
postToMastodon = true;
|
||||
loading = false;
|
||||
}
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
<div class="row center-align">
|
||||
<h3>
|
||||
<i class="@icon extra"></i> @title
|
||||
<h1><i class="@icon page-heading-icon"></i></h1>
|
||||
</div>
|
||||
<div class="row center-align">
|
||||
<h3 class="page-heading">
|
||||
@title
|
||||
</h3>
|
||||
</div>
|
||||
<div class="row center-align">
|
||||
<p>@Description</p>
|
||||
</div>
|
||||
<div class="space"></div>
|
||||
<div class="space margin"></div>
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
@page "/ephemeral"
|
||||
@implements IDisposable
|
||||
@inject IJSRuntime JS
|
||||
@inject State State
|
||||
|
||||
<RefreshButton></RefreshButton>
|
||||
|
||||
<PageHeading title="Eph.emer.al" icon="fa-light fa-comment-dots">
|
||||
<Description><a href="https://eph.emer.al">Eph.emer.al</a> is a place for fleeting thoughts. Everything on this page will disappear after a while.</Description>
|
||||
</PageHeading>
|
||||
|
@ -24,7 +28,21 @@
|
|||
protected override async Task OnInitializedAsync() {
|
||||
await base.OnInitializedAsync();
|
||||
if (messages == null || messages.Count == 0) messages = await State.GetEphemeralMessages();
|
||||
State.PropertyChanged += StateChanged;
|
||||
State.CanRefresh = true;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
await JS.InvokeVoidAsync("removeElementById", "ephemeral-loading");
|
||||
}
|
||||
|
||||
private async void StateChanged(object? sender, PropertyChangedEventArgs e) {
|
||||
if (e.PropertyName == nameof(State.IsRefreshing) && State.IsRefreshing) {
|
||||
messages = await State.GetEphemeralMessages(true);
|
||||
State.IsRefreshing = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
State.PropertyChanged -= StateChanged;
|
||||
State.CanRefresh = false;
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
@page "/"
|
||||
@inject CustomAuthenticationStateProvider AuthStateProvider;
|
||||
|
||||
<h1><i data-emoji="👋"></i> Hello, lol!</h1>
|
||||
<a @onclick='() => AuthStateProvider.Logout()'>Logout</a>
|
||||
|
||||
Welcome to your new app.
|
|
@ -1,6 +1,10 @@
|
|||
@page "/now"
|
||||
@implements IDisposable
|
||||
@inject IJSRuntime JS
|
||||
@inject State State
|
||||
|
||||
<RefreshButton></RefreshButton>
|
||||
|
||||
<PageHeading title="Now.garden" icon="fa-duotone fa-seedling">
|
||||
<Description>Feel free to stroll through the <a href="now.garden">now.garden</a> and take a look at what people are up to.</Description>
|
||||
</PageHeading>
|
||||
|
@ -12,7 +16,7 @@
|
|||
<article class="now">
|
||||
<nav>
|
||||
<a class="author" href="/person/@now.Address#now">
|
||||
<i class="fa-duotone fa-seedling"></i> @now.Address
|
||||
<h6><i class="fa-duotone fa-seedling"></i> @now.Address</h6>
|
||||
</a>
|
||||
</nav>
|
||||
<nav>
|
||||
|
@ -31,7 +35,21 @@
|
|||
protected override async Task OnInitializedAsync() {
|
||||
await base.OnInitializedAsync();
|
||||
if (garden == null || garden.Count == 0) garden = await State.GetNowGarden();
|
||||
State.PropertyChanged += StateChanged;
|
||||
State.CanRefresh = true;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
await JS.InvokeVoidAsync("removeElementById", "now-loading");
|
||||
}
|
||||
|
||||
private async void StateChanged(object? sender, PropertyChangedEventArgs e) {
|
||||
if (e.PropertyName == nameof(State.IsRefreshing) && State.IsRefreshing) {
|
||||
garden = await State.GetNowGarden(true);
|
||||
State.IsRefreshing = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
State.PropertyChanged -= StateChanged;
|
||||
State.CanRefresh = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,16 +3,18 @@
|
|||
@inject IJSRuntime JS
|
||||
@inject NavigationManager Nav
|
||||
|
||||
<RefreshButton></RefreshButton>
|
||||
|
||||
|
||||
<div class="row center-align">
|
||||
<h3><i class="fa-solid fa-fw fa-at"></i>@Address</h3>
|
||||
<h3 class="page-heading"><i class="fa-solid fa-fw fa-at"></i>@Address</h3>
|
||||
</div>
|
||||
<div class="row center-align">
|
||||
<img class="profile avatar" src="https://profiles.cache.lol/@Address/picture" alt="@Address" />
|
||||
</div>
|
||||
|
||||
<div class="responsive">
|
||||
<div class="tabs">
|
||||
<div class="tabs scroll">
|
||||
<a data-ui="#profile" @onclick="ReloadProfile">
|
||||
<i class="fa-solid fa-id-card"></i>
|
||||
<span>@(Address).omg.lol</span>
|
||||
|
@ -41,21 +43,35 @@
|
|||
</div>
|
||||
|
||||
<div id="statuses" class="page padding active">
|
||||
<div id="info" class="box basis transparent">
|
||||
<article id="bio" class="container shadowed blue-2-bg gray-9-fg">
|
||||
@if (bio == null) {
|
||||
<p><progress class="circle small"></progress></p>
|
||||
}
|
||||
else {
|
||||
@bio
|
||||
}
|
||||
</article>
|
||||
</div>
|
||||
<StatusList StatusFunc="@(async() => await State.GetStatuses(Address))"></StatusList>
|
||||
@if(bio == null || !string.IsNullOrEmpty(bio.ToString())) {
|
||||
<div id="info" class="box basis transparent">
|
||||
<article id="bio" class="container shadowed blue-2-bg gray-9-fg">
|
||||
@if (bio == null) {
|
||||
<p><progress class="circle small"></progress></p>
|
||||
}
|
||||
else {
|
||||
@bio
|
||||
}
|
||||
</article>
|
||||
</div>
|
||||
}
|
||||
<StatusList @ref="StatusList" StatusFunc="@(async(refresh) => await State.GetStatuses(Address, refresh))" Editable="@IsMe"></StatusList>
|
||||
@if(IsMe) {
|
||||
<button class="fab circle extra large-elevate" data-ui="#post-modal">
|
||||
<i class="fa-solid fa-pen-to-square"></i>
|
||||
</button>
|
||||
<NewStatusDialog id="post-modal"></NewStatusDialog>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div id="pics" class="page padding">
|
||||
<PicList PicsFunc="@(async() => await State.GetPics(Address))" Editable="@Editable"></PicList>
|
||||
<PicList @ref="PicList" PicsFunc="@(async(refresh) => await State.GetPics(Address, refresh))" Editable="@IsMe"></PicList>
|
||||
@if (IsMe) {
|
||||
<button class="fab circle extra large-elevate" data-ui="#post-modal">
|
||||
<i class="fa-solid fa-camera-retro"></i>
|
||||
</button>
|
||||
<NewPicDialog id="post-modal"></NewPicDialog>
|
||||
}
|
||||
</div>
|
||||
@if(now != null){
|
||||
<div id="now" class="page no-padding">
|
||||
|
@ -66,8 +82,16 @@
|
|||
</div>
|
||||
|
||||
@code {
|
||||
private string _address;
|
||||
[Parameter]
|
||||
public string Address { get; set; }
|
||||
public string Address {
|
||||
get => _address;
|
||||
set {
|
||||
_address = value;
|
||||
if (StatusList != null) StatusList.StatusFunc = async (refresh) => await State.GetStatuses(_address, refresh);
|
||||
if (PicList != null) PicList.PicsFunc = async (refresh) => await State.GetPics(_address, refresh);
|
||||
}
|
||||
}
|
||||
public string ProfileUrl {
|
||||
get => $"https://{Address}.omg.lol/";
|
||||
}
|
||||
|
@ -75,7 +99,10 @@
|
|||
public ExternalPageComponent? NowPage { get; set; }
|
||||
public ExternalPageComponent? ProfilePage { get; set; }
|
||||
|
||||
private bool Editable {
|
||||
private StatusList StatusList { get; set; }
|
||||
private PicList PicList { get; set; }
|
||||
|
||||
private bool IsMe {
|
||||
get => Address == State.SelectedAddressName;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
@page "/pics"
|
||||
@inject State State
|
||||
|
||||
<RefreshButton></RefreshButton>
|
||||
|
||||
<PageHeading title="Some.pics" icon="fa-solid fa-images">
|
||||
<Description>Sit back, relax, and look at <a href="https://some.pics/">some.pics</a></Description>
|
||||
</PageHeading>
|
||||
|
@ -15,7 +17,7 @@
|
|||
</AuthorizeView>
|
||||
|
||||
<div id="pics" class="responsive card-grid">
|
||||
<PicList PicsFunc="@(async() => await State.GetPics())"></PicList>
|
||||
<PicList PicsFunc="@(async(refresh) => await State.GetPics(refresh))"></PicList>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
|
|
51
Components/Pages/SharePic.razor
Normal file
51
Components/Pages/SharePic.razor
Normal file
|
@ -0,0 +1,51 @@
|
|||
@page "/sharepic"
|
||||
@inject NavigationManager navigationManager
|
||||
@inject AuthenticationStateProvider AuthStateProvider
|
||||
@inject State State
|
||||
|
||||
<PageHeading title="Some.pics" icon="fa-solid fa-images">
|
||||
<Description>Upload an image to <a href="https://some.pics/">some.pics</a></Description>
|
||||
</PageHeading>
|
||||
|
||||
<AuthorizeView>
|
||||
<Authorized>
|
||||
<button class="fab circle extra large-elevate" data-ui="#post-modal">
|
||||
<i class="fa-solid fa-camera-retro"></i>
|
||||
</button>
|
||||
<NewPicDialog id="post-modal" Active="true" Base64File="@SharePhoto" FileSize="@SharePhotoSize" FileContentType="@SharePhotoContentType" Description="@SharePhotoText"></NewPicDialog>
|
||||
</Authorized>
|
||||
</AuthorizeView>
|
||||
|
||||
@code {
|
||||
public string SharePhoto { get; set; }
|
||||
public long? SharePhotoSize { get; set; }
|
||||
public string? SharePhotoContentType { get; set; }
|
||||
public string? SharePhotoText { get; set; }
|
||||
|
||||
protected override async Task OnInitializedAsync() {
|
||||
await checkLogin();
|
||||
|
||||
SharePhoto = State.SharePhoto;
|
||||
SharePhotoContentType = State.SharePhotoContentType;
|
||||
SharePhotoSize = State.SharePhotoSize;
|
||||
SharePhotoText = State.SharePhotoText;
|
||||
|
||||
State.SharePhoto = null;
|
||||
State.SharePhotoContentType = null;
|
||||
State.SharePhotoSize = null;
|
||||
State.SharePhotoText = null;
|
||||
}
|
||||
|
||||
private async Task<bool> checkLogin() {
|
||||
var authState = await AuthStateProvider.GetAuthenticationStateAsync();
|
||||
var user = authState.User;
|
||||
|
||||
if (user.Identity is not null && user.Identity.IsAuthenticated) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
navigationManager.NavigateTo("/login");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
47
Components/Pages/ShareText.razor
Normal file
47
Components/Pages/ShareText.razor
Normal file
|
@ -0,0 +1,47 @@
|
|||
@page "/sharetext"
|
||||
@inject NavigationManager navigationManager
|
||||
@inject AuthenticationStateProvider AuthStateProvider
|
||||
@inject State State
|
||||
|
||||
<PageHeading title="Status.lol" icon="fa-solid fa-message-smile">
|
||||
<Description>Share a post to <a href="https://status.lol">status.lol</a></Description>
|
||||
</PageHeading>
|
||||
|
||||
<AuthorizeView>
|
||||
<Authorized>
|
||||
<button class="fab circle extra large-elevate" data-ui="#post-modal">
|
||||
<i class="fa-solid fa-pen-to-square"></i>
|
||||
</button>
|
||||
<NewStatusDialog id="post-modal" Active="true" Content="@Text"></NewStatusDialog>
|
||||
</Authorized>
|
||||
</AuthorizeView>
|
||||
|
||||
@code {
|
||||
public string? Text { get; set; }
|
||||
|
||||
protected override async Task OnInitializedAsync() {
|
||||
await checkLogin();
|
||||
|
||||
Text = State.ShareString;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(State.ShareStringSubject)) {
|
||||
Text = $"{State.ShareStringSubject}\n\n{State.ShareString}";
|
||||
}
|
||||
|
||||
State.ShareStringSubject = null;
|
||||
State.ShareString = null;
|
||||
}
|
||||
|
||||
private async Task<bool> checkLogin() {
|
||||
var authState = await AuthStateProvider.GetAuthenticationStateAsync();
|
||||
var user = authState.User;
|
||||
|
||||
if (user.Identity is not null && user.Identity.IsAuthenticated) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
navigationManager.NavigateTo("/login");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,9 @@
|
|||
@page "/statuslog/latest"
|
||||
@page "/"
|
||||
@page "/statuslog/latest"
|
||||
@inject State State
|
||||
|
||||
<RefreshButton></RefreshButton>
|
||||
|
||||
<PageHeading title="Status.lol" icon="fa-solid fa-message-smile">
|
||||
<Description>The latest posts from everyone at <a href="https://status.lol">status.lol</a></Description>
|
||||
</PageHeading>
|
||||
|
@ -15,7 +18,7 @@
|
|||
</AuthorizeView>
|
||||
|
||||
<div id="statuses" class="responsive">
|
||||
<StatusList StatusFunc="@(async() => await State.GetStatuses())"></StatusList>
|
||||
<StatusList StatusFunc="@(async(refresh) => await State.GetStatuses(refresh))"></StatusList>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
@code {
|
||||
[Parameter]
|
||||
public Pic Pic {get; set;}
|
||||
[Parameter]
|
||||
[Parameter]
|
||||
public bool Editable { get; set; } = false;
|
||||
[Parameter]
|
||||
public EditPicDialog? Dialog { get; set; }
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
<template id="PicCard">
|
||||
<article class="no-padding">
|
||||
<img src="{{Pic.Url}}" loading="lazy">
|
||||
<div class="padding">
|
||||
<nav>
|
||||
<a class="author" href="/person/{{Pic.Address}}#pics">
|
||||
<i class="fa-solid fa-fw fa-at"></i>{{Pic.Address}}
|
||||
</a>
|
||||
<span class="max"></span>
|
||||
<a class="chip transparent-border right">
|
||||
<i class="fa fa-clock"></i> {{Pic.RelativeTime}}
|
||||
</a>
|
||||
<span class="max"></span>
|
||||
<button class="share-button transparent circle">
|
||||
<input type="hidden" name="url" value="{{Pic.Url}}" />
|
||||
<input type="hidden" name="description" value="{{Pic.Description}}" />
|
||||
<i class="fa-solid fa-share-nodes"></i>
|
||||
</button>
|
||||
</nav>
|
||||
<p class="description">{{Pic.Description}}</p>
|
||||
<nav>
|
||||
<div class="max"></div>
|
||||
<button class="edit-button">
|
||||
<input type="hidden" name="id" value="{{Pic.Id}}" />
|
||||
<i class="fa-solid fa-pencil"></i> Edit
|
||||
</button>
|
||||
</nav>
|
||||
</div>
|
||||
</article>
|
||||
</template>
|
|
@ -1,23 +0,0 @@
|
|||
<template id="PicCard">
|
||||
<article class="no-padding">
|
||||
<img src="{{Pic.Url}}" loading="lazy">
|
||||
<div class="padding">
|
||||
<nav>
|
||||
<a class="author" href="/person/{{Pic.Address}}#pics">
|
||||
<i class="fa-solid fa-fw fa-at"></i>{{Pic.Address}}
|
||||
</a>
|
||||
<span class="max"></span>
|
||||
<a class="chip transparent-border right">
|
||||
<i class="fa fa-clock"></i> {{Pic.RelativeTime}}
|
||||
</a>
|
||||
<span class="max"></span>
|
||||
<button class="share-button transparent circle">
|
||||
<input type="hidden" name="url" value="{{Pic.Url}}" />
|
||||
<input type="hidden" name="description" value="{{Pic.Description}}" />
|
||||
<i class="fa-solid fa-share-nodes"></i>
|
||||
</button>
|
||||
</nav>
|
||||
<p class="description">{{Pic.DescriptionHtml}}</p>
|
||||
</div>
|
||||
</article>
|
||||
</template>
|
|
@ -1,4 +1,5 @@
|
|||
@inject IJSRuntime JS
|
||||
@implements IDisposable
|
||||
@inject IJSRuntime JS
|
||||
@inject State State
|
||||
|
||||
@if (Editable) {
|
||||
|
@ -13,7 +14,7 @@
|
|||
|
||||
@code {
|
||||
[Parameter]
|
||||
public Func<Task<List<Pic>?>> PicsFunc { get; set; }
|
||||
public Func<bool, Task<List<Pic>?>> PicsFunc { get; set; }
|
||||
[Parameter]
|
||||
public bool Editable { get; set; } = false;
|
||||
|
||||
|
@ -24,8 +25,22 @@
|
|||
// TODO: There is a noticable rendering delay between the pics loading and the page rendering
|
||||
protected override async Task OnInitializedAsync() {
|
||||
await base.OnInitializedAsync();
|
||||
if (pics == null || pics.Count == 0) pics = await PicsFunc();
|
||||
if (pics == null || pics.Count == 0) pics = await PicsFunc(false);
|
||||
State.PropertyChanged += StateChanged;
|
||||
State.CanRefresh = true;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
await JS.InvokeVoidAsync("removeElementById", "pics-loading");
|
||||
}
|
||||
|
||||
private async void StateChanged(object? sender, PropertyChangedEventArgs e) {
|
||||
if (e.PropertyName == nameof(State.IsRefreshing) && State.IsRefreshing) {
|
||||
pics = await PicsFunc(true);
|
||||
State.IsRefreshing = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
State.PropertyChanged -= StateChanged;
|
||||
State.CanRefresh = false;
|
||||
}
|
||||
}
|
18
Components/RefreshButton.razor
Normal file
18
Components/RefreshButton.razor
Normal file
|
@ -0,0 +1,18 @@
|
|||
@inject State State
|
||||
|
||||
<button id="refreshButton" class="absolute transparent circle top right margin" @onclick="() => State.IsRefreshing = true">
|
||||
<i class="fa-solid fa-arrow-rotate-right @(State.IsRefreshing ? "fa-spin" : "")"></i>
|
||||
</button>
|
||||
|
||||
@code {
|
||||
protected override async Task OnInitializedAsync() {
|
||||
await base.OnInitializedAsync();
|
||||
State.PropertyChanged += StateChanged;
|
||||
}
|
||||
|
||||
private async void StateChanged(object? sender, PropertyChangedEventArgs e) {
|
||||
if (e.PropertyName == nameof(State.IsRefreshing)) {
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
@using Microsoft.AspNetCore.Components.Authorization
|
||||
@inject NavigationManager navigationManager
|
||||
<Router AppAssembly="@typeof(MauiProgram).Assembly">
|
||||
<Found Context="routeData">
|
||||
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(Layout.MainLayout)">
|
||||
|
@ -16,3 +17,15 @@
|
|||
</CascadingAuthenticationState>
|
||||
</NotFound>
|
||||
</Router>
|
||||
|
||||
|
||||
@code
|
||||
{
|
||||
protected override void OnAfterRender(bool firstRender) {
|
||||
string? shareString = Preferences.Get("shareString", null);
|
||||
if (!string.IsNullOrWhiteSpace(shareString)) {
|
||||
Preferences.Remove("shareString");
|
||||
navigationManager.NavigateTo($"/sharetext/{shareString}");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,34 +1,53 @@
|
|||
<article class="status">
|
||||
@inject IJSRuntime JS
|
||||
|
||||
<article class="status gray-9-fg" style="background-color:@(Status.Background)">
|
||||
<div class="row">
|
||||
<div class="emoji" data-emoji="@status.EmojiOrDefault">@status.EmojiOrDefault</div>
|
||||
<div class="emoji" data-emoji="@Status.EmojiOrDefault">@Status.EmojiOrDefault</div>
|
||||
<div class="max">
|
||||
<a class="author" href="/person/@status.Address">
|
||||
<i class="fa-solid fa-fw fa-at"></i>@status.Address
|
||||
</a>
|
||||
@status.HtmlContent
|
||||
<nav class="no-margin">
|
||||
<a class="chip transparent-border">
|
||||
<i class="fa fa-clock"></i> @status.RelativeTime
|
||||
</a>
|
||||
<a class="chip transparent-border" href="@status.ExternalUrl" target="_blank">
|
||||
<i class="fa fa-message-dots"></i> Respond
|
||||
<div class="row">
|
||||
<a class="author" href="/person/@Status.Address">
|
||||
<i class="fa-solid fa-fw fa-at"></i>@Status.Address
|
||||
</a>
|
||||
<div class="max"></div>
|
||||
<button class="transparent circle" @onclick="ShareClick">
|
||||
<i class="fa-solid fa-share-nodes"></i>
|
||||
</button>
|
||||
</nav>
|
||||
@if (Editable) {
|
||||
<button class="small circle small-elevate" @onclick="EditStatus">
|
||||
<i class="fa-solid fa-pencil"></i>
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
@Status.HtmlContent
|
||||
<nav class="no-margin">
|
||||
<a class="chip transparent-border">
|
||||
<i class="fa fa-clock"></i> @Status.RelativeTime
|
||||
</a>
|
||||
<a class="chip transparent-border" href="@Status.ExternalUrl" target="_blank">
|
||||
<i class="fa fa-message-dots"></i> Respond
|
||||
</a>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public Status status { get; set; }
|
||||
public Status Status { get; set; }
|
||||
[Parameter]
|
||||
public bool Editable { get; set; } = false;
|
||||
[Parameter]
|
||||
public EditStatusDialog? Dialog { get; set; }
|
||||
|
||||
private async Task EditStatus(EventArgs e) {
|
||||
Dialog.Status = Status;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
await JS.InvokeVoidAsync("ui", "#" + Dialog?.id);
|
||||
}
|
||||
|
||||
public async Task ShareClick(EventArgs e){
|
||||
await Share.Default.RequestAsync(new ShareTextRequest{
|
||||
Text = $"{status.Content}\n- from [@{status.Address}]({status.Url})",
|
||||
Text = $"{Status.Content}\n- from [@{Status.Address}]({Status.Url})",
|
||||
Title = "I saw this on status.lol",
|
||||
Subject = "I saw this on status.lol"
|
||||
});
|
||||
|
|
|
@ -1,24 +1,45 @@
|
|||
@inject IJSRuntime JS
|
||||
@implements IDisposable
|
||||
@inject IJSRuntime JS
|
||||
@inject State State
|
||||
|
||||
@if (Editable) {
|
||||
<EditStatusDialog @ref="Dialog" id="EditStatusModal"></EditStatusDialog>
|
||||
}
|
||||
|
||||
@if(statuses != null) foreach(Status status in statuses) {
|
||||
<StatusCard status="@status"></StatusCard>
|
||||
<StatusCard Status="@status" Editable="Editable" Dialog="Dialog"></StatusCard>
|
||||
}
|
||||
|
||||
<LoadingCard id="statusLoading" icon="fa-solid fa-message-smile"></LoadingCard>
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public Func<Task<List<Status>?>> StatusFunc { get; set; }
|
||||
public Func<bool, Task<List<Status>?>> StatusFunc { get; set; }
|
||||
[Parameter]
|
||||
public bool Editable { get; set; } = false;
|
||||
|
||||
public EditStatusDialog? Dialog { get; set; }
|
||||
|
||||
private List<Status>? statuses;
|
||||
|
||||
protected override async Task OnInitializedAsync() {
|
||||
await base.OnInitializedAsync();
|
||||
if (statuses == null || statuses.Count == 0) statuses = await StatusFunc();
|
||||
if (statuses == null || statuses.Count == 0) statuses = await StatusFunc(false);
|
||||
State.PropertyChanged += StateChanged;
|
||||
State.CanRefresh = true;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
await JS.InvokeVoidAsync("removeElementById", "statusLoading");
|
||||
}
|
||||
|
||||
private async void StateChanged(object? sender, PropertyChangedEventArgs e) {
|
||||
if (e.PropertyName == nameof(State.IsRefreshing) && State.IsRefreshing) {
|
||||
statuses = await StatusFunc(true);
|
||||
State.IsRefreshing = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
State.PropertyChanged -= StateChanged;
|
||||
State.CanRefresh = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
@using System.Net.Http
|
||||
@using System.ComponentModel
|
||||
@using System.Net.Http
|
||||
@using System.Net.Http.Json
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
@using Microsoft.AspNetCore.Components.Routing
|
||||
|
|
|
@ -12,16 +12,18 @@ public partial class LoginWebViewPage : ContentPage
|
|||
private AuthenticationStateProvider AuthStateProvider { get; set; }
|
||||
private NavigatorService NavigatorService { get; set; }
|
||||
private IConfiguration Configuration { get; set; }
|
||||
private RestService api { get; set; }
|
||||
|
||||
private string? client_id;
|
||||
private string? client_secret;
|
||||
private string? redirect_uri;
|
||||
|
||||
public LoginWebViewPage(AuthenticationStateProvider authStateProvider, NavigatorService navigatorService, IConfiguration configuration)
|
||||
public LoginWebViewPage(AuthenticationStateProvider authStateProvider, NavigatorService navigatorService, IConfiguration configuration, RestService restService)
|
||||
{
|
||||
this.AuthStateProvider = authStateProvider;
|
||||
this.NavigatorService = navigatorService;
|
||||
this.Configuration = configuration;
|
||||
this.api = restService;
|
||||
InitializeComponent();
|
||||
client_id = configuration.GetValue<string>("client_id");
|
||||
client_secret = configuration.GetValue<string>("client_secret");
|
||||
|
@ -45,10 +47,8 @@ public partial class LoginWebViewPage : ContentPage
|
|||
var query = HttpUtility.ParseQueryString(uri.Query);
|
||||
string? code = query.Get("code");
|
||||
if (!string.IsNullOrEmpty(code)) {
|
||||
RestService api = new RestService();
|
||||
string? token = await api.OAuth(code, client_id, client_secret, redirect_uri);
|
||||
if (!string.IsNullOrEmpty(token)) {
|
||||
Debug.WriteLine($"Fuck yeah, a token! {token}");
|
||||
await ((CustomAuthenticationStateProvider)this.AuthStateProvider).Login(token);
|
||||
NavigatorService.NavigationManager.NavigateTo(NavigatorService.NavigationManager.Uri, forceLoad: true);
|
||||
await Shell.Current.GoToAsync("..");
|
||||
|
|
|
@ -16,10 +16,5 @@ namespace Neighbourhood.omg.lol {
|
|||
Shell.Current.GoToAsync(nameof(LoginWebViewPage));
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnAppearing() {
|
||||
base.OnAppearing();
|
||||
Debug.WriteLine("And now you're back. From outer space.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using Markdig;
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Neighbourhood.omg.lol.Models;
|
||||
|
@ -17,6 +18,7 @@ namespace Neighbourhood.omg.lol {
|
|||
builder.Services.AddTransient<LoginWebViewPage>();
|
||||
builder.Services.AddTransient<EphemeralWebPage>();
|
||||
|
||||
builder.Services.AddSingleton<RestService>();
|
||||
builder.Services.AddSingleton<State>();
|
||||
builder.Services.AddSingleton<NavigatorService>();
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace Neighbourhood.omg.lol.Models {
|
|||
public TimeData Updated { get; set; }
|
||||
|
||||
public string UpdatedRelative {
|
||||
get => State.RelativeTimeFromUnix(Convert.ToInt64(Updated.UnixEpochTime));
|
||||
get => Utilities.RelativeTimeFromUnix(Convert.ToInt64(Updated.UnixEpochTime));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
13
Models/PatchStatus.cs
Normal file
13
Models/PatchStatus.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Neighbourhood.omg.lol.Models {
|
||||
public class PatchStatus {
|
||||
public string Id { get; set; }
|
||||
public string Content { get; set; }
|
||||
public string? Emoji { get; set; }
|
||||
}
|
||||
}
|
13
Models/PatchStatusResponseData.cs
Normal file
13
Models/PatchStatusResponseData.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Neighbourhood.omg.lol.Models {
|
||||
public class PatchStatusResponseData : IOmgLolResponseData {
|
||||
public string Message { get; set; }
|
||||
public string Id { get; set; }
|
||||
public string Url { get; set; }
|
||||
}
|
||||
}
|
|
@ -17,7 +17,7 @@ namespace Neighbourhood.omg.lol.Models {
|
|||
public long Size { get; set; }
|
||||
public string Mime { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string DescriptionHtml { get => Description == null ? string.Empty : Markdown.ToHtml(Description); }
|
||||
public string DescriptionHtml { get => Description == null ? string.Empty : Utilities.MdToHtml(Description); }
|
||||
|
||||
[JsonPropertyName("exif")]
|
||||
public JsonElement ExifJson { get; set; }
|
||||
|
|
131
Models/State.cs
131
Models/State.cs
|
@ -1,32 +1,28 @@
|
|||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web.Virtualization;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.ComponentModel;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Neighbourhood.omg.lol.Models {
|
||||
public class State {
|
||||
|
||||
public Page CurrentPage { get; set; }
|
||||
public AccountResponseData? AccountInfo { get; set; }
|
||||
public AddressResponseList? AddressList { get; set; }
|
||||
|
||||
public string? Name { get => AccountInfo?.Name; }
|
||||
public string? Email { get => AccountInfo?.Email; }
|
||||
public IEnumerable<string>? AddressNames { get => AddressList?.Select(a => a.Address); }
|
||||
public AddressResponseData? SelectedAddress { get; set; }
|
||||
public string? SelectedAddressName { get => SelectedAddress?.Address; }
|
||||
|
||||
public class State : INotifyPropertyChanged {
|
||||
// Main data lists
|
||||
public List<Status>? Statuses { get; set; }
|
||||
public List<Pic>? Pics { get; set; }
|
||||
public List<NowData>? NowGarden { get; set; }
|
||||
public List<MarkupString>? EphemeralMessages { get; set; }
|
||||
|
||||
// Account data
|
||||
public AccountResponseData? AccountInfo { get; set; }
|
||||
public AddressResponseList? AddressList { get; set; }
|
||||
|
||||
public string? Name { get => AccountInfo?.Name; }
|
||||
public string? Email { get => AccountInfo?.Email; }
|
||||
public IEnumerable<string>? AddressNames { get => AddressList?.Select(a => a.Address); }
|
||||
|
||||
// Selected Address
|
||||
public AddressResponseData? SelectedAddress { get; set; }
|
||||
public string? SelectedAddressName { get => SelectedAddress?.Address; }
|
||||
|
||||
// data for selected address
|
||||
public List<Status>? CachedAddressStatuses { get; set; }
|
||||
public List<Pic>? CachedAddressPics { get; set; }
|
||||
public MarkupString? CachedAddressBio { get; set; }
|
||||
|
@ -43,8 +39,59 @@ namespace Neighbourhood.omg.lol.Models {
|
|||
}
|
||||
}
|
||||
|
||||
// share intent stuff
|
||||
public event EventHandler<EventArgs>? IntentReceived;
|
||||
private string? _shareString;
|
||||
public string? ShareString {
|
||||
get => _shareString;
|
||||
set {
|
||||
_shareString = value;
|
||||
IntentReceived?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
public string? ShareStringSubject { get; set; }
|
||||
|
||||
private string? _sharePhoto;
|
||||
public string? SharePhoto {
|
||||
get => _sharePhoto;
|
||||
set {
|
||||
_sharePhoto = value;
|
||||
IntentReceived?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
public long? SharePhotoSize { get; set; }
|
||||
public string? SharePhotoContentType { get; set; }
|
||||
public string? SharePhotoText { get; set; }
|
||||
|
||||
// refreshing
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
private bool _isRefreshing;
|
||||
public bool IsRefreshing {
|
||||
get => _isRefreshing;
|
||||
set {
|
||||
_isRefreshing = value;
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsRefreshing)));
|
||||
}
|
||||
}
|
||||
|
||||
private bool _canRefresh;
|
||||
public bool CanRefresh {
|
||||
get => _canRefresh;
|
||||
set {
|
||||
_canRefresh = value;
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CanRefresh)));
|
||||
}
|
||||
}
|
||||
|
||||
// api service
|
||||
private RestService api { get; set; }
|
||||
|
||||
public State(RestService restService) {
|
||||
api = restService;
|
||||
}
|
||||
|
||||
public async Task PopulateAccountDetails(string token) {
|
||||
RestService api = new RestService(token);
|
||||
api.AddToken(token);
|
||||
|
||||
string accountJson = Preferences.Default.Get("accountdetails", string.Empty);
|
||||
string addressJson = Preferences.Default.Get("accountaddresses", string.Empty);
|
||||
|
@ -78,19 +125,18 @@ namespace Neighbourhood.omg.lol.Models {
|
|||
AccountInfo = null;
|
||||
AddressList = null;
|
||||
SelectedAddress = null;
|
||||
api.RemoveToken();
|
||||
}
|
||||
|
||||
public async Task<MarkupString?> GetBio(string address, bool forceRefresh = false) {
|
||||
CachedAddress = address;
|
||||
if (forceRefresh || CachedAddressBio == null) {
|
||||
RestService api = new RestService();
|
||||
CachedAddressBio = await api.StatuslogBio(address);
|
||||
}
|
||||
return CachedAddressBio;
|
||||
}
|
||||
|
||||
public async Task<List<MarkupString>?> GetEphemeralMessages(bool forceRefresh = false) {
|
||||
RestService api = new RestService();
|
||||
if(forceRefresh || this.EphemeralMessages == null || this.EphemeralMessages.Count == 0) {
|
||||
this.EphemeralMessages = await api.Ephemeral();
|
||||
}
|
||||
|
@ -98,7 +144,6 @@ namespace Neighbourhood.omg.lol.Models {
|
|||
}
|
||||
|
||||
public async Task<List<Status>?> GetStatuses(bool forceRefresh = false) {
|
||||
RestService api = new RestService();
|
||||
if (forceRefresh || this.Statuses == null || this.Statuses.Count == 0) {
|
||||
this.Statuses = await api.StatuslogLatest();
|
||||
}
|
||||
|
@ -107,7 +152,6 @@ namespace Neighbourhood.omg.lol.Models {
|
|||
|
||||
public async Task<List<Status>?> GetStatuses(string address, bool forceRefresh = false) {
|
||||
this.CachedAddress = address;
|
||||
RestService api = new RestService();
|
||||
if (forceRefresh || this.CachedAddressStatuses == null || this.CachedAddressStatuses.Count == 0) {
|
||||
this.CachedAddressStatuses = await api.Statuslog(address);
|
||||
}
|
||||
|
@ -115,7 +159,6 @@ namespace Neighbourhood.omg.lol.Models {
|
|||
}
|
||||
|
||||
public async Task<List<NowData>?> GetNowGarden(bool forceRefresh = false) {
|
||||
RestService api = new RestService();
|
||||
if (forceRefresh || this.NowGarden == null || this.NowGarden.Count == 0) {
|
||||
this.NowGarden = await api.NowGarden();
|
||||
}
|
||||
|
@ -124,7 +167,6 @@ namespace Neighbourhood.omg.lol.Models {
|
|||
|
||||
public async Task<List<Pic>?> GetPics(bool forceRefresh = false) {
|
||||
if(forceRefresh || this.Pics == null || this.Pics.Count == 0) {
|
||||
RestService api = new RestService();
|
||||
this.Pics = await api.SomePics();
|
||||
}
|
||||
return this.Pics;
|
||||
|
@ -133,49 +175,14 @@ namespace Neighbourhood.omg.lol.Models {
|
|||
public async Task<List<Pic>?> GetPics(string address, bool forceRefresh = false) {
|
||||
CachedAddress = address;
|
||||
if (forceRefresh || this.CachedAddressPics == null || this.CachedAddressPics.Count == 0) {
|
||||
RestService api = new RestService();
|
||||
CachedAddressPics = (await api.SomePics(address)) ?? new List<Pic>();
|
||||
}
|
||||
return CachedAddressPics;
|
||||
}
|
||||
|
||||
public async Task<long> FileSize(FileResult file) {
|
||||
using var fileStream = await file.OpenReadAsync();
|
||||
return fileStream.Length;
|
||||
}
|
||||
|
||||
public async Task<string> Base64FromFile(FileResult file) {
|
||||
using var memoryStream = new MemoryStream();
|
||||
using var fileStream = await file.OpenReadAsync();
|
||||
await fileStream.CopyToAsync(memoryStream);
|
||||
byte[] bytes = memoryStream.ToArray();
|
||||
return Convert.ToBase64String(bytes);
|
||||
}
|
||||
|
||||
public async Task RefreshStatuses() => await GetStatuses(forceRefresh: true);
|
||||
public async Task RefreshPics() => await GetPics(forceRefresh: true);
|
||||
public async Task RefreshNow() => await GetNowGarden(forceRefresh: true);
|
||||
|
||||
public static string RelativeTimeFromUnix(long unix) {
|
||||
DateTimeOffset createdTime = DateTimeOffset.UnixEpoch.AddSeconds(unix);
|
||||
TimeSpan offset = DateTimeOffset.UtcNow - createdTime;
|
||||
|
||||
var offsetString = string.Empty;
|
||||
if (offset.TotalDays >= 1) offsetString = $"{Math.Floor(offset.TotalDays)} days ago";
|
||||
else if (offset.TotalHours >= 1) offsetString = $"{Math.Floor(offset.TotalHours)} hours, {offset.Minutes} minutes ago";
|
||||
else if (offset.TotalMinutes >= 1) offsetString = $"{Math.Floor(offset.TotalMinutes)} minutes ago";
|
||||
else offsetString = $"{Math.Floor(offset.TotalSeconds)} seconds ago";
|
||||
|
||||
return offsetString;
|
||||
}
|
||||
}
|
||||
|
||||
public enum Page {
|
||||
None = 0,
|
||||
Status,
|
||||
Pics,
|
||||
Ephemeral,
|
||||
NowGarden,
|
||||
Other
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ namespace Neighbourhood.omg.lol.Models {
|
|||
public string RelativeTime { get; set; }
|
||||
public string Emoji { get; set; }
|
||||
public string Background { get; set; }
|
||||
public string BackgroundColor { get => Background; set => Background = "#" + value; }
|
||||
public string Content { get; set; }
|
||||
public string RenderedMarkdown { get; set; }
|
||||
public string ExternalUrl { get; set; }
|
||||
|
@ -19,11 +20,8 @@ namespace Neighbourhood.omg.lol.Models {
|
|||
}
|
||||
}
|
||||
|
||||
public MarkupString HtmlContent {
|
||||
get {
|
||||
if(!string.IsNullOrEmpty(RenderedMarkdown)) return (MarkupString)RenderedMarkdown;
|
||||
else return (MarkupString)Markdown.ToHtml(Content);
|
||||
}
|
||||
public MarkupString HtmlContent {
|
||||
get => Utilities.MdToHtmlMarkup(Content);
|
||||
}
|
||||
|
||||
public string Url {
|
||||
|
|
51
Models/Utilities.cs
Normal file
51
Models/Utilities.cs
Normal file
|
@ -0,0 +1,51 @@
|
|||
using Markdig;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Neighbourhood.omg.lol {
|
||||
public static class Utilities {
|
||||
|
||||
private static MarkdownPipeline markdownPipeline { get; }
|
||||
= new MarkdownPipelineBuilder().UseAutoLinks().Build();
|
||||
|
||||
public static string MdToHtml(string markdown) =>
|
||||
Markdown.ToHtml(markdown, markdownPipeline);
|
||||
|
||||
public static MarkupString MdToHtmlMarkup(string markdown) =>
|
||||
(MarkupString)MdToHtml(markdown);
|
||||
|
||||
public static async Task<long> FileSize(FileResult file) {
|
||||
using var fileStream = await file.OpenReadAsync();
|
||||
return fileStream.Length;
|
||||
}
|
||||
|
||||
public static async Task<string> Base64FromFile(FileResult file) {
|
||||
using var memoryStream = new MemoryStream();
|
||||
using var fileStream = await file.OpenReadAsync();
|
||||
await fileStream.CopyToAsync(memoryStream);
|
||||
byte[] bytes = memoryStream.ToArray();
|
||||
return Convert.ToBase64String(bytes);
|
||||
}
|
||||
|
||||
public static string RelativeTimeFromUnix(long unix) {
|
||||
DateTimeOffset createdTime = DateTimeOffset.UnixEpoch.AddSeconds(unix);
|
||||
TimeSpan offset = DateTimeOffset.UtcNow - createdTime;
|
||||
|
||||
var offsetString = string.Empty;
|
||||
if (Math.Floor(offset.TotalDays) == 1) offsetString = $"{Math.Floor(offset.TotalDays)} day ago";
|
||||
else if (offset.TotalDays > 1) offsetString = $"{Math.Floor(offset.TotalDays)} days ago";
|
||||
else if (Math.Floor(offset.TotalHours) == 1) offsetString = $"{Math.Floor(offset.TotalHours)} hour ago";
|
||||
else if (offset.TotalHours > 1) offsetString = $"{Math.Floor(offset.TotalHours)} hours ago";
|
||||
else if (Math.Floor(offset.TotalMinutes) == 1) offsetString = $"{Math.Floor(offset.TotalMinutes)} minute ago";
|
||||
else if (offset.TotalMinutes > 1) offsetString = $"{Math.Floor(offset.TotalMinutes)} minutes ago";
|
||||
else if (Math.Floor(offset.TotalSeconds) == 1) offsetString = $"{Math.Floor(offset.TotalSeconds)} second ago";
|
||||
else offsetString = $"{Math.Floor(offset.TotalSeconds)} seconds ago";
|
||||
|
||||
return offsetString;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -77,7 +77,7 @@
|
|||
<MauiIcon Include="Resources\AppIcon\icon_background.svg" ForegroundFile="Resources\AppIcon\icon_foreground.svg" Color="#f3eb76" BaseSize="1024,1024" />
|
||||
|
||||
<!-- Splash Screen -->
|
||||
<MauiSplashScreen Include="Resources\Splash\splash.svg" Color="#512BD4" BaseSize="128,128" />
|
||||
<MauiSplashScreen Include="Resources\Splash\splash.svg" Color="#343a40" BaseSize="128,128" />
|
||||
|
||||
<!-- Images -->
|
||||
<MauiImage Include="Resources\Images\*" />
|
||||
|
@ -90,6 +90,111 @@
|
|||
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<MauiFont Remove="Resources\Fonts\fa-brands-400.ttf" />
|
||||
<MauiFont Remove="Resources\Fonts\fa-brands-400.woff2" />
|
||||
<MauiFont Remove="Resources\Fonts\fa-duotone-900.ttf" />
|
||||
<MauiFont Remove="Resources\Fonts\fa-duotone-900.woff2" />
|
||||
<MauiFont Remove="Resources\Fonts\fa-light-300.ttf" />
|
||||
<MauiFont Remove="Resources\Fonts\fa-light-300.woff2" />
|
||||
<MauiFont Remove="Resources\Fonts\fa-regular-400.ttf" />
|
||||
<MauiFont Remove="Resources\Fonts\fa-regular-400.woff2" />
|
||||
<MauiFont Remove="Resources\Fonts\fa-solid-900.ttf" />
|
||||
<MauiFont Remove="Resources\Fonts\fa-solid-900.woff2" />
|
||||
<MauiFont Remove="Resources\Fonts\fa-thin-100.ttf" />
|
||||
<MauiFont Remove="Resources\Fonts\fa-thin-100.woff2" />
|
||||
<MauiFont Remove="Resources\Fonts\fa-v4compatibility.ttf" />
|
||||
<MauiFont Remove="Resources\Fonts\fa-v4compatibility.woff2" />
|
||||
<MauiFont Remove="Resources\Fonts\omg.lol-icons.woff2" />
|
||||
<MauiFont Remove="Resources\Fonts\seguiemj.ttf" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Resources\Fonts\fa-brands-400.ttf" />
|
||||
<None Remove="Resources\Fonts\fa-brands-400.woff2" />
|
||||
<None Remove="Resources\Fonts\fa-duotone-900.ttf" />
|
||||
<None Remove="Resources\Fonts\fa-duotone-900.woff2" />
|
||||
<None Remove="Resources\Fonts\fa-light-300.ttf" />
|
||||
<None Remove="Resources\Fonts\fa-light-300.woff2" />
|
||||
<None Remove="Resources\Fonts\fa-regular-400.ttf" />
|
||||
<None Remove="Resources\Fonts\fa-regular-400.woff2" />
|
||||
<None Remove="Resources\Fonts\fa-solid-900.ttf" />
|
||||
<None Remove="Resources\Fonts\fa-solid-900.woff2" />
|
||||
<None Remove="Resources\Fonts\fa-thin-100.ttf" />
|
||||
<None Remove="Resources\Fonts\fa-thin-100.woff2" />
|
||||
<None Remove="Resources\Fonts\fa-v4compatibility.ttf" />
|
||||
<None Remove="Resources\Fonts\fa-v4compatibility.woff2" />
|
||||
<None Remove="Resources\Fonts\omg.lol-icons.woff2" />
|
||||
<None Remove="Resources\Fonts\seguiemj.ttf" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="Resources\Fonts\fa-brands-400.ttf">
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
<Content Include="Resources\Fonts\fa-brands-400.woff2">
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
<Content Include="Resources\Fonts\fa-duotone-900.ttf">
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
<Content Include="Resources\Fonts\fa-duotone-900.woff2">
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
<Content Include="Resources\Fonts\fa-light-300.ttf">
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
<Content Include="Resources\Fonts\fa-light-300.woff2">
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
<Content Include="Resources\Fonts\fa-regular-400.ttf">
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
<Content Include="Resources\Fonts\fa-regular-400.woff2">
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
<Content Include="Resources\Fonts\fa-solid-900.ttf">
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
<Content Include="Resources\Fonts\fa-solid-900.woff2">
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
<Content Include="Resources\Fonts\fa-thin-100.ttf">
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
<Content Include="Resources\Fonts\fa-thin-100.woff2">
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
<Content Include="Resources\Fonts\fa-v4compatibility.ttf">
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
<Content Include="Resources\Fonts\fa-v4compatibility.woff2">
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
<Content Include="Resources\Fonts\omg.lol-icons.woff2">
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
<Content Include="Resources\Fonts\seguiemj.ttf">
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
||||
<PackageReference Include="Markdig" Version="0.37.0" />
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<application android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round" android:supportsRtl="true"></application>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="au.death.lol.omg.neighbourhood" android:versionCode="1" android:versionName="1.0.0">
|
||||
<application android:allowBackup="true" android:icon="@mipmap/icon_background" android:supportsRtl="true" android:label="Neighbourhood.omg.lol"></application>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
</manifest>
|
|
@ -1,9 +1,62 @@
|
|||
using Android.App;
|
||||
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.Content.PM;
|
||||
using Android.Net;
|
||||
using Android.OS;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Neighbourhood.omg.lol.Models;
|
||||
|
||||
namespace Neighbourhood.omg.lol {
|
||||
[Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
|
||||
[Activity(Theme = "@style/Maui.SplashTheme", LaunchMode = LaunchMode.SingleTop, MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
|
||||
[IntentFilter([Intent.ActionSend], Categories = [Intent.CategoryDefault], DataMimeType = "text/plain")]
|
||||
[IntentFilter([Intent.ActionSend], Categories = [Intent.CategoryDefault], DataMimeType = "*/*")]
|
||||
public class MainActivity : MauiAppCompatActivity {
|
||||
|
||||
protected override void OnCreate(Bundle savedInstanceState) {
|
||||
base.OnCreate(savedInstanceState);
|
||||
|
||||
// In case the app was opened (on first load) with an `ActionView` intent
|
||||
OnNewIntent(this.Intent);
|
||||
}
|
||||
|
||||
|
||||
protected override void OnNewIntent(Intent? intent) {
|
||||
base.OnNewIntent(intent);
|
||||
if (intent != null && intent.Type != null) {
|
||||
if (intent.Type.StartsWith("text/")) //string
|
||||
{
|
||||
string? subject = intent.GetStringExtra(Intent.ExtraSubject);
|
||||
string? shareString = intent.GetStringExtra(Intent.ExtraText);
|
||||
if (!string.IsNullOrWhiteSpace(shareString)) {
|
||||
State state = IPlatformApplication.Current!.Services.GetService<State>()!;
|
||||
state.ShareStringSubject = subject;
|
||||
state.ShareString = shareString;
|
||||
}
|
||||
}
|
||||
else if (intent.Type.StartsWith("image/")) //image
|
||||
{
|
||||
string? shareString = intent.GetStringExtra(Intent.ExtraText);
|
||||
var extra = intent.GetParcelableExtra(Intent.ExtraStream);
|
||||
if (extra is Android.Net.Uri) {
|
||||
Stream? stream = ContentResolver?.OpenInputStream(extra as Android.Net.Uri);
|
||||
byte[] bytes = new byte[stream?.Length ?? 0];
|
||||
stream?.Read(bytes, 0, bytes.Length);
|
||||
string base64String = Convert.ToBase64String(bytes);
|
||||
if (!string.IsNullOrWhiteSpace(base64String)) {
|
||||
State state = IPlatformApplication.Current!.Services.GetService<State>()!;
|
||||
state.SharePhotoContentType = intent.Type;
|
||||
state.SharePhotoSize = bytes.Length;
|
||||
state.SharePhotoText = shareString;
|
||||
state.SharePhoto = base64String;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (intent.Type.Equals(Intent.ActionSendMultiple)) //Multiple file
|
||||
{
|
||||
var uriList = intent.GetParcelableArrayListExtra(Intent.ExtraStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#512BD4</color>
|
||||
<color name="colorPrimaryDark">#2B0B98</color>
|
||||
<color name="colorPrimary">#343a40</color>
|
||||
<color name="colorPrimaryDark">#343a40</color>
|
||||
<color name="colorAccent">#2B0B98</color>
|
||||
</resources>
|
|
@ -8,13 +8,13 @@
|
|||
<filter filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB" id="filter_1">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix" />
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 128 0" />
|
||||
<feOffset dx="0" dy="40" />
|
||||
<feGaussianBlur stdDeviation="20" />
|
||||
<feOffset dx="0" dy="27" />
|
||||
<feGaussianBlur stdDeviation="13.5" />
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2509804 0" />
|
||||
<feBlend mode="normal" in2="BackgroundImageFix" result="effect0_dropShadow" />
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 128 0" />
|
||||
<feOffset dx="0" dy="15" />
|
||||
<feGaussianBlur stdDeviation="15" />
|
||||
<feOffset dx="0" dy="10" />
|
||||
<feGaussianBlur stdDeviation="10.5" />
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.29803923 0" />
|
||||
<feBlend mode="normal" in2="effect0_dropShadow" result="effect1_dropShadow" />
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape" />
|
||||
|
@ -22,15 +22,15 @@
|
|||
</defs>
|
||||
<g id="neighbourhood-purple">
|
||||
<rect x="0" y="0" width="100%" height="100%" fill="url(#grad1)"/>
|
||||
<path d="M864.362 79.8798L864.362 134.95M662.099 55.0981L975.99 200.559M343.467 201.034L657.357 55.5735M276.97 55.0979L465.304 142.375M47 159.732L273.001 55" id="Shape" fill="none" fill-rule="evenodd" stroke="#8C53E7" stroke-width="44" stroke-linecap="round" stroke-linejoin="round" filter="url(#filter_1)" />
|
||||
<g filter="url(#filter_1)">
|
||||
<g id="Group" transform="translate(72.13778 248.08119)">
|
||||
<path d="M439.862 703.781C372.32 703.781 304.78 678.013 253.244 626.482L77.3003 450.537C-25.7668 347.47 -25.7668 180.368 77.3003 77.3012C176.882 -22.2802 336.238 -25.6497 439.862 67.1961C543.49 -25.6464 702.847 -22.277 802.425 77.3012C905.492 180.368 905.492 347.47 802.425 450.537L626.48 626.482C574.949 678.013 507.406 703.781 439.862 703.781" id="Path" fill="#B776FC" stroke="none" />
|
||||
<path d="M367.283 305.824C400.495 360.018 479.232 360.018 512.441 305.824" id="Path" fill="none" stroke="#22184C" stroke-width="33" stroke-linecap="round" />
|
||||
<path d="M481.297 222.748C481.297 205.5 495.28 191.518 512.527 191.518C529.776 191.518 543.758 205.5 543.758 222.748C543.758 239.996 529.776 253.978 512.527 253.978C495.28 253.978 481.297 239.996 481.297 222.748Z" id="Oval" fill="#22184C" fill-rule="evenodd" stroke="none" />
|
||||
<path d="M335.791 222.748C335.791 205.5 349.773 191.518 367.021 191.518C384.269 191.518 398.251 205.5 398.251 222.748C398.251 239.996 384.269 253.978 367.021 253.978C349.773 253.978 335.791 239.996 335.791 222.748Z" id="Oval" fill="#22184C" fill-rule="evenodd" stroke="none" />
|
||||
<path d="M107.502 285.032C107.502 227.507 154.136 180.873 211.662 180.873C269.187 180.873 315.821 227.507 315.821 285.032C315.821 342.558 269.187 389.192 211.662 389.192C154.136 389.192 107.502 342.558 107.502 285.032Z" id="Oval" fill="#8C53E7" fill-rule="evenodd" stroke="none" />
|
||||
<path d="M563.903 285.032C563.903 227.507 610.537 180.873 668.063 180.873C725.589 180.873 772.222 227.507 772.222 285.032C772.222 342.558 725.589 389.192 668.063 389.192C610.537 389.192 563.903 342.558 563.903 285.032Z" id="Oval" fill="#8C53E7" fill-rule="evenodd" stroke="none" />
|
||||
<path d="M750.419 224.839L750.419 262.111M613.471 208.066L826 306.515M397.732 306.837L610.26 208.388M352.708 208.066L480.225 267.135M197 278.883L350.021 208" id="Shape" fill="none" fill-rule="evenodd" stroke="#8C53E7" stroke-width="29" stroke-linecap="round" stroke-linejoin="round" filter="url(#filter_1)" clip-path="url(#clip_1)" />
|
||||
<g filter="url(#filter_1)" clip-path="url(#clip_1)">
|
||||
<g id="Group" transform="translate(214.02026 338.67798)">
|
||||
<path d="M297.822 476.322C252.091 476.322 206.361 458.882 171.467 424.006L52.3385 304.925C-17.4462 235.169 -17.4462 122.074 52.3385 52.3178C119.763 -15.0793 227.66 -17.3598 297.822 45.4785C367.986 -17.3576 475.883 -15.0771 543.306 52.3178C613.09 122.074 613.09 235.169 543.306 304.925L424.177 424.006C389.286 458.882 343.554 476.322 297.822 476.322" id="Path" fill="#B776FC" stroke="none" />
|
||||
<path d="M248.68 206.983C271.167 243.662 324.478 243.662 346.964 206.983" id="Path" fill="none" stroke="#22184C" stroke-width="22" stroke-linecap="round" />
|
||||
<path d="M325.877 150.757C325.877 139.083 335.344 129.62 347.022 129.62C358.7 129.62 368.167 139.083 368.167 150.757C368.167 162.43 358.7 171.893 347.022 171.893C335.344 171.893 325.877 162.43 325.877 150.757Z" id="Oval" fill="#22184C" fill-rule="evenodd" stroke="none" />
|
||||
<path d="M227.357 150.757C227.357 139.083 236.824 129.62 248.502 129.62C260.181 129.62 269.648 139.083 269.648 150.757C269.648 162.43 260.181 171.893 248.502 171.893C236.824 171.893 227.357 162.43 227.357 150.757Z" id="Oval" fill="#22184C" fill-rule="evenodd" stroke="none" />
|
||||
<path d="M72.7875 192.911C72.7875 153.977 104.362 122.416 143.312 122.416C182.261 122.416 213.836 153.977 213.836 192.911C213.836 231.845 182.261 263.407 143.312 263.407C104.362 263.407 72.7875 231.845 72.7875 192.911Z" id="Oval" fill="#8C53E7" fill-rule="evenodd" stroke="none" />
|
||||
<path d="M381.808 192.911C381.808 153.977 413.382 122.416 452.332 122.416C491.281 122.416 522.856 153.977 522.856 192.911C522.856 231.845 491.281 263.407 452.332 263.407C413.382 263.407 381.808 231.845 381.808 192.911Z" id="Oval" fill="#8C53E7" fill-rule="evenodd" stroke="none" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
|
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
|
@ -1,36 +1,31 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg width="1024px" height="1024px" viewBox="0 0 1024 1024" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<linearGradient gradientUnits="objectBoundingBox" x1="0.5" y1="0" x2="0.5" y2="1" id="gradient_1">
|
||||
<stop offset="0%" stop-color="#F8F081" />
|
||||
<stop offset="100%" stop-color="#E1DA51" />
|
||||
</linearGradient>
|
||||
<filter filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB" id="filter_1">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix" />
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 128 0" />
|
||||
<feOffset dx="0" dy="40" />
|
||||
<feGaussianBlur stdDeviation="20" />
|
||||
<feOffset dx="0" dy="27" />
|
||||
<feGaussianBlur stdDeviation="13.5" />
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2509804 0" />
|
||||
<feBlend mode="normal" in2="BackgroundImageFix" result="effect0_dropShadow" />
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 128 0" />
|
||||
<feOffset dx="0" dy="15" />
|
||||
<feGaussianBlur stdDeviation="15" />
|
||||
<feOffset dx="0" dy="10" />
|
||||
<feGaussianBlur stdDeviation="10.5" />
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.29803923 0" />
|
||||
<feBlend mode="normal" in2="effect0_dropShadow" result="effect1_dropShadow" />
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape" />
|
||||
</filter>
|
||||
</defs>
|
||||
<g id="neighbourhood-purple">
|
||||
<path d="M1024 2056L1024 2056L1024 3080L0 3080L0 2056L1024 2056Z" id="neighbourhood-purple" fill="url(#gradient_1)" stroke="none" />
|
||||
<path d="M864.362 79.8798L864.362 134.95M662.099 55.0981L975.99 200.559M343.467 201.034L657.357 55.5735M276.97 55.0979L465.304 142.375M47 159.732L273.001 55" id="Shape" fill="none" fill-rule="evenodd" stroke="#8C53E7" stroke-width="44" stroke-linecap="round" stroke-linejoin="round" filter="url(#filter_1)" />
|
||||
<g filter="url(#filter_1)">
|
||||
<g id="Group" transform="translate(72.13778 248.08119)">
|
||||
<path d="M439.862 703.781C372.32 703.781 304.78 678.013 253.244 626.482L77.3003 450.537C-25.7668 347.47 -25.7668 180.368 77.3003 77.3012C176.882 -22.2802 336.238 -25.6497 439.862 67.1961C543.49 -25.6464 702.847 -22.277 802.425 77.3012C905.492 180.368 905.492 347.47 802.425 450.537L626.48 626.482C574.949 678.013 507.406 703.781 439.862 703.781" id="Path" fill="#B776FC" stroke="none" />
|
||||
<path d="M367.283 305.824C400.495 360.018 479.232 360.018 512.441 305.824" id="Path" fill="none" stroke="#22184C" stroke-width="33" stroke-linecap="round" />
|
||||
<path d="M481.297 222.748C481.297 205.5 495.28 191.518 512.527 191.518C529.776 191.518 543.758 205.5 543.758 222.748C543.758 239.996 529.776 253.978 512.527 253.978C495.28 253.978 481.297 239.996 481.297 222.748Z" id="Oval" fill="#22184C" fill-rule="evenodd" stroke="none" />
|
||||
<path d="M335.791 222.748C335.791 205.5 349.773 191.518 367.021 191.518C384.269 191.518 398.251 205.5 398.251 222.748C398.251 239.996 384.269 253.978 367.021 253.978C349.773 253.978 335.791 239.996 335.791 222.748Z" id="Oval" fill="#22184C" fill-rule="evenodd" stroke="none" />
|
||||
<path d="M107.502 285.032C107.502 227.507 154.136 180.873 211.662 180.873C269.187 180.873 315.821 227.507 315.821 285.032C315.821 342.558 269.187 389.192 211.662 389.192C154.136 389.192 107.502 342.558 107.502 285.032Z" id="Oval" fill="#8C53E7" fill-rule="evenodd" stroke="none" />
|
||||
<path d="M563.903 285.032C563.903 227.507 610.537 180.873 668.063 180.873C725.589 180.873 772.222 227.507 772.222 285.032C772.222 342.558 725.589 389.192 668.063 389.192C610.537 389.192 563.903 342.558 563.903 285.032Z" id="Oval" fill="#8C53E7" fill-rule="evenodd" stroke="none" />
|
||||
<path d="M750.419 224.839L750.419 262.111M613.471 208.066L826 306.515M397.732 306.837L610.26 208.388M352.708 208.066L480.225 267.135M197 278.883L350.021 208" id="Shape" fill="none" fill-rule="evenodd" stroke="#8C53E7" stroke-width="29" stroke-linecap="round" stroke-linejoin="round" filter="url(#filter_1)" clip-path="url(#clip_1)" />
|
||||
<g filter="url(#filter_1)" clip-path="url(#clip_1)">
|
||||
<g id="Group" transform="translate(214.02026 338.67798)">
|
||||
<path d="M297.822 476.322C252.091 476.322 206.361 458.882 171.467 424.006L52.3385 304.925C-17.4462 235.169 -17.4462 122.074 52.3385 52.3178C119.763 -15.0793 227.66 -17.3598 297.822 45.4785C367.986 -17.3576 475.883 -15.0771 543.306 52.3178C613.09 122.074 613.09 235.169 543.306 304.925L424.177 424.006C389.286 458.882 343.554 476.322 297.822 476.322" id="Path" fill="#B776FC" stroke="none" />
|
||||
<path d="M248.68 206.983C271.167 243.662 324.478 243.662 346.964 206.983" id="Path" fill="none" stroke="#22184C" stroke-width="22" stroke-linecap="round" />
|
||||
<path d="M325.877 150.757C325.877 139.083 335.344 129.62 347.022 129.62C358.7 129.62 368.167 139.083 368.167 150.757C368.167 162.43 358.7 171.893 347.022 171.893C335.344 171.893 325.877 162.43 325.877 150.757Z" id="Oval" fill="#22184C" fill-rule="evenodd" stroke="none" />
|
||||
<path d="M227.357 150.757C227.357 139.083 236.824 129.62 248.502 129.62C260.181 129.62 269.648 139.083 269.648 150.757C269.648 162.43 260.181 171.893 248.502 171.893C236.824 171.893 227.357 162.43 227.357 150.757Z" id="Oval" fill="#22184C" fill-rule="evenodd" stroke="none" />
|
||||
<path d="M72.7875 192.911C72.7875 153.977 104.362 122.416 143.312 122.416C182.261 122.416 213.836 153.977 213.836 192.911C213.836 231.845 182.261 263.407 143.312 263.407C104.362 263.407 72.7875 231.845 72.7875 192.911Z" id="Oval" fill="#8C53E7" fill-rule="evenodd" stroke="none" />
|
||||
<path d="M381.808 192.911C381.808 153.977 413.382 122.416 452.332 122.416C491.281 122.416 522.856 153.977 522.856 192.911C522.856 231.845 491.281 263.407 452.332 263.407C413.382 263.407 381.808 231.845 381.808 192.911Z" id="Oval" fill="#8C53E7" fill-rule="evenodd" stroke="none" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
|
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.4 KiB |
BIN
Resources/Fonts/fa-brands-400.ttf
Normal file
BIN
Resources/Fonts/fa-brands-400.ttf
Normal file
Binary file not shown.
BIN
Resources/Fonts/fa-brands-400.woff2
Normal file
BIN
Resources/Fonts/fa-brands-400.woff2
Normal file
Binary file not shown.
BIN
Resources/Fonts/fa-duotone-900.ttf
Normal file
BIN
Resources/Fonts/fa-duotone-900.ttf
Normal file
Binary file not shown.
BIN
Resources/Fonts/fa-duotone-900.woff2
Normal file
BIN
Resources/Fonts/fa-duotone-900.woff2
Normal file
Binary file not shown.
BIN
Resources/Fonts/fa-light-300.ttf
Normal file
BIN
Resources/Fonts/fa-light-300.ttf
Normal file
Binary file not shown.
BIN
Resources/Fonts/fa-light-300.woff2
Normal file
BIN
Resources/Fonts/fa-light-300.woff2
Normal file
Binary file not shown.
BIN
Resources/Fonts/fa-regular-400.ttf
Normal file
BIN
Resources/Fonts/fa-regular-400.ttf
Normal file
Binary file not shown.
BIN
Resources/Fonts/fa-regular-400.woff2
Normal file
BIN
Resources/Fonts/fa-regular-400.woff2
Normal file
Binary file not shown.
BIN
Resources/Fonts/fa-solid-900.ttf
Normal file
BIN
Resources/Fonts/fa-solid-900.ttf
Normal file
Binary file not shown.
BIN
Resources/Fonts/fa-solid-900.woff2
Normal file
BIN
Resources/Fonts/fa-solid-900.woff2
Normal file
Binary file not shown.
BIN
Resources/Fonts/fa-thin-100.ttf
Normal file
BIN
Resources/Fonts/fa-thin-100.ttf
Normal file
Binary file not shown.
BIN
Resources/Fonts/fa-thin-100.woff2
Normal file
BIN
Resources/Fonts/fa-thin-100.woff2
Normal file
Binary file not shown.
BIN
Resources/Fonts/fa-v4compatibility.ttf
Normal file
BIN
Resources/Fonts/fa-v4compatibility.ttf
Normal file
Binary file not shown.
BIN
Resources/Fonts/fa-v4compatibility.woff2
Normal file
BIN
Resources/Fonts/fa-v4compatibility.woff2
Normal file
Binary file not shown.
BIN
Resources/Fonts/omg.lol-icons.woff2
Normal file
BIN
Resources/Fonts/omg.lol-icons.woff2
Normal file
Binary file not shown.
BIN
Resources/Fonts/seguiemj.ttf
Normal file
BIN
Resources/Fonts/seguiemj.ttf
Normal file
Binary file not shown.
|
@ -1,8 +1,32 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="456" height="456" viewBox="0 0 456 456" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<path d="m 105.50037,281.60863 c -2.70293,0 -5.00091,-0.90042 -6.893127,-2.70209 -1.892214,-1.84778 -2.837901,-4.04181 -2.837901,-6.58209 0,-2.58722 0.945687,-4.80389 2.837901,-6.65167 1.892217,-1.84778 4.190197,-2.77167 6.893127,-2.77167 2.74819,0 5.06798,0.92389 6.96019,2.77167 1.93749,1.84778 2.90581,4.06445 2.90581,6.65167 0,2.54028 -0.96832,4.73431 -2.90581,6.58209 -1.89221,1.80167 -4.212,2.70209 -6.96019,2.70209 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
|
||||
<path d="M 213.56111,280.08446 H 195.99044 L 149.69953,207.0544 c -1.17121,-1.84778 -2.14037,-3.76515 -2.90581,-5.75126 h -0.40578 c 0.36051,2.12528 0.54076,6.67515 0.54076,13.6496 v 65.13172 h -15.54349 v -99.36009 h 18.71925 l 44.7374,71.29798 c 1.89222,2.95695 3.1087,4.98917 3.64945,6.09751 h 0.26996 c -0.45021,-2.6325 -0.67573,-7.09015 -0.67573,-13.37293 v -64.02256 h 15.47557 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
|
||||
<path d="m 289.25134,280.08446 h -54.40052 v -99.36009 h 52.23835 v 13.99669 h -36.15411 v 28.13085 h 33.31621 v 13.9271 h -33.31621 v 29.37835 h 38.31628 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
|
||||
<path d="M 366.56466,194.72106 H 338.7222 v 85.3634 h -16.08423 v -85.3634 h -27.77455 v -13.99669 h 71.70124 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg width="1024px" height="1024px" viewBox="0 0 1024 1024" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<filter filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB" id="filter_1">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix" />
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 128 0" />
|
||||
<feOffset dx="0" dy="27" />
|
||||
<feGaussianBlur stdDeviation="13.5" />
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2509804 0" />
|
||||
<feBlend mode="normal" in2="BackgroundImageFix" result="effect0_dropShadow" />
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 128 0" />
|
||||
<feOffset dx="0" dy="10" />
|
||||
<feGaussianBlur stdDeviation="10.5" />
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.29803923 0" />
|
||||
<feBlend mode="normal" in2="effect0_dropShadow" result="effect1_dropShadow" />
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape" />
|
||||
</filter>
|
||||
</defs>
|
||||
<g id="neighbourhood-purple">
|
||||
<path d="M750.419 224.839L750.419 262.111M613.471 208.066L826 306.515M397.732 306.837L610.26 208.388M352.708 208.066L480.225 267.135M197 278.883L350.021 208" id="Shape" fill="none" fill-rule="evenodd" stroke="#8C53E7" stroke-width="29" stroke-linecap="round" stroke-linejoin="round" filter="url(#filter_1)" clip-path="url(#clip_1)" />
|
||||
<g filter="url(#filter_1)" clip-path="url(#clip_1)">
|
||||
<g id="Group" transform="translate(214.02026 338.67798)">
|
||||
<path d="M297.822 476.322C252.091 476.322 206.361 458.882 171.467 424.006L52.3385 304.925C-17.4462 235.169 -17.4462 122.074 52.3385 52.3178C119.763 -15.0793 227.66 -17.3598 297.822 45.4785C367.986 -17.3576 475.883 -15.0771 543.306 52.3178C613.09 122.074 613.09 235.169 543.306 304.925L424.177 424.006C389.286 458.882 343.554 476.322 297.822 476.322" id="Path" fill="#B776FC" stroke="none" />
|
||||
<path d="M248.68 206.983C271.167 243.662 324.478 243.662 346.964 206.983" id="Path" fill="none" stroke="#22184C" stroke-width="22" stroke-linecap="round" />
|
||||
<path d="M325.877 150.757C325.877 139.083 335.344 129.62 347.022 129.62C358.7 129.62 368.167 139.083 368.167 150.757C368.167 162.43 358.7 171.893 347.022 171.893C335.344 171.893 325.877 162.43 325.877 150.757Z" id="Oval" fill="#22184C" fill-rule="evenodd" stroke="none" />
|
||||
<path d="M227.357 150.757C227.357 139.083 236.824 129.62 248.502 129.62C260.181 129.62 269.648 139.083 269.648 150.757C269.648 162.43 260.181 171.893 248.502 171.893C236.824 171.893 227.357 162.43 227.357 150.757Z" id="Oval" fill="#22184C" fill-rule="evenodd" stroke="none" />
|
||||
<path d="M72.7875 192.911C72.7875 153.977 104.362 122.416 143.312 122.416C182.261 122.416 213.836 153.977 213.836 192.911C213.836 231.845 182.261 263.407 143.312 263.407C104.362 263.407 72.7875 231.845 72.7875 192.911Z" id="Oval" fill="#8C53E7" fill-rule="evenodd" stroke="none" />
|
||||
<path d="M381.808 192.911C381.808 153.977 413.382 122.416 452.332 122.416C491.281 122.416 522.856 153.977 522.856 192.911C522.856 231.845 491.281 263.407 452.332 263.407C413.382 263.407 381.808 231.845 381.808 192.911Z" id="Oval" fill="#8C53E7" fill-rule="evenodd" stroke="none" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 3.4 KiB |
|
@ -21,14 +21,18 @@ namespace Neighbourhood.omg.lol {
|
|||
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
|
||||
WriteIndented = true
|
||||
};
|
||||
addToken(token);
|
||||
AddToken(token);
|
||||
}
|
||||
|
||||
private void addToken(string? token = null) {
|
||||
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);
|
||||
}
|
||||
|
||||
public void RemoveToken() {
|
||||
_client.DefaultRequestHeaders.Remove("Authorization");
|
||||
}
|
||||
|
||||
private async Task<T?> Get<T>(string uri, CancellationToken cancellationToken = default) where T : IOmgLolResponseData {
|
||||
T? responseData = default(T);
|
||||
try {
|
||||
|
@ -94,6 +98,25 @@ namespace Neighbourhood.omg.lol {
|
|||
return responseData;
|
||||
}
|
||||
|
||||
private async Task<TResponse?> Patch<TResponse, TData>(string uri, TData data, CancellationToken cancellationToken = default) where TResponse : IOmgLolResponseData {
|
||||
TResponse? responseData = default(TResponse);
|
||||
try {
|
||||
HttpResponseMessage response = await _client.PatchAsJsonAsync(uri, data, _serializerOptions, cancellationToken: cancellationToken);
|
||||
string str = await response.Content.ReadAsStringAsync();
|
||||
if (response.IsSuccessStatusCode) {
|
||||
OmgLolResponse<TResponse>? responseObj = await response.Content.ReadFromJsonAsync<OmgLolResponse<TResponse>>(_serializerOptions, cancellationToken: cancellationToken);
|
||||
if (responseObj != null && responseObj.Request.Success) {
|
||||
responseData = responseObj.Response;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Debug.WriteLine(@"\tERROR {0}", ex.Message);
|
||||
}
|
||||
|
||||
return responseData;
|
||||
}
|
||||
|
||||
public async Task<List<Status>> StatuslogLatest() =>
|
||||
(await Get<StatusResponseData>("/statuslog/latest"))?.Statuses ?? new List<Status>();
|
||||
|
||||
|
@ -102,7 +125,7 @@ namespace Neighbourhood.omg.lol {
|
|||
|
||||
public async Task<MarkupString> StatuslogBio(string address) {
|
||||
StatusBioResponseData? responseData = await Get<StatusBioResponseData>($"/address/{address}/statuses/bio");
|
||||
return (MarkupString)Markdown.ToHtml(responseData?.Bio ?? "");
|
||||
return Utilities.MdToHtmlMarkup(responseData?.Bio ?? "");
|
||||
}
|
||||
|
||||
public async Task<AccountResponseData?> AccountInfo() =>
|
||||
|
@ -148,6 +171,10 @@ namespace Neighbourhood.omg.lol {
|
|||
public async Task<PutPicResponseData?> PostPicDescription(string address, string id, string description) =>
|
||||
(await Post<PutPicResponseData, PostPic>($"/address/{address}/pics/{id}", new PostPic { Description = description }));
|
||||
|
||||
public async Task<PatchStatusResponseData?> PatchStatus(string address, string id, string content, string? emoji) =>
|
||||
(await Patch<PatchStatusResponseData, PatchStatus>($"/address/{address}/statuses/", new PatchStatus { Id = id, Content = content, Emoji = emoji }));
|
||||
|
||||
|
||||
public async Task<List<NowData>?> NowGarden() =>
|
||||
(await Get<NowResponseData>($"/now/garden"))?.Garden ?? new List<NowData>();
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
@import url(../vendor/color.css);
|
||||
@import url(../vendor/beer.min.css);
|
||||
@import url(../vendor/beer.min.css);
|
||||
@import url(../vendor/color.css);
|
||||
@import url(../vendor/type.css);
|
||||
@import url(../vendor/fluent-emoji/SegoeUIEmoji.css);
|
||||
/*@import url(../vendor/fluent-emoji/3d.css);*/
|
||||
|
@ -13,11 +13,35 @@
|
|||
--spacing: 1.5rem;
|
||||
--radius: .75em;
|
||||
--small-radius: .13em;
|
||||
/* --color: var(--white);
|
||||
--color: var(--gray-1);
|
||||
--background: var(--gray-8);
|
||||
--shadow: var(--black);
|
||||
--button-shadow: var(--gray-7);*/
|
||||
--button-shadow: var(--gray-7);
|
||||
}
|
||||
|
||||
body.dark {
|
||||
--background: var(--gray-8);
|
||||
--on-background: var(--gray-1);
|
||||
--surface: var(--gray-9);
|
||||
--on-surface: var(--gray-4);
|
||||
/* --surface-variant: #49454e;
|
||||
--on-surface-variant: #cac4cf;
|
||||
--outline: #948f99;
|
||||
--outline-variant: #49454e;
|
||||
--shadow: #000000;
|
||||
--scrim: #000000;
|
||||
--inverse-surface: #e6e1e6;
|
||||
--inverse-on-surface: #313033;
|
||||
--inverse-primary: #6750a4;
|
||||
--surface-dim: #141316;
|
||||
--surface-bright: #3a383c;
|
||||
--surface-container-lowest: #0f0e11;
|
||||
--surface-container-low: #1c1b1e;
|
||||
--surface-container: #201f22;
|
||||
--surface-container-high: #2b292d;
|
||||
--surface-container-highest: #363438;*/
|
||||
}
|
||||
|
||||
html, body {
|
||||
font-family: var(--font);
|
||||
}
|
||||
|
@ -43,7 +67,7 @@ p, li {
|
|||
line-height: 160%;
|
||||
}
|
||||
|
||||
.author, .address {
|
||||
.author, .address, .page-heading {
|
||||
font-family: 'VC Honey Deck', var(--font);
|
||||
}
|
||||
.author {
|
||||
|
@ -58,15 +82,37 @@ img {
|
|||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.status .emoji, #status-emoji {
|
||||
.status .emoji {
|
||||
margin-bottom: auto;
|
||||
inline-size: 5.5rem;
|
||||
block-size: 5.5rem;
|
||||
font-size: 5rem;
|
||||
line-height: 5.5rem;
|
||||
text-indent: -10px;
|
||||
}
|
||||
|
||||
.status .emoji, #status-emoji {
|
||||
margin-bottom: auto;
|
||||
inline-size: 3.5rem;
|
||||
block-size: 3.5rem;
|
||||
font-size: 3.1rem;
|
||||
line-height: 3.5rem;
|
||||
text-indent: -6px;
|
||||
}
|
||||
|
||||
:is(h1, h2, h3, h4, h5, h6) :is(i.fa-at, i:only-child){
|
||||
margin-right: 0;
|
||||
inline-size: auto;
|
||||
}
|
||||
|
||||
h1 i:only-child {
|
||||
margin-block-start: 1rem;
|
||||
}
|
||||
|
||||
.chip i {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.status nav .chip, .status nav {
|
||||
color: var(--gray-7);
|
||||
}
|
||||
|
@ -253,7 +299,7 @@ article.ephemeral {
|
|||
flex-shrink: 1;
|
||||
}
|
||||
|
||||
.page-container > .page {
|
||||
.page-container > .page.active {
|
||||
display:flex;
|
||||
flex-direction:column;
|
||||
flex-grow: 1;
|
||||
|
@ -267,6 +313,13 @@ article.ephemeral {
|
|||
|
||||
}
|
||||
|
||||
.now {
|
||||
background-color: var(--green-2);
|
||||
color: var(--black);
|
||||
}
|
||||
|
||||
|
||||
|
||||
main, .page-container {
|
||||
flex-grow:1;
|
||||
display: flex;
|
||||
|
@ -274,7 +327,9 @@ main, .page-container {
|
|||
}
|
||||
|
||||
main {
|
||||
overflow: hidden;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
|
||||
}
|
||||
|
||||
.hover {
|
||||
|
@ -287,4 +342,57 @@ main {
|
|||
|
||||
#info :is(p, ul, ol) {
|
||||
margin-bottom: var(--spacing);
|
||||
}
|
||||
|
||||
.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-comment-dots { color: var(--gray-6) !important; }
|
||||
|
||||
nav.bottom.s :is(small, .label) {
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
i.tiny {
|
||||
---size: 1em;
|
||||
}
|
||||
|
||||
.row p {
|
||||
white-space: normal;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
a.row.indent {
|
||||
margin-left: 1rem;
|
||||
border-left: 1px solid var(--outline);
|
||||
}
|
||||
|
||||
:is(.circle,.square).large.small:not(i,img,video,svg) {
|
||||
block-size: 2rem;
|
||||
inline-size: 2rem;
|
||||
}
|
||||
:is(button,.button,.chip).large.small > .responsive {
|
||||
inline-size: 2rem;
|
||||
}
|
||||
|
||||
/* s */
|
||||
@media only screen and (max-width: 600px) {
|
||||
|
||||
}
|
||||
|
||||
/* m */
|
||||
@media only screen and (min-width: 601px) and (max-width: 992px) {
|
||||
|
||||
}
|
||||
|
||||
/* l */
|
||||
@media only screen and (min-width: 993px) {
|
||||
:is(.circle,.square).large.small:not(i,img,video,svg) {
|
||||
block-size: 3rem;
|
||||
inline-size: 3rem;
|
||||
}
|
||||
:is(button,.button,.chip).large.small > .responsive {
|
||||
inline-size: 3rem;
|
||||
}
|
||||
}
|
4
wwwroot/vendor/type/icons/omg.lol-icons.css
vendored
4
wwwroot/vendor/type/icons/omg.lol-icons.css
vendored
|
@ -1,13 +1,13 @@
|
|||
/* omg.lol Icon Type */
|
||||
|
||||
@import url('/css/lol/icons/omg.lol-glyphs.css');
|
||||
@import url('/vendor/type/icons/omg.lol-glyphs.css');
|
||||
|
||||
@font-face {
|
||||
font-family: 'omg.lol Icons';
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
font-display: block;
|
||||
src: url('/css/lol/icons/omg.lol-icons.woff2') format('woff2');
|
||||
src: url('/vendor/type/icons/omg.lol-icons.woff2') format('woff2');
|
||||
}
|
||||
|
||||
.omg-icon {
|
||||
|
|
Loading…
Reference in a new issue