feat: Add Enum preference type support

This commit is contained in:
Jesse Wierzbinski 2024-12-04 14:34:09 +01:00
parent ca824a2a1a
commit dca7af4b0e
No known key found for this signature in database
10 changed files with 149 additions and 4 deletions

View file

@ -0,0 +1,46 @@
<template>
<Card class="grid grid-cols-[1fr,auto] items-center p-6 gap-2">
<CardHeader class="space-y-0.5 p-0">
<CardTitle class="text-base">
{{ setting.title }}
</CardTitle>
<CardDescription>
{{ setting.description }}
</CardDescription>
</CardHeader>
<CardFooter class="p-0">
<Select :model-value="setting.value" @update:model-value="v => { setting.value = v }">
<SelectTrigger>
<SelectValue placeholder="Select an option" />
</SelectTrigger>
<SelectContent>
<SelectItem v-for="option of setting.options" :value="option.value">
{{ option.label }}
</SelectItem>
</SelectContent>
</Select>
</CardFooter>
</Card>
</template>
<script lang="ts" setup>
import {
Card,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "~/components/ui/card";
import type { EnumSetting } from "~/settings.ts";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "../ui/select";
defineModel<EnumSetting>("setting", {
required: true,
});
</script>

View file

@ -1,5 +1,5 @@
<template> <template>
<Card class="grid grid-cols-[1fr,auto] items-center p-6"> <Card class="grid grid-cols-[1fr,auto] items-center p-6 gap-2">
<CardHeader class="space-y-0.5 p-0"> <CardHeader class="space-y-0.5 p-0">
<CardTitle class="text-base"> <CardTitle class="text-base">
{{ setting.title }} {{ setting.title }}

View file

@ -1,5 +1,5 @@
<template> <template>
<Avatar shape="square"> <Avatar :shape="(shape.value as 'circle' | 'square')">
<AvatarFallback v-if="name"> <AvatarFallback v-if="name">
{{ getInitials(name) }} {{ getInitials(name) }}
</AvatarFallback> </AvatarFallback>
@ -8,6 +8,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { SettingIds } from "~/settings";
import { Avatar, AvatarFallback, AvatarImage } from "../ui/avatar"; import { Avatar, AvatarFallback, AvatarImage } from "../ui/avatar";
const { name } = defineProps<{ const { name } = defineProps<{
@ -28,4 +29,6 @@ const getInitials = (name: string): string => {
return `${firstLetter}${secondLetter}`.toUpperCase(); return `${firstLetter}${secondLetter}`.toUpperCase();
}; };
const shape = useSetting(SettingIds.AvatarShape);
</script> </script>

View file

@ -13,8 +13,11 @@ import {
SidebarProvider, SidebarProvider,
SidebarTrigger, SidebarTrigger,
} from "~/components/ui/sidebar"; } from "~/components/ui/sidebar";
import { SettingIds } from "~/settings";
import LeftSidebar from "./left-sidebar.vue"; import LeftSidebar from "./left-sidebar.vue";
import RightSidebar from "./right-sidebar.vue"; import RightSidebar from "./right-sidebar.vue";
const showRightSidebar = useSetting(SettingIds.NotificationsSidebar);
</script> </script>
<template> <template>
@ -45,6 +48,6 @@ import RightSidebar from "./right-sidebar.vue";
<slot /> <slot />
</div> </div>
</SidebarInset> </SidebarInset>
<RightSidebar v-if="identity" /> <RightSidebar v-if="identity" v-show="showRightSidebar.value" />
</SidebarProvider> </SidebarProvider>
</template> </template>

View file

@ -0,0 +1,34 @@
<template>
<Timeline type="status" :items="(items as Status[])" :is-loading="isLoading" :has-reached-end="hasReachedEnd"
:error="error" :load-next="loadNext" :load-prev="loadPrev" :remove-item="removeItem"
:update-item="updateItem" />
</template>
<script lang="ts" setup>
import type { Status } from "@versia/client/types";
import { useGlobalTimeline } from "~/composables/GlobalTimeline";
import Timeline from "./timeline.vue";
const {
error,
hasReachedEnd,
isLoading,
items,
loadNext,
loadPrev,
removeItem,
updateItem,
} = useGlobalTimeline(client.value);
useListen("note:delete", ({ id }) => {
removeItem(id);
});
useListen("note:edit", (updatedNote) => {
updateItem(updatedNote);
});
useListen("composer:send", () => {
loadPrev();
});
</script>

View file

@ -2,7 +2,7 @@
<template> <template>
<div class="timeline rounded"> <div class="timeline rounded">
<TransitionGroup name="timeline-item" tag="div" <TransitionGroup name="timeline-item" tag="div"
class="timeline-items *:rounded space-y-4 *:border *:border-border/50"> class="timeline-items *:rounded space-y-4 *:border">
<TimelineItem :type="type" v-for="item in items" :key="item.id" :item="item" @update="updateItem" <TimelineItem :type="type" v-for="item in items" :key="item.id" :item="item" @update="updateItem"
@delete="removeItem" /> @delete="removeItem" />
</TransitionGroup> </TransitionGroup>

View file

@ -0,0 +1,14 @@
import type { Client } from "@versia/client";
import type { Status } from "@versia/client/types";
import { type TimelineOptions, useTimeline } from "./Timeline";
export function useGlobalTimeline(
client: Client,
options: Partial<TimelineOptions<Status>> = {},
) {
return useTimeline(client, {
// TODO: Implement global timeline in client sdk
fetchFunction: (client, opts) => client.getPublicTimeline(opts),
...options,
});
}

16
pages/global.vue Normal file
View file

@ -0,0 +1,16 @@
<template>
<div class="mx-auto max-w-2xl w-full">
<TimelineScroller>
<Global />
</TimelineScroller>
</div>
</template>
<script setup lang="ts">
import Global from "~/components/timelines/global.vue";
import TimelineScroller from "~/components/timelines/timeline-scroller.vue";
definePageMeta({
layout: "app",
});
</script>

View file

@ -6,15 +6,18 @@
<div class="grid grid-cols-1 2xl:grid-cols-2 gap-4 mt-6"> <div class="grid grid-cols-1 2xl:grid-cols-2 gap-4 mt-6">
<template v-for="[id, setting] of settingEntries"> <template v-for="[id, setting] of settingEntries">
<SwitchPreference v-if="setting.type === SettingType.Boolean" :setting="(setting as BooleanSetting)" @update:setting="updateSetting(id, setting)" /> <SwitchPreference v-if="setting.type === SettingType.Boolean" :setting="(setting as BooleanSetting)" @update:setting="updateSetting(id, setting)" />
<SelectPreference v-else-if="setting.type === SettingType.Enum" :setting="(setting as EnumSetting)" @update:setting="updateSetting(id, setting)" />
</template> </template>
</div> </div>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import SelectPreference from "~/components/preferences/select.vue";
import SwitchPreference from "~/components/preferences/switch.vue"; import SwitchPreference from "~/components/preferences/switch.vue";
import { import {
type BooleanSetting, type BooleanSetting,
type EnumSetting,
type Setting, type Setting,
type SettingIds, type SettingIds,
type SettingPages, type SettingPages,

View file

@ -80,6 +80,8 @@ export enum SettingIds {
CtrlEnterToSend = "ctrl-enter-to-send", CtrlEnterToSend = "ctrl-enter-to-send",
EmojiTheme = "emoji-theme", EmojiTheme = "emoji-theme",
BackgroundURL = "background-url", BackgroundURL = "background-url",
NotificationsSidebar = "notifications-sidebar",
AvatarShape = "avatar-shape",
} }
export const settings: Record<SettingIds, Setting> = { export const settings: Record<SettingIds, Setting> = {
@ -91,6 +93,23 @@ export const settings: Record<SettingIds, Setting> = {
page: SettingPages.Behaviour, page: SettingPages.Behaviour,
notImplemented: true, notImplemented: true,
} as BooleanSetting, } as BooleanSetting,
[SettingIds.AvatarShape]: {
title: "Avatar Shape",
description: "Shape of all user avatars.",
type: SettingType.Enum,
value: "square",
options: [
{
value: "circle",
label: "Round",
},
{
value: "square",
label: "Square",
},
],
page: SettingPages.Appearance,
} as EnumSetting,
[SettingIds.CustomCSS]: { [SettingIds.CustomCSS]: {
title: "Custom CSS", title: "Custom CSS",
description: "Custom CSS for the UI.", description: "Custom CSS for the UI.",
@ -222,6 +241,13 @@ export const settings: Record<SettingIds, Setting> = {
value: "", value: "",
page: SettingPages.Appearance, page: SettingPages.Appearance,
} as StringSetting, } as StringSetting,
[SettingIds.NotificationsSidebar]: {
title: "Notifications Sidebar",
description: "Display a sidebar with notifications on desktop.",
type: SettingType.Boolean,
value: true,
page: SettingPages.Appearance,
} as BooleanSetting,
}; };
export const getSettingsForPage = (page: SettingPages): Partial<Settings> => { export const getSettingsForPage = (page: SettingPages): Partial<Settings> => {