more pic fixes
This commit is contained in:
parent
ff54c4c613
commit
d0d3d2cc00
9 changed files with 166 additions and 119 deletions
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
<div class="overlay" data-ui="#@id"></div>
|
<div class="overlay" data-ui="#@id"></div>
|
||||||
<dialog id="@id">
|
<dialog id="@id">
|
||||||
<img src="@Pic.Url" />
|
<img src="@Pic?.Url" />
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="field textarea label border max">
|
<div class="field textarea label border max">
|
||||||
<InputTextArea @bind-Value="Description"></InputTextArea>
|
<InputTextArea @bind-Value="Description"></InputTextArea>
|
||||||
|
@ -25,7 +25,7 @@
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private Pic? _pic;
|
private Pic? _pic;
|
||||||
[Parameter]
|
|
||||||
public Pic? Pic {
|
public Pic? Pic {
|
||||||
get => _pic;
|
get => _pic;
|
||||||
set {
|
set {
|
||||||
|
|
|
@ -56,7 +56,7 @@
|
||||||
@if(Editable){
|
@if(Editable){
|
||||||
<EditPicDialog @ref="editPicDialog" id="EditPicModal"></EditPicDialog>
|
<EditPicDialog @ref="editPicDialog" id="EditPicModal"></EditPicDialog>
|
||||||
}
|
}
|
||||||
<PicList PicsFunc="@State.VirtualPicsFunc(Address)" Editable="@Editable" Dialog="@editPicDialog"></PicList>
|
<PicList PicsFunc="@(async() => await State.GetPics(Address))" Editable="@Editable" Dialog="@editPicDialog"></PicList>
|
||||||
</div>
|
</div>
|
||||||
@if(now != null){
|
@if(now != null){
|
||||||
<div id="now" class="page no-padding">
|
<div id="now" class="page no-padding">
|
||||||
|
|
|
@ -21,112 +21,10 @@
|
||||||
</Authorized>
|
</Authorized>
|
||||||
</AuthorizeView>
|
</AuthorizeView>
|
||||||
|
|
||||||
<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="right-align 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>
|
|
||||||
@* @if (Editable) {
|
|
||||||
<button @onclick="EditPic"><i class="fa-solid fa-pencil"></i> Edit</button>
|
|
||||||
} *@
|
|
||||||
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div id="pics" class="responsive card-grid">
|
<div id="pics" class="responsive card-grid">
|
||||||
@* <PicList PicsFunc="@State.VirtualPicsFunc()"></PicList> *@
|
<PicList PicsFunc="@(async() => await State.GetPics())"></PicList>
|
||||||
<article id="pics-loading" class="middle-align center-align">
|
|
||||||
<div>
|
|
||||||
<i class="extra fa-solid fa-images"></i>
|
|
||||||
<div class="space"></div>
|
|
||||||
<progress class="circle"></progress>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
|
||||||
const template = document.getElementById("PicCard")
|
|
||||||
let cSharp;
|
|
||||||
async function renderPics(somePics) {
|
|
||||||
for(const pic of somePics){
|
|
||||||
const clone = template.content.cloneNode(true)
|
|
||||||
let html = clone.children[0].innerHTML
|
|
||||||
|
|
||||||
html = html.replaceAll("{{Pic.Url}}", pic.url)
|
|
||||||
html = html.replaceAll("{{Pic.Address}}", pic.address)
|
|
||||||
html = html.replaceAll("{{Pic.RelativeTime}}", pic.relativeTime)
|
|
||||||
html = html.replaceAll("{{Pic.Description}}", pic.description)
|
|
||||||
|
|
||||||
clone.children[0].innerHTML = html
|
|
||||||
|
|
||||||
clone.querySelector('.share-button').addEventListener('click', shareClick)
|
|
||||||
document.getElementById("pics").insertBefore(clone, document.getElementById("pics-loading"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function clearLoading() {
|
|
||||||
document.getElementById("pics-loading").remove()
|
|
||||||
}
|
|
||||||
|
|
||||||
async function shareClick(e) {
|
|
||||||
const url = this.querySelector('input[name="url"]')?.value
|
|
||||||
const desc = this.querySelector('input[name="description"]')?.value
|
|
||||||
if (cSharp) cSharp.invokeMethodAsync('ShareClick', url, desc)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function setDotNetHelper(helper) {
|
|
||||||
cSharp = helper;
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private List<Pic> pics;
|
|
||||||
private DotNetObjectReference<Pics>? objRef;
|
|
||||||
|
|
||||||
protected override void OnInitialized() {
|
}
|
||||||
objRef = DotNetObjectReference.Create(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override async Task OnAfterRenderAsync(bool firstRender) {
|
|
||||||
await base.OnAfterRenderAsync(firstRender);
|
|
||||||
if (firstRender) {
|
|
||||||
await JS.InvokeVoidAsync("setDotNetHelper", objRef);
|
|
||||||
RestService api = new RestService();
|
|
||||||
if (pics == null || pics.Count == 0) pics = await api.SomePics();
|
|
||||||
|
|
||||||
int page_size = 1;
|
|
||||||
for(int i = 0; i < pics.Count; i += page_size) {
|
|
||||||
await JS.InvokeVoidAsync("renderPics", pics.Skip(i * page_size).Take(page_size));
|
|
||||||
}
|
|
||||||
await JS.InvokeVoidAsync("clearLoading");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[JSInvokable]
|
|
||||||
public async Task ShareClick(string? url, string? description) {
|
|
||||||
await Share.Default.RequestAsync(new ShareTextRequest {
|
|
||||||
Uri = url,
|
|
||||||
Text = description,
|
|
||||||
Title = "I saw this on some.pics",
|
|
||||||
Subject = "I saw this on some.pics"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
30
Components/PicCardEditableTemplate.razor
Normal file
30
Components/PicCardEditableTemplate.razor
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<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>
|
23
Components/PicCardTemplate.razor
Normal file
23
Components/PicCardTemplate.razor
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</template>
|
|
@ -1,22 +1,105 @@
|
||||||
@inject IJSRuntime JS
|
@inject IJSRuntime JS
|
||||||
<Virtualize ItemsProvider="GetPics" Context="pic" ItemSize="500">
|
|
||||||
<ItemContent>
|
@if (Editable) {
|
||||||
<PicCard Pic="@pic" Editable="@Editable" Dialog="@Dialog"></PicCard>
|
<PicCardEditableTemplate></PicCardEditableTemplate>
|
||||||
</ItemContent>
|
}
|
||||||
<Placeholder>
|
else {
|
||||||
<article class="no-padding center" style="min-height:500px;"></article>
|
<PicCardTemplate></PicCardTemplate>
|
||||||
</Placeholder>
|
}
|
||||||
</Virtualize>
|
|
||||||
|
<article id="pics-loading" class="middle-align center-align">
|
||||||
|
<div>
|
||||||
|
<i class="extra fa-solid fa-images"></i>
|
||||||
|
<div class="space"></div>
|
||||||
|
<progress class="circle"></progress>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
async function renderPics(somePics) {
|
||||||
|
const template = document.getElementById("PicCard")
|
||||||
|
if(template) for (const pic of somePics) {
|
||||||
|
const clone = template.content.cloneNode(true)
|
||||||
|
let html = clone.children[0].innerHTML
|
||||||
|
|
||||||
|
html = html.replaceAll("{{Pic.Id}}", pic.id)
|
||||||
|
html = html.replaceAll("{{Pic.Url}}", pic.url ?? `https://cdn.some.pics/${pic.address}/${pic.id}.${JSON.parse(pic.exif)["File Type Extension"]}`) //TODO: temporary fix
|
||||||
|
html = html.replaceAll("{{Pic.Address}}", pic.address)
|
||||||
|
html = html.replaceAll("{{Pic.RelativeTime}}", pic.relativeTime)
|
||||||
|
html = html.replaceAll("{{Pic.Description}}", pic.description)
|
||||||
|
|
||||||
|
clone.children[0].innerHTML = html
|
||||||
|
|
||||||
|
clone.querySelector('.share-button').addEventListener('click', shareClick)
|
||||||
|
clone.querySelector('.edit-button')?.addEventListener('click', editClick)
|
||||||
|
document.getElementById("pics").insertBefore(clone, document.getElementById("pics-loading"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async function clearLoading() {
|
||||||
|
document.getElementById("pics-loading").remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
async function shareClick(e) {
|
||||||
|
const url = this.querySelector('input[name="url"]')?.value
|
||||||
|
const desc = this.querySelector('input[name="description"]')?.value
|
||||||
|
if (CSHARP) CSHARP.invokeMethodAsync('ShareClick', url, desc)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function editClick(e) {
|
||||||
|
const id = this.querySelector('input[name="id"]')?.value
|
||||||
|
if (CSHARP) CSHARP.invokeMethodAsync('EditClick', id)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public Func<ItemsProviderRequest, ValueTask<ItemsProviderResult<Pic>>> PicsFunc { get; set; }
|
public Func<Task<List<Pic>?>> PicsFunc { get; set; }
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public bool Editable { get; set; } = false;
|
public bool Editable { get; set; } = false;
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public EditPicDialog? Dialog { get; set; }
|
public EditPicDialog? Dialog { get; set; }
|
||||||
|
|
||||||
private async ValueTask<ItemsProviderResult<Pic>> GetPics(ItemsProviderRequest request) {
|
private List<Pic> pics;
|
||||||
return await this.PicsFunc(request);
|
private DotNetObjectReference<PicList>? objRef;
|
||||||
|
|
||||||
|
protected override void OnInitialized() {
|
||||||
|
objRef = DotNetObjectReference.Create(this);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
protected override async Task OnAfterRenderAsync(bool firstRender) {
|
||||||
|
await base.OnAfterRenderAsync(firstRender);
|
||||||
|
if (firstRender) {
|
||||||
|
await JS.InvokeVoidAsync("injectCSharp", objRef);
|
||||||
|
RestService api = new RestService();
|
||||||
|
if (pics == null || pics.Count == 0) pics = await PicsFunc();
|
||||||
|
|
||||||
|
int page_size = 1;
|
||||||
|
for (int i = 0; i < pics.Count; i += page_size) {
|
||||||
|
await JS.InvokeVoidAsync("renderPics", pics.Skip(i * page_size).Take(page_size));
|
||||||
|
}
|
||||||
|
await JS.InvokeVoidAsync("clearLoading");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[JSInvokable]
|
||||||
|
public async Task EditClick(string? id) {
|
||||||
|
if (Editable && Dialog != null)
|
||||||
|
{
|
||||||
|
Pic? pic = pics.FirstOrDefault(p => p.Id == id);
|
||||||
|
Dialog.Pic = pic;
|
||||||
|
// await InvokeAsync(StateHasChanged);
|
||||||
|
await JS.InvokeVoidAsync("ui", "#" + Dialog?.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[JSInvokable]
|
||||||
|
public async Task ShareClick(string? url, string? description) {
|
||||||
|
await Share.Default.RequestAsync(new ShareTextRequest {
|
||||||
|
Uri = url,
|
||||||
|
Text = description,
|
||||||
|
Title = "I saw this on some.pics",
|
||||||
|
Subject = "I saw this on some.pics"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -143,6 +143,15 @@ namespace Neighbourhood.omg.lol.Models {
|
||||||
return this.Pics;
|
return this.Pics;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<List<Pic>?> GetPics(string address, bool forceRefresh = false) {
|
||||||
|
CachedAddress = address;
|
||||||
|
if (forceRefresh || this.Pics == null || this.Pics.Count == 0) {
|
||||||
|
RestService api = new RestService();
|
||||||
|
CachedAddressPics = (await api.SomePics(address)) ?? new List<Pic>();
|
||||||
|
}
|
||||||
|
return CachedAddressPics;
|
||||||
|
}
|
||||||
|
|
||||||
public async ValueTask<ItemsProviderResult<Pic>> VirtualPics(ItemsProviderRequest request) {
|
public async ValueTask<ItemsProviderResult<Pic>> VirtualPics(ItemsProviderRequest request) {
|
||||||
// TODO: request.cancellationToken
|
// TODO: request.cancellationToken
|
||||||
var pics = (await this.GetPics()) ?? new List<Pic>();
|
var pics = (await this.GetPics()) ?? new List<Pic>();
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
<script type="module" src="vendor/beer.min.js"></script>
|
<script type="module" src="vendor/beer.min.js"></script>
|
||||||
<script type="module" src="vendor/material-dynamic-colors.min.js"></script>
|
<script type="module" src="vendor/material-dynamic-colors.min.js"></script>
|
||||||
<script src="vendor/iframe-resizer/parent.js"></script>
|
<script src="vendor/iframe-resizer/parent.js"></script>
|
||||||
|
<script src="/js/csharp.js"></script>
|
||||||
<link rel="icon" type="image/png" href="favicon.png" />
|
<link rel="icon" type="image/png" href="favicon.png" />
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
3
wwwroot/js/csharp.js
Normal file
3
wwwroot/js/csharp.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
window.injectCSharp = async function (helper) {
|
||||||
|
window.CSHARP = helper
|
||||||
|
}
|
Loading…
Reference in a new issue