merge: branch 'main' into reports

This commit is contained in:
Sam 2023-03-23 10:50:36 +01:00
commit 244c13cd84
Signed by: sam
GPG key ID: B4EF20DDE721CAA1
30 changed files with 207 additions and 435 deletions

View file

@ -1,3 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

View file

@ -0,0 +1,11 @@
import MarkdownIt from "markdown-it";
import sanitize from "sanitize-html";
const md = new MarkdownIt({
html: false,
breaks: true,
}).disable(["heading", "link", "table"]);
export default function renderMarkdown(src: string | null) {
return src ? sanitize(md.render(src)) : null;
}

View file

@ -1,6 +1,4 @@
<script lang="ts">
import { Card, CardHeader, CardTitle, ListGroup, ListGroupItem } from "sveltestrap";
import type { Field } from "$lib/api/entities";
import StatusIcon from "./StatusIcon.svelte";

View file

@ -31,7 +31,9 @@
</script>
<div>
<FallbackImage urls={memberAvatars(member)} width={200} alt="Avatar for {member.name}" />
<a href="/@{user.name}/{member.name}">
<FallbackImage urls={memberAvatars(member)} width={200} alt="Avatar for {member.name}" />
</a>
<p class="m-2">
<a class="text-reset fs-5" href="/@{user.name}/{member.name}">
{member.display_name ?? member.name}

View file

@ -4,18 +4,25 @@
export let pronouns: Pronoun;
let pronounText: string;
if (pronouns.display_text) {
pronounText = pronouns.display_text;
} else {
const split = pronouns.pronouns.split("/");
if (split.length < 2) pronounText = split.join("/");
else pronounText = split.slice(0, 2).join("/");
}
$: pronounText = updatePronouns(pronouns);
const link = pronouns.display_text
const updatePronouns = (pronouns: Pronoun) => {
if (pronouns.display_text) {
return pronouns.display_text;
} else {
const split = pronouns.pronouns.split("/");
if (split.length < 2) return split.join("/");
else return split.slice(0, 2).join("/");
}
};
let link: string;
let shouldLink: boolean;
$: link = pronouns.display_text
? `${pronouns.pronouns},${pronouns.display_text}`
: pronouns.pronouns;
const shouldLink = pronouns.pronouns.split("/").length === 5;
$: shouldLink = pronouns.pronouns.split("/").length === 5;
</script>
{#if shouldLink}

View file

@ -4,7 +4,7 @@ import type { APIError } from "$lib/api/entities";
import { apiFetch } from "$lib/api/fetch";
import type { MetaResponse } from "$lib/api/responses";
export const load = (async (event) => {
export const load = (async () => {
try {
return await apiFetch<MetaResponse>("/meta", {});
} catch (e) {

View file

@ -1,7 +1,4 @@
<script lang="ts">
import { marked } from "marked";
import sanitizeHtml from "sanitize-html";
import type { PageData } from "./$types";
import {
@ -33,11 +30,12 @@
import { apiFetchClient } from "$lib/api/fetch";
import ErrorAlert from "$lib/components/ErrorAlert.svelte";
import { goto } from "$app/navigation";
import renderMarkdown from "$lib/api/markdown";
export let data: PageData;
let bio: string | null;
$: bio = data.bio ? sanitizeHtml(marked.parse(data.bio, { breaks: true })) : null;
$: bio = renderMarkdown(data.bio);
let memberPage: number = 0;
let memberSlice: PartialMember[] = [];

View file

@ -1,7 +1,4 @@
<script lang="ts">
import { marked } from "marked";
import sanitizeHtml from "sanitize-html";
import FieldCard from "$lib/components/FieldCard.svelte";
import type { PageData } from "./$types";
@ -12,11 +9,12 @@
import { memberAvatars, pronounDisplay, WordStatus } from "$lib/api/entities";
import { PUBLIC_BASE_URL } from "$env/static/public";
import { userStore } from "$lib/store";
import renderMarkdown from "$lib/api/markdown";
export let data: PageData;
let bio: string | null;
$: bio = data.bio ? sanitizeHtml(marked.parse(data.bio, { breaks: true })) : null;
$: bio = renderMarkdown(data.bio);
const favNames = data.names.filter((entry) => entry.status === WordStatus.Favourite);
const favPronouns = data.pronouns.filter((entry) => entry.status === WordStatus.Favourite);

View file

@ -1,6 +1,6 @@
import type { APIError, MeUser } from "$lib/api/entities";
import { apiFetch } from "$lib/api/fetch";
import type { PageServerLoad, Actions } from "./$types";
import type { PageServerLoad } from "./$types";
import { PUBLIC_BASE_URL } from "$env/static/public";
export const load = (async ({ url }) => {

View file

@ -1,7 +1,7 @@
<script lang="ts">
import { WordStatus, type Field } from "$lib/api/entities";
import IconButton from "$lib/components/IconButton.svelte";
import { Button, Input, InputGroup, InputGroupText } from "sveltestrap";
import { Button, Input, InputGroup } from "sveltestrap";
import FieldEntry from "./FieldEntry.svelte";
export let field: Field;

View file

@ -88,6 +88,7 @@
const fieldsEqual = (arr1: Field[], arr2: Field[]) => {
if (arr1?.length !== arr2?.length) return false;
if (!arr1.every((_, i) => arr1[i].entries.length === arr2[i].entries.length)) return false;
if (!arr1.every((_, i) => arr1[i].name === arr2[i].name)) return false;
return arr1.every((_, i) =>
@ -334,8 +335,8 @@
accept="image/png, image/jpeg, image/gif, image/webp"
/>
<p class="text-muted mt-3">
<Icon name="info-circle-fill" /> Only PNG, JPEG, GIF, and WebP can be used as avatars.
Avatars cannot be larger than 1 MB, and animated avatars will be made static.
<Icon name="info-circle-fill" aria-hidden /> Only PNG, JPEG, GIF, and WebP can be used
as avatars. Avatars cannot be larger than 1 MB, and animated avatars will be made static.
</p>
<a href="" on:click={() => (avatar = "")}>Remove avatar</a>
</div>
@ -356,6 +357,15 @@
<FormGroup floating label="Bio ({bio.length}/{MAX_DESCRIPTION_LENGTH})">
<textarea style="min-height: 100px;" class="form-control" bind:value={bio} />
</FormGroup>
<p class="text-muted mt-3">
<Icon name="info-circle-fill" aria-hidden /> Your bio supports limited
<a
class="text-reset"
href="https://commonmark.org/help/"
target="_blank"
rel="noopener noreferrer">Markdown</a
>.
</p>
</div>
</div>
</div>

View file

@ -75,6 +75,7 @@
const fieldsEqual = (arr1: Field[], arr2: Field[]) => {
if (arr1?.length !== arr2?.length) return false;
if (!arr1.every((_, i) => arr1[i].entries.length === arr2[i].entries.length)) return false;
if (!arr1.every((_, i) => arr1[i].name === arr2[i].name)) return false;
return arr1.every((_, i) =>
@ -281,8 +282,9 @@
accept="image/png, image/jpeg, image/gif, image/webp"
/>
<p class="text-muted mt-3">
<Icon name="info-circle-fill" /> Only PNG, JPEG, GIF, and WebP images can be used as avatars.
Avatars cannot be larger than 1 MB, and animated avatars will be made static.
<Icon name="info-circle-fill" aria-hidden /> Only PNG, JPEG, GIF, and WebP images can be
used as avatars. Avatars cannot be larger than 1 MB, and animated avatars will be made
static.
</p>
<p>
<a href="" on:click={() => (avatar = "")}>Remove avatar</a>
@ -298,6 +300,15 @@
<FormGroup floating label="Bio ({bio.length}/{MAX_DESCRIPTION_LENGTH})">
<textarea style="min-height: 100px;" class="form-control" bind:value={bio} />
</FormGroup>
<p class="text-muted mt-3">
<Icon name="info-circle-fill" aria-hidden /> Your bio supports limited
<a
class="text-reset"
href="https://commonmark.org/help/"
target="_blank"
rel="noopener noreferrer">Markdown</a
>.
</p>
</div>
</div>
</div>

View file

@ -1,10 +1,4 @@
import {
ErrorCode,
type APIError,
type Invite,
type MeUser,
type PartialMember,
} from "$lib/api/entities";
import { ErrorCode, type APIError, type Invite, type MeUser } from "$lib/api/entities";
import { apiFetchClient } from "$lib/api/fetch";
import type { LayoutLoad } from "./$types";
@ -12,7 +6,6 @@ export const ssr = false;
export const load = (async ({ parent }) => {
const user = await apiFetchClient<MeUser>("/users/@me");
const members = await apiFetchClient<PartialMember[]>("/users/@me/members");
let invites: Invite[] = [];
let invitesEnabled = true;
@ -29,7 +22,6 @@ export const load = (async ({ parent }) => {
return {
...data,
user,
members,
invites,
invitesEnabled,
};

View file

@ -91,7 +91,7 @@
</tr>
<tr>
<th scope="row">Members</th>
<td>{data.members.length}/{MAX_MEMBERS}</td>
<td>{data.user.members.length}/{MAX_MEMBERS}</td>
</tr>
{#if data.invitesEnabled}
<tr>

View file

@ -5,8 +5,8 @@
export let data: PageData;
import * as jose from "jose";
const claims = jose.decodeJwt(localStorage.getItem("pronouns-token")!);
import { decodeJwt } from "jose";
const claims = decodeJwt(localStorage.getItem("pronouns-token")!);
</script>
<h1>Tokens ({data.tokens.length})</h1>