mirror of
https://github.com/versia-pub/frontend.git
synced 2025-12-06 08:28:20 +01:00
refactor: 🔥 Clean up codebase
This commit is contained in:
parent
1b5e7a6575
commit
ee8c543cd9
10
app.vue
10
app.vue
|
|
@ -20,7 +20,7 @@ import { convert } from "html-to-text";
|
||||||
import "iconify-icon";
|
import "iconify-icon";
|
||||||
import ConfirmationModal from "./components/modals/confirm.vue";
|
import ConfirmationModal from "./components/modals/confirm.vue";
|
||||||
import { Toaster } from "./components/ui/sonner";
|
import { Toaster } from "./components/ui/sonner";
|
||||||
import { SettingIds } from "./settings";
|
import { type EnumSetting, SettingIds } from "./settings";
|
||||||
// Sin
|
// Sin
|
||||||
//import "~/styles/mcdonalds.css";
|
//import "~/styles/mcdonalds.css";
|
||||||
|
|
||||||
|
|
@ -31,6 +31,14 @@ const description = useExtendedDescription(client);
|
||||||
const customCss = useSetting(SettingIds.CustomCSS);
|
const customCss = useSetting(SettingIds.CustomCSS);
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|
||||||
|
// Theme switcher
|
||||||
|
const theme = useSetting(SettingIds.Theme) as Ref<EnumSetting>;
|
||||||
|
const colorMode = useColorMode();
|
||||||
|
|
||||||
|
watch(theme.value, () => {
|
||||||
|
colorMode.preference = theme.value.value;
|
||||||
|
});
|
||||||
|
|
||||||
useSeoMeta({
|
useSeoMeta({
|
||||||
titleTemplate: (titleChunk) => {
|
titleTemplate: (titleChunk) => {
|
||||||
return titleChunk ? `${titleChunk} · Versia` : "Versia";
|
return titleChunk ? `${titleChunk} · Versia` : "Versia";
|
||||||
|
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
<template>
|
|
||||||
<ButtonBase class="enabled:hover:bg-white/20 text-sm !rounded-sm !ring-0 !py-3 sm:!py-1.5 sm:!px-2 !justify-start">
|
|
||||||
<Icon :icon="icon" />
|
|
||||||
<slot />
|
|
||||||
</ButtonBase>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import type { ButtonHTMLAttributes } from "vue";
|
|
||||||
import ButtonBase from "~/packages/ui/components/buttons/button.vue";
|
|
||||||
import Icon from "~/packages/ui/components/icons/icon.vue";
|
|
||||||
|
|
||||||
interface Props extends /* @vue-ignore */ ButtonHTMLAttributes {}
|
|
||||||
|
|
||||||
defineProps<
|
|
||||||
Props & {
|
|
||||||
icon: string;
|
|
||||||
}
|
|
||||||
>();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style></style>
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
<template>
|
|
||||||
<ButtonBase class="hover:bg-white/5 text-xs max-w-full w-full h-full !p-0">
|
|
||||||
<Icon :icon="icon" class="!size-6" />
|
|
||||||
</ButtonBase>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import ButtonBase from "~/packages/ui/components/buttons/button.vue";
|
|
||||||
import Icon from "~/packages/ui/components/icons/icon.vue";
|
|
||||||
|
|
||||||
defineProps<{
|
|
||||||
icon: string;
|
|
||||||
text: string;
|
|
||||||
}>();
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,64 +0,0 @@
|
||||||
<template>
|
|
||||||
<Menu.Root :positioning="{
|
|
||||||
strategy: 'fixed',
|
|
||||||
}" @update:open="(o) => open = o" :open="open">
|
|
||||||
<Menu.Trigger :as-child="true">
|
|
||||||
<slot name="button"></slot>
|
|
||||||
</Menu.Trigger>
|
|
||||||
|
|
||||||
<Teleport to="body">
|
|
||||||
<div @mousedown="open = false" @touchstart="open = false" v-if="open"
|
|
||||||
class="fixed inset-0 z-10 bg-black/50">
|
|
||||||
</div>
|
|
||||||
<Menu.Positioner :class="isSmallScreen && '!bottom-0 !top-[unset] fixed inset-x-0 w-full !translate-y-0'">
|
|
||||||
<transition enter-active-class="transition ease-in duration-100"
|
|
||||||
enter-from-class="transform opacity-0 translate-y-full sm:translate-y-0 scale-95"
|
|
||||||
enter-to-class="transform translate-y-0 opacity-100 scale-100"
|
|
||||||
leave-active-class="transition ease-out duration-75"
|
|
||||||
leave-from-class="transform opacity-100 scale-100" leave-to-class="transform opacity-0 scale-95">
|
|
||||||
<Menu.Content v-if="open"
|
|
||||||
:class="['z-20 mt-2 rounded overflow-hidden p-1 space-y-1 bg-dark-700 shadow-lg ring-1 ring-white/10 focus:outline-none min-w-56', id]">
|
|
||||||
<div v-if="isSmallScreen" class="w-full py-2">
|
|
||||||
<div class="rounded-full h-1 bg-gray-400 w-12 mx-auto"></div>
|
|
||||||
</div>
|
|
||||||
<slot name="items"></slot>
|
|
||||||
</Menu.Content>
|
|
||||||
</transition>
|
|
||||||
</Menu.Positioner>
|
|
||||||
</Teleport>
|
|
||||||
</Menu.Root>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { Menu } from "@ark-ui/vue";
|
|
||||||
const { width } = useWindowSize();
|
|
||||||
const isSmallScreen = computed(() => width.value < 768);
|
|
||||||
|
|
||||||
const open = ref(false);
|
|
||||||
const id = useId();
|
|
||||||
|
|
||||||
// HACK: Fix the menu children not reacting to touch events as click for some reason
|
|
||||||
const registerClickHandlers = () => {
|
|
||||||
const targetElements = document.querySelectorAll(`.${id} [data-part=item]`);
|
|
||||||
for (const el of targetElements) {
|
|
||||||
el.addEventListener("touchstart", (e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
e.preventDefault();
|
|
||||||
// Click all element children
|
|
||||||
for (const elChild of Array.from(el.children)) {
|
|
||||||
if (elChild instanceof HTMLElement) {
|
|
||||||
elChild.click();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// When opening, register click handlers
|
|
||||||
watch(open, async (o) => {
|
|
||||||
if (o) {
|
|
||||||
await nextTick();
|
|
||||||
registerClickHandlers();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
<template>
|
|
||||||
<TextInput type="checkbox" v-bind="$attrs, $props"
|
|
||||||
class="rounded disabled:hover:cursor-wait text-primary2-700 !size-5" />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import type { InputHTMLAttributes } from "vue";
|
|
||||||
import TextInput from "./text-input.vue";
|
|
||||||
|
|
||||||
interface Props extends /* @vue-ignore */ InputHTMLAttributes {}
|
|
||||||
|
|
||||||
defineProps<Props>();
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
<template>
|
|
||||||
<Renderer :id="id" v-for="id of settingsIds" :key="id" />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import {
|
|
||||||
type SettingIds,
|
|
||||||
type SettingPages,
|
|
||||||
getSettingsForPage,
|
|
||||||
} from "~/settings";
|
|
||||||
import Renderer from "./renderer.vue";
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
page: SettingPages;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const settingsIds = Object.keys(getSettingsForPage(props.page)) as SettingIds[];
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="w-full px-8 py-4 bg-dark-700 hover:bg-dark-500 duration-100 h-full">
|
|
||||||
<div class="max-w-7xl mx-auto h-full">
|
|
||||||
<SettingBoolean v-if="setting.type === SettingType.Boolean" :id="id" />
|
|
||||||
|
|
||||||
<SettingCode v-else-if="setting.type === SettingType.Code" :id="id" />
|
|
||||||
<SettingEnum v-else-if="setting.type === SettingType.Enum" :id="id" />
|
|
||||||
<SettingString v-else-if="setting.type === SettingType.String" :id="id" />
|
|
||||||
<SettingOther v-else :id="id" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { type SettingIds, SettingType } from "~/settings";
|
|
||||||
import SettingBoolean from "./types/Boolean.vue";
|
|
||||||
import SettingCode from "./types/Code.vue";
|
|
||||||
import SettingEnum from "./types/Enum.vue";
|
|
||||||
import SettingOther from "./types/Other.vue";
|
|
||||||
import SettingString from "./types/String.vue";
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
id: SettingIds;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const setting = useSetting(props.id);
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
<template>
|
|
||||||
<Switch.Root v-model:checked="checked" class="grid grid-cols-[1fr_auto] gap-x-4"
|
|
||||||
@click="setting.notImplemented ? $event.preventDefault() : undefined"
|
|
||||||
v-if="setting.type === SettingType.Boolean" @update:checked="c => checked = c">
|
|
||||||
<Switch.Label :data-disabled="setting.notImplemented ? '' : undefined"
|
|
||||||
class="row-start-1 select-none text-base/6 data-[disabled]:opacity-50 sm:text-sm/6 text-white font-semibold">
|
|
||||||
{{
|
|
||||||
setting.title
|
|
||||||
}}</Switch.Label>
|
|
||||||
<p v-if="setting.notImplemented" class="text-xs mt-1 row-start-3 text-red-300 font-semibold">Not
|
|
||||||
implemented
|
|
||||||
</p>
|
|
||||||
<p v-else :data-disabled="setting.notImplemented ? '' : undefined"
|
|
||||||
class="text-base/6 row-start-2 data-[disabled]:opacity-50 sm:text-sm/6 text-gray-300">{{
|
|
||||||
setting.description }}
|
|
||||||
</p>
|
|
||||||
<Switch.Control :data-disabled="setting.notImplemented ? '' : undefined"
|
|
||||||
:data-checked="checked ? '' : undefined"
|
|
||||||
class="group col-start-2 relative isolate inline-flex h-6 w-10 cursor-default rounded-full p-[3px] sm:h-5 sm:w-8 transition duration-0 ease-in-out data-[changing]:duration-200 forced-colors:outline forced-colors:[--switch-bg:Highlight] ring-1 ring-inset bg-white/5 ring-white/15 data-[checked]:bg-[--switch-bg] data-[checked]:ring-[--switch-bg-ring] focus:outline-none focus:outline focus:outline-2 focus:outline-offset-2 focus:outline-blue-500 hover:data-[checked]:ring-[--switch-bg-ring] hover:ring-white/25 data-[disabled]:bg-zinc-200 data-[disabled]:data-[checked]:bg-zinc-200 data-[disabled]:opacity-50 data-[disabled]:bg-white/15 data-[disabled]:data-[checked]:bg-white/15 data-[disabled]:data-[checked]:ring-white/15 [--switch-bg-ring:transparent] [--switch-bg:theme(colors.primary.600/25%)] [--switch-shadow:theme(colors.black/10%)] [--switch:white] [--switch-ring:theme(colors.white/10%)]">
|
|
||||||
<Switch.Thumb
|
|
||||||
class="pointer-events-none relative inline-block size-[1.125rem] rounded-full sm:size-3.5 translate-x-0 transition duration-200 ease-in-out border border-transparent bg-white shadow ring-1 ring-black/5 group-data-[checked]:bg-[--switch] group-data-[checked]:shadow-[--switch-shadow] group-data-[checked]:ring-[--switch-ring] group-data-[checked]:translate-x-4 sm:group-data-[checked]:translate-x-3 group-data-[disabled]:group-data-[checked]:bg-white group-data-[disabled]:group-data-[checked]:shadow group-data-[disabled]:group-data-[checked]:ring-black/5" />
|
|
||||||
</Switch.Control>
|
|
||||||
<Switch.HiddenInput />
|
|
||||||
</Switch.Root>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { Switch } from "@ark-ui/vue";
|
|
||||||
import { type SettingIds, SettingType } from "~/settings";
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
id: SettingIds;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const setting = useSetting(props.id);
|
|
||||||
const checked = ref(setting.value.value as boolean);
|
|
||||||
|
|
||||||
watch(checked, (c) => {
|
|
||||||
setting.value.value = c;
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="flex flex-col gap-y-1">
|
|
||||||
<h4 class="row-start-1 select-none text-base/6 sm:text-sm/6 text-white font-semibold">{{ setting.title
|
|
||||||
}}
|
|
||||||
</h4>
|
|
||||||
<textarea v-model="content"
|
|
||||||
class="resize-none min-h-48 mt-1 prose prose-invert max-w-full ring-1 ring-white/20 font-mono placeholder:text-zinc-500 bg-transparent rounded appearance-none disabled:cursor-not-allowed"
|
|
||||||
aria-label="Start typing here..."></textarea>
|
|
||||||
<p v-if="setting.description" class="text-xs mt-2 text-gray-400">{{ setting.description }}</p>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import type { SettingIds } from "~/settings";
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
id: SettingIds;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const setting = useSetting(props.id);
|
|
||||||
const content = ref(setting.value.value as string);
|
|
||||||
|
|
||||||
watch(content, (c) => {
|
|
||||||
setting.value.value = c;
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,64 +0,0 @@
|
||||||
<template>
|
|
||||||
<Select.Root :collection="collection" v-model:model-value="selectedValues">
|
|
||||||
<Select.Label class="select-none text-base/6 data-[disabled]:opacity-50 sm:text-sm/6 text-white font-semibold">{{ setting.title }}</Select.Label>
|
|
||||||
<Select.Control class="mt-1">
|
|
||||||
<Select.Trigger :disabled="setting.notImplemented" class="disabled:opacity-70 disabled:hover:cursor-not-allowed bg-dark-500 rounded-md border-0 py-1.5 text-gray-50 shadow-sm ring-1 ring-inset ring-white/10 sm:text-sm sm:leading-6 w-full md:w-auto min-w-72 text-left px-4 flex flew-row justify-between items-center">
|
|
||||||
<Select.ValueText placeholder="Select an option" />
|
|
||||||
<Select.Indicator class="size-4">
|
|
||||||
<iconify-icon icon="tabler:chevron-down" class="size-4" width="unset" aria-hidden="true" />
|
|
||||||
</Select.Indicator>
|
|
||||||
</Select.Trigger>
|
|
||||||
</Select.Control>
|
|
||||||
<p v-if="setting.notImplemented" class="text-xs mt-2 row-start-3 text-red-300 font-semibold">Not
|
|
||||||
implemented
|
|
||||||
</p>
|
|
||||||
<p v-else-if="setting.description" class="text-xs mt-2 text-gray-400">{{ setting.description }}</p>
|
|
||||||
<Teleport to="body">
|
|
||||||
<Select.Positioner>
|
|
||||||
<Select.Content
|
|
||||||
class="z-10 mt-1 max-h-56 w-full overflow-auto rounded-md bg-dark-700 py-1 text-base shadow-lg ring-1 ring-white/10 focus:outline-none sm:text-sm min-w-72">
|
|
||||||
<Select.ItemGroup>
|
|
||||||
<Select.Item v-for="item in collection.items" :key="item.value" :item="item"
|
|
||||||
:class="['text-gray-100 hover:bg-dark-900 flex flex-row gap-4 justify-between items-center duration-100 relative cursor-default select-none py-2 px-4 group']">
|
|
||||||
<Select.ItemText
|
|
||||||
:class="['group-data-[state=checked]:font-semibold font-normal block truncate']">{{
|
|
||||||
item.label }}</Select.ItemText>
|
|
||||||
<Select.ItemIndicator
|
|
||||||
:class="['text-primary2-600 hidden group-data-[state=checked]:flex items-center justify-center']">
|
|
||||||
<iconify-icon icon="tabler:check" class="size-4" width="unset" aria-hidden="true" />
|
|
||||||
</Select.ItemIndicator>
|
|
||||||
</Select.Item>
|
|
||||||
</Select.ItemGroup>
|
|
||||||
</Select.Content>
|
|
||||||
</Select.Positioner>
|
|
||||||
</Teleport>
|
|
||||||
<Select.HiddenSelect />
|
|
||||||
</Select.Root>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { Select, createListCollection } from "@ark-ui/vue/select";
|
|
||||||
import type { EnumSetting, SettingIds } from "~/settings";
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
id: SettingIds;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const setting = useSetting(props.id) as Ref<EnumSetting>;
|
|
||||||
const selectedValues = ref([setting.value.value]);
|
|
||||||
|
|
||||||
const collection = createListCollection({
|
|
||||||
items: setting.value.options.map((option) => ({
|
|
||||||
value: option.value,
|
|
||||||
label: option.label,
|
|
||||||
})),
|
|
||||||
});
|
|
||||||
|
|
||||||
watch(selectedValues, (value) => {
|
|
||||||
if (!value[0]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setting.value.value = value[0];
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="grid grid-cols-[1fr_auto] gap-x-4">
|
|
||||||
<h4 class="row-start-1 select-none text-base/6 sm:text-sm/6 text-white font-semibold">{{ setting.title
|
|
||||||
}}
|
|
||||||
</h4>
|
|
||||||
<p class="text-xs mt-1 row-start-3 text-red-300 font-semibold">Not implemented</p>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import type { SettingIds } from "~/settings";
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
id: SettingIds;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const setting = useSetting(props.id);
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="flex flex-col gap-y-1">
|
|
||||||
<h4 class="row-start-1 select-none text-base/6 sm:text-sm/6 text-white font-semibold">{{ setting.title
|
|
||||||
}}
|
|
||||||
</h4>
|
|
||||||
<TextInput v-model:value="content" class="w-full md:w-auto min-w-72" />
|
|
||||||
<p v-if="setting.description" class="text-xs mt-2 text-gray-400">{{ setting.description }}</p>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import TextInput from "~/components/inputs/text-input.vue";
|
|
||||||
import type { SettingIds } from "~/settings";
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
id: SettingIds;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const setting = useSetting(props.id);
|
|
||||||
const content = ref(setting.value.value as string);
|
|
||||||
|
|
||||||
watch(content, (c) => {
|
|
||||||
setting.value.value = c;
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
@ -66,9 +66,6 @@
|
||||||
</SidebarContent>
|
</SidebarContent>
|
||||||
<SidebarFooter>
|
<SidebarFooter>
|
||||||
<SidebarMenu class="gap-3">
|
<SidebarMenu class="gap-3">
|
||||||
<SidebarMenuItem>
|
|
||||||
<ThemeSwitcher />
|
|
||||||
</SidebarMenuItem>
|
|
||||||
<SidebarMenuItem>
|
<SidebarMenuItem>
|
||||||
<AccountSwitcher />
|
<AccountSwitcher />
|
||||||
</SidebarMenuItem>
|
</SidebarMenuItem>
|
||||||
|
|
@ -125,7 +122,6 @@ import {
|
||||||
import Avatar from "../profiles/avatar.vue";
|
import Avatar from "../profiles/avatar.vue";
|
||||||
import { Button } from "../ui/button";
|
import { Button } from "../ui/button";
|
||||||
import AccountSwitcher from "./account-switcher.vue";
|
import AccountSwitcher from "./account-switcher.vue";
|
||||||
import ThemeSwitcher from "./theme-switcher.vue";
|
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
navMain: [
|
navMain: [
|
||||||
|
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
<template>
|
|
||||||
<Tabs.Root v-model="tab" class="bg-dark-700 h-full overflow-auto pb-20">
|
|
||||||
<Tabs.List class="flex flex-row p-4 gap-4 bg-dark-800 relative ring-1 ring-white/5 overflow-x-auto">
|
|
||||||
<Tabs.Trigger :value="page"
|
|
||||||
v-for="page of SettingPages"
|
|
||||||
:as-child="true">
|
|
||||||
<ButtonBase class="capitalize hover:bg-white/5">
|
|
||||||
{{ page }}
|
|
||||||
</ButtonBase>
|
|
||||||
</Tabs.Trigger>
|
|
||||||
<Tabs.Indicator class="h-1 bg-gray-300 w-[--width] top-0 rounded-b" />
|
|
||||||
</Tabs.List>
|
|
||||||
<Tabs.Content :value="page" v-for="page of SettingPages">
|
|
||||||
<slot :name="page" />
|
|
||||||
</Tabs.Content>
|
|
||||||
</Tabs.Root>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { Tabs } from "@ark-ui/vue";
|
|
||||||
import ButtonBase from "~/packages/ui/components/buttons/button.vue";
|
|
||||||
import { SettingPages } from "~/settings";
|
|
||||||
|
|
||||||
const tab = ref<SettingPages>(
|
|
||||||
(window.location.hash.slice(1) as SettingPages) || SettingPages.Account,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Update page hash when tab changes
|
|
||||||
watch(
|
|
||||||
tab,
|
|
||||||
(value) => {
|
|
||||||
window.location.hash = value;
|
|
||||||
},
|
|
||||||
{ immediate: true },
|
|
||||||
);
|
|
||||||
</script>
|
|
||||||
|
|
@ -36,7 +36,7 @@
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<div v-else-if="!infiniteScroll.value" class="py-10 px-4">
|
<div v-else-if="!infiniteScroll.value" class="py-10 px-4">
|
||||||
<Button theme="secondary" @click="loadNext" :disabled="isLoading" class="w-full">
|
<Button variant="secondary" @click="loadNext" :disabled="isLoading" class="w-full">
|
||||||
Load More
|
Load More
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -55,8 +55,8 @@ import {
|
||||||
CardHeader,
|
CardHeader,
|
||||||
CardTitle,
|
CardTitle,
|
||||||
} from "~/components/ui/card";
|
} from "~/components/ui/card";
|
||||||
import Button from "~/packages/ui/components/buttons/button.vue";
|
|
||||||
import { SettingIds } from "~/settings";
|
import { SettingIds } from "~/settings";
|
||||||
|
import { Button } from "../ui/button";
|
||||||
import TimelineItem from "./timeline-item.vue";
|
import TimelineItem from "./timeline-item.vue";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
||||||
v-if="!props.hideClose"
|
v-if="!props.hideClose"
|
||||||
class="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground"
|
class="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground"
|
||||||
>
|
>
|
||||||
<X class="w-4 h-4" />
|
<X class="size-4" />
|
||||||
<span class="sr-only">Close</span>
|
<span class="sr-only">Close</span>
|
||||||
</DialogClose>
|
</DialogClose>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
||||||
<DialogClose
|
<DialogClose
|
||||||
class="absolute top-3 right-3 p-0.5 transition-colors rounded-md hover:bg-secondary"
|
class="absolute top-3 right-3 p-0.5 transition-colors rounded-md hover:bg-secondary"
|
||||||
>
|
>
|
||||||
<X class="w-4 h-4" />
|
<X class="size-4" />
|
||||||
<span class="sr-only">Close</span>
|
<span class="sr-only">Close</span>
|
||||||
</DialogClose>
|
</DialogClose>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
||||||
>
|
>
|
||||||
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||||
<DropdownMenuItemIndicator>
|
<DropdownMenuItemIndicator>
|
||||||
<Check class="w-4 h-4" />
|
<Check class="size-4" />
|
||||||
</DropdownMenuItemIndicator>
|
</DropdownMenuItemIndicator>
|
||||||
</span>
|
</span>
|
||||||
<slot />
|
<slot />
|
||||||
|
|
|
||||||
|
|
@ -19,5 +19,5 @@ const modelValue = useVModel(props, "modelValue", emits, {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<input v-model="modelValue" :class="cn('flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground !outline-none focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50', props.class)">
|
<input v-model="modelValue" :class="cn('flex h-10 w-full rounded-md border !border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus:ring-0 focus:ring-offset-0 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50', props.class)">
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ const forwardedProps = useForwardProps(delegatedProps);
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
<SelectIcon as-child>
|
<SelectIcon as-child>
|
||||||
<ChevronDown class="w-4 h-4 opacity-50 shrink-0" />
|
<ChevronDown class="size-4 opacity-50 shrink-0" />
|
||||||
</SelectIcon>
|
</SelectIcon>
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
||||||
<DialogClose
|
<DialogClose
|
||||||
class="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary"
|
class="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary"
|
||||||
>
|
>
|
||||||
<X class="w-4 h-4 text-muted-foreground" />
|
<X class="size-4 text-muted-foreground" />
|
||||||
</DialogClose>
|
</DialogClose>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</DialogPortal>
|
</DialogPortal>
|
||||||
|
|
|
||||||
|
|
@ -47,12 +47,12 @@ const { error, error_description } = useUrlSearchParams();
|
||||||
<div class="lg:p-8 w-full max-w-xl">
|
<div class="lg:p-8 w-full max-w-xl">
|
||||||
<div class="mx-auto flex w-full flex-col justify-center space-y-10 sm:w-[350px]">
|
<div class="mx-auto flex w-full flex-col justify-center space-y-10 sm:w-[350px]">
|
||||||
<Alert v-if="error" variant="destructive" class="mb-4">
|
<Alert v-if="error" variant="destructive" class="mb-4">
|
||||||
<AlertCircle class="w-4 h-4" />
|
<AlertCircle class="size-4" />
|
||||||
<AlertTitle>{{ error }}</AlertTitle>
|
<AlertTitle>{{ error }}</AlertTitle>
|
||||||
<AlertDescription>
|
<AlertDescription>
|
||||||
{{ error_description }}
|
{{ error_description }}
|
||||||
</AlertDescription>
|
</AlertDescription>
|
||||||
</Alert>
|
</Alert>
|
||||||
<div class="flex flex-col space-y-2 text-center">
|
<div class="flex flex-col space-y-2 text-center">
|
||||||
<h1 class="text-2xl font-semibold tracking-tight">
|
<h1 class="text-2xl font-semibold tracking-tight">
|
||||||
Log in to your account.
|
Log in to your account.
|
||||||
|
|
|
||||||
|
|
@ -19,14 +19,14 @@
|
||||||
<form method="POST" action="/api/auth/reset" @submit="form.submitForm">
|
<form method="POST" action="/api/auth/reset" @submit="form.submitForm">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<Alert v-if="params.login_reset" variant="default" class="mb-4">
|
<Alert v-if="params.login_reset" variant="default" class="mb-4">
|
||||||
<AlertCircle class="w-4 h-4" />
|
<AlertCircle class="size-4" />
|
||||||
<AlertTitle>Info</AlertTitle>
|
<AlertTitle>Info</AlertTitle>
|
||||||
<AlertDescription>
|
<AlertDescription>
|
||||||
Your password has been reset by an administrator. Please change it here.
|
Your password has been reset by an administrator. Please change it here.
|
||||||
</AlertDescription>
|
</AlertDescription>
|
||||||
</Alert>
|
</Alert>
|
||||||
<Alert v-if="params.error" variant="destructive" class="mb-4">
|
<Alert v-if="params.error" variant="destructive" class="mb-4">
|
||||||
<AlertCircle class="w-4 h-4" />
|
<AlertCircle class="size-4" />
|
||||||
<AlertTitle>{{ params.error }}</AlertTitle>
|
<AlertTitle>{{ params.error }}</AlertTitle>
|
||||||
<AlertDescription>
|
<AlertDescription>
|
||||||
{{ params.error_description }}
|
{{ params.error_description }}
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,6 @@ export const settings: Record<SettingIds, Setting> = {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
page: SettingPages.Appearance,
|
page: SettingPages.Appearance,
|
||||||
notImplemented: true,
|
|
||||||
} as EnumSetting,
|
} as EnumSetting,
|
||||||
[SettingIds.CustomEmojis]: {
|
[SettingIds.CustomEmojis]: {
|
||||||
title: "Render Custom Emojis",
|
title: "Render Custom Emojis",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue