feat(frontend): show custom preferences

This commit is contained in:
Sam 2023-04-19 12:24:34 +02:00 committed by Gitea
parent 2c71741d7c
commit 8bda5f9860
7 changed files with 120 additions and 57 deletions

View file

@ -0,0 +1,41 @@
import { type CustomPreferences, PreferenceSize } from "./entities";
const defaultPreferences: CustomPreferences = {
favourite: {
icon: "heart-fill",
tooltip: "Favourite",
size: PreferenceSize.Large,
muted: false,
favourite: true,
},
okay: {
icon: "hand-thumbs-up",
tooltip: "Okay",
size: PreferenceSize.Normal,
muted: false,
favourite: false,
},
jokingly: {
icon: "emoji-laughing",
tooltip: "Jokingly",
size: PreferenceSize.Normal,
muted: false,
favourite: false,
},
friends_only: {
icon: "people",
tooltip: "Friends only",
size: PreferenceSize.Normal,
muted: false,
favourite: false,
},
avoid: {
icon: "people",
tooltip: "Avoid",
size: PreferenceSize.Small,
muted: true,
favourite: false,
},
};
export default defaultPreferences;

View file

@ -16,6 +16,25 @@ export interface User {
pronouns: Pronoun[]; pronouns: Pronoun[];
members: PartialMember[]; members: PartialMember[];
fields: Field[]; fields: Field[];
custom_preferences: CustomPreferences;
}
export interface CustomPreferences {
[key: string]: CustomPreference;
}
export interface CustomPreference {
icon: string;
tooltip: string;
size: PreferenceSize;
muted: boolean;
favourite: boolean;
}
export enum PreferenceSize {
Large = "large",
Normal = "normal",
Small = "small",
} }
export interface MeUser extends User { export interface MeUser extends User {
@ -80,6 +99,7 @@ export interface MemberPartialUser {
name: string; name: string;
display_name: string | null; display_name: string | null;
avatar: string | null; avatar: string | null;
custom_preferences: CustomPreferences;
} }
export interface Invite { export interface Invite {

View file

@ -1,16 +1,17 @@
<script lang="ts"> <script lang="ts">
import type { Field } from "$lib/api/entities"; import type { CustomPreferences, Field } from "$lib/api/entities";
import StatusLine from "./StatusLine.svelte"; import StatusLine from "./StatusLine.svelte";
export let field: Field; export let field: Field;
export let preferences: CustomPreferences;
</script> </script>
<div> <div>
<h3>{field.name}</h3> <h3>{field.name}</h3>
<ul class="list-unstyled fs-5"> <ul class="list-unstyled fs-5">
{#each field.entries as entry} {#each field.entries as entry}
<li><StatusLine status={entry.status}>{entry.value}</StatusLine></li> <li><StatusLine {preferences} status={entry.status}>{entry.value}</StatusLine></li>
{/each} {/each}
</ul> </ul>
</div> </div>

View file

@ -1,53 +1,24 @@
<script lang="ts"> <script lang="ts">
import { Icon, Tooltip } from "sveltestrap"; import { Icon, Tooltip } from "sveltestrap";
import { WordStatus } from "$lib/api/entities"; import type { CustomPreference, CustomPreferences } from "$lib/api/entities";
import defaultPreferences from "$lib/api/default_preferences";
export let status: WordStatus; export let preferences: CustomPreferences;
export let status: string;
export let className: string | null = null; export let className: string | null = null;
const iconFor = (wordStatus: WordStatus) => { let mergedPreferences: CustomPreferences;
switch (wordStatus) { $: mergedPreferences = Object.assign(defaultPreferences, preferences);
case WordStatus.Favourite:
return "heart-fill";
case WordStatus.Okay:
return "hand-thumbs-up";
case WordStatus.Jokingly:
return "emoji-laughing";
case WordStatus.FriendsOnly:
return "people";
case WordStatus.Avoid:
return "hand-thumbs-down";
default:
return "hand-thumbs-up";
}
};
const textFor = (wordStatus: WordStatus) => { let currentPreference: CustomPreference;
switch (wordStatus) { $: currentPreference =
case WordStatus.Favourite: status in mergedPreferences ? mergedPreferences[status] : defaultPreferences.okay;
return "Favourite";
case WordStatus.Okay:
return "Okay";
case WordStatus.Jokingly:
return "Jokingly";
case WordStatus.FriendsOnly:
return "Friends only";
case WordStatus.Avoid:
return "Avoid";
default:
return "Okay";
}
};
let statusIcon: string;
$: statusIcon = iconFor(status);
let statusText: string;
$: statusText = textFor(status);
let iconElement: HTMLElement; let iconElement: HTMLElement;
</script> </script>
<span bind:this={iconElement} tabindex={0}><Icon name={statusIcon} class={className} /></span> <span bind:this={iconElement} tabindex={0}
<Tooltip target={iconElement} placement="top">{statusText}</Tooltip> ><Icon name={currentPreference.icon} class={className} /></span
>
<Tooltip target={iconElement} placement="top">{currentPreference.tooltip}</Tooltip>

View file

@ -1,14 +1,44 @@
<script lang="ts"> <script lang="ts">
import { WordStatus } from "$lib/api/entities"; import { PreferenceSize } from "$lib/api/entities";
import StatusIcon from "$lib/components/StatusIcon.svelte"; import StatusIcon from "$lib/components/StatusIcon.svelte";
export let status: WordStatus; import type { CustomPreference, CustomPreferences } from "$lib/api/entities";
import defaultPreferences from "$lib/api/default_preferences";
export let preferences: CustomPreferences;
export let status: string;
let mergedPreferences: CustomPreferences;
$: mergedPreferences = Object.assign(defaultPreferences, preferences);
let currentPreference: CustomPreference;
$: currentPreference =
status in mergedPreferences ? mergedPreferences[status] : defaultPreferences.okay;
let classes: string;
$: classes = setClasses(currentPreference);
const setClasses = (pref: CustomPreference) => {
let classes = "";
if (pref.muted) {
classes += "text-muted ";
}
switch (pref.size) {
case PreferenceSize.Large:
classes += "fs-5";
break;
case PreferenceSize.Normal:
break;
case PreferenceSize.Small:
classes += "fs-6";
}
return classes.trim();
};
</script> </script>
{#if status === WordStatus.Favourite} {#if currentPreference.size === PreferenceSize.Large}
<strong class="fs-5"><StatusIcon {status} /> <slot /></strong> <strong class={classes}><StatusIcon {preferences} {status} /> <slot /></strong>
{:else if status === WordStatus.Avoid}
<span class="fs-6 text-muted"><StatusIcon {status} /> <slot /></span>
{:else} {:else}
<StatusIcon {status} /> <slot /> <span class={classes}><StatusIcon {preferences} {status} /> <slot /></span>
{/if} {/if}

View file

@ -146,7 +146,7 @@
<h3>Names</h3> <h3>Names</h3>
<ul class="list-unstyled fs-5"> <ul class="list-unstyled fs-5">
{#each data.names as name} {#each data.names as name}
<li><StatusLine status={name.status}>{name.value}</StatusLine></li> <li><StatusLine preferences={data.custom_preferences} status={name.status}>{name.value}</StatusLine></li>
{/each} {/each}
</ul> </ul>
</div> </div>
@ -156,14 +156,14 @@
<h3>Pronouns</h3> <h3>Pronouns</h3>
<ul class="list-unstyled fs-5"> <ul class="list-unstyled fs-5">
{#each data.pronouns as pronouns} {#each data.pronouns as pronouns}
<li><StatusLine status={pronouns.status}><PronounLink {pronouns} /></StatusLine></li> <li><StatusLine preferences={data.custom_preferences} status={pronouns.status}><PronounLink {pronouns} /></StatusLine></li>
{/each} {/each}
</ul> </ul>
</div> </div>
{/if} {/if}
{#each data.fields as field} {#each data.fields as field}
<div class="col"> <div class="col">
<FieldCard {field} /> <FieldCard preferences={data.custom_preferences} {field} />
</div> </div>
{/each} {/each}
</div> </div>

View file

@ -81,7 +81,7 @@
<h3>Names</h3> <h3>Names</h3>
<ul class="list-unstyled fs-5"> <ul class="list-unstyled fs-5">
{#each data.names as name} {#each data.names as name}
<li><StatusLine status={name.status}>{name.value}</StatusLine></li> <li><StatusLine preferences={data.user.custom_preferences} status={name.status}>{name.value}</StatusLine></li>
{/each} {/each}
</ul> </ul>
</div> </div>
@ -91,14 +91,14 @@
<h3>Pronouns</h3> <h3>Pronouns</h3>
<ul class="list-unstyled fs-5"> <ul class="list-unstyled fs-5">
{#each data.pronouns as pronouns} {#each data.pronouns as pronouns}
<li><StatusLine status={pronouns.status}><PronounLink {pronouns} /></StatusLine></li> <li><StatusLine preferences={data.user.custom_preferences} status={pronouns.status}><PronounLink {pronouns} /></StatusLine></li>
{/each} {/each}
</ul> </ul>
</div> </div>
{/if} {/if}
{#each data.fields as field} {#each data.fields as field}
<div class="col"> <div class="col">
<FieldCard {field} /> <FieldCard preferences={data.user.custom_preferences} {field} />
</div> </div>
{/each} {/each}
</div> </div>