even more frontend stuff
This commit is contained in:
parent
8bba5f6137
commit
c0bb76580d
33 changed files with 796 additions and 178 deletions
|
@ -1,22 +1,23 @@
|
|||
<script lang="ts">
|
||||
import { DEFAULT_AVATAR } from "$lib";
|
||||
|
||||
type Props = { url: string | null; alt: string; lazyLoad?: boolean };
|
||||
let { url, alt, lazyLoad }: Props = $props();
|
||||
type Props = { url: string | null; alt: string; lazyLoad?: boolean; size?: number };
|
||||
let { url, alt, lazyLoad, size }: Props = $props();
|
||||
|
||||
let width = $derived(size || 200);
|
||||
</script>
|
||||
|
||||
<img
|
||||
class="rounded-circle img-fluid"
|
||||
style="height: {width}px; width: {width}px"
|
||||
src={url || DEFAULT_AVATAR}
|
||||
{alt}
|
||||
width={200}
|
||||
{width}
|
||||
loading={lazyLoad ? "lazy" : "eager"}
|
||||
/>
|
||||
|
||||
<style>
|
||||
img {
|
||||
object-fit: cover;
|
||||
height: 200px;
|
||||
width: 200px;
|
||||
}
|
||||
</style>
|
||||
|
|
35
Foxnouns.Frontend/src/lib/components/Paginator.svelte
Normal file
35
Foxnouns.Frontend/src/lib/components/Paginator.svelte
Normal file
|
@ -0,0 +1,35 @@
|
|||
<script lang="ts">
|
||||
import { Pagination, PaginationItem, PaginationLink } from "@sveltestrap/sveltestrap";
|
||||
|
||||
type Props = { currentPage: number; pageCount: number; href: string; center?: boolean };
|
||||
let { currentPage, pageCount, href, center }: Props = $props();
|
||||
|
||||
let prevPage = $derived(currentPage > 0 ? currentPage - 1 : 0);
|
||||
let prevLink = $derived(prevPage !== 0 ? `${href}?page=${prevPage}` : href);
|
||||
|
||||
let nextPage = $derived(currentPage < pageCount - 1 ? currentPage + 1 : pageCount - 1);
|
||||
</script>
|
||||
|
||||
{#if pageCount > 1}
|
||||
<div>
|
||||
<Pagination listClassName={center ? "justify-content-center" : undefined}>
|
||||
<PaginationItem>
|
||||
<PaginationLink first {href} />
|
||||
</PaginationItem>
|
||||
<PaginationItem>
|
||||
<PaginationLink previous href={prevLink} />
|
||||
</PaginationItem>
|
||||
{#each new Array(pageCount) as _, page}
|
||||
<PaginationItem active={page === currentPage}>
|
||||
<PaginationLink href="{href}?page={page}">{page + 1}</PaginationLink>
|
||||
</PaginationItem>
|
||||
{/each}
|
||||
<PaginationItem>
|
||||
<PaginationLink next href="{href}?page={nextPage}" />
|
||||
</PaginationItem>
|
||||
<PaginationItem>
|
||||
<PaginationLink last href="{href}?page={pageCount - 1}" />
|
||||
</PaginationItem>
|
||||
</Pagination>
|
||||
</div>
|
||||
{/if}
|
|
@ -4,14 +4,15 @@
|
|||
import { Icon, InputGroup } from "@sveltestrap/sveltestrap";
|
||||
import { encode } from "base64-arraybuffer";
|
||||
import prettyBytes from "pretty-bytes";
|
||||
import ShortNoscriptWarning from "./ShortNoscriptWarning.svelte";
|
||||
|
||||
type Props = {
|
||||
current: string | null;
|
||||
alt: string;
|
||||
onclick: (avatar: string) => Promise<void>;
|
||||
update: (avatar: string) => Promise<void>;
|
||||
updated: boolean;
|
||||
};
|
||||
let { current, alt, onclick, updated }: Props = $props();
|
||||
let { current, alt, update: onclick, updated }: Props = $props();
|
||||
|
||||
const MAX_AVATAR_BYTES = 1_000_000;
|
||||
|
||||
|
@ -59,6 +60,8 @@
|
|||
</button>
|
||||
</InputGroup>
|
||||
|
||||
<ShortNoscriptWarning />
|
||||
|
||||
{#if updated}
|
||||
<p class="text-success-emphasis">
|
||||
<Icon name="check-circle-fill" />
|
||||
|
|
26
Foxnouns.Frontend/src/lib/components/editor/BioEditor.svelte
Normal file
26
Foxnouns.Frontend/src/lib/components/editor/BioEditor.svelte
Normal file
|
@ -0,0 +1,26 @@
|
|||
<script lang="ts">
|
||||
import { t } from "$lib/i18n";
|
||||
import { renderMarkdown } from "$lib/markdown";
|
||||
|
||||
type Props = { value: string; maxLength: number };
|
||||
let { value = $bindable(), maxLength }: Props = $props();
|
||||
</script>
|
||||
|
||||
<textarea name="bio" class="form-control" style="height: 200px;" bind:value></textarea>
|
||||
<button disabled={value.length > maxLength} type="submit" class="btn btn-primary mt-2 my-1">
|
||||
{$t("save-changes")}
|
||||
</button>
|
||||
|
||||
<p class="text-muted mt-1">
|
||||
{$t("edit-profile.bio-length-hint", {
|
||||
length: value.length,
|
||||
maxLength,
|
||||
})}
|
||||
</p>
|
||||
|
||||
{#if value !== ""}
|
||||
<div class="card">
|
||||
<div class="card-header">{$t("edit-profile.preview")}</div>
|
||||
<div class="card-body">{@html renderMarkdown(value)}</div>
|
||||
</div>
|
||||
{/if}
|
|
@ -0,0 +1,12 @@
|
|||
<script lang="ts">
|
||||
import { t } from "$lib/i18n";
|
||||
</script>
|
||||
|
||||
<noscript>
|
||||
<div class="alert alert-secondary">
|
||||
<h4>{$t("error.noscript-title")}</h4>
|
||||
<p>
|
||||
{$t("error.noscript-info")}
|
||||
</p>
|
||||
</div>
|
||||
</noscript>
|
|
@ -0,0 +1,11 @@
|
|||
<script lang="ts">
|
||||
import { t } from "$lib/i18n";
|
||||
import { Icon } from "@sveltestrap/sveltestrap";
|
||||
</script>
|
||||
|
||||
<noscript>
|
||||
<p class="text-danger-emphasis">
|
||||
<Icon name="exclamation-circle-fill" aria-hidden />
|
||||
{$t("error.noscript-short")}
|
||||
</p>
|
||||
</noscript>
|
30
Foxnouns.Frontend/src/lib/components/editor/SidEditor.svelte
Normal file
30
Foxnouns.Frontend/src/lib/components/editor/SidEditor.svelte
Normal file
|
@ -0,0 +1,30 @@
|
|||
<script lang="ts">
|
||||
import { PUBLIC_SHORT_URL } from "$env/static/public";
|
||||
import { t } from "$lib/i18n";
|
||||
import { ButtonGroup, Button, Icon } from "@sveltestrap/sveltestrap";
|
||||
import ShortNoscriptWarning from "./ShortNoscriptWarning.svelte";
|
||||
|
||||
type Props = { sid: string; rerollSid: () => Promise<void>; canRerollSid: boolean };
|
||||
let { sid, rerollSid, canRerollSid }: Props = $props();
|
||||
|
||||
const copySid = async () => {
|
||||
const url = `${PUBLIC_SHORT_URL}/${sid}`;
|
||||
await navigator.clipboard.writeText(url);
|
||||
};
|
||||
</script>
|
||||
|
||||
{$t("edit-profile.sid-current")} <code>{sid}</code>
|
||||
<ButtonGroup class="mb-1">
|
||||
<Button color="secondary" onclick={() => rerollSid()} disabled={!canRerollSid}>
|
||||
{$t("edit-profile.sid-reroll")}
|
||||
</Button>
|
||||
<Button color="secondary" onclick={() => copySid()}>
|
||||
<Icon name="link-45deg" aria-hidden />
|
||||
<span class="visually-hidden">{$t("edit-profile.sid-copy")}</span>
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
<ShortNoscriptWarning />
|
||||
<p class="text-muted">
|
||||
<Icon name="info-circle-fill" aria-hidden />
|
||||
{$t("edit-profile.sid-hint")}
|
||||
</p>
|
|
@ -35,11 +35,15 @@
|
|||
|
||||
<div>
|
||||
<a href="/@{username}/{member.name}">
|
||||
<Avatar url={member.avatar_url} lazyLoad alt={$t("avatar-tooltip", { name: member.name })} />
|
||||
<Avatar
|
||||
url={member.avatar_url}
|
||||
lazyLoad
|
||||
alt={$t("avatar-tooltip", { name: member.display_name })}
|
||||
/>
|
||||
</a>
|
||||
<p class="m-2">
|
||||
<a class="text-reset fs-5 text-break" href="/@{username}/{member.name}">
|
||||
{member.name}
|
||||
{member.display_name}
|
||||
</a>
|
||||
{#if pronouns}
|
||||
<br />
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue