chore: ⬆️ Upgrade to Nuxt 4
Some checks failed
CodeQL / Analyze (javascript) (push) Failing after 1s
Deploy to GitHub Pages / build (push) Failing after 1s
Deploy to GitHub Pages / deploy (push) Has been skipped
Docker / build (push) Failing after 1s
Mirror to Codeberg / Mirror (push) Failing after 1s

This commit is contained in:
Jesse Wierzbinski 2025-07-16 07:48:39 +02:00
parent 8debe97f63
commit 7f7cf20311
386 changed files with 2376 additions and 2332 deletions

View file

@ -0,0 +1,37 @@
<template>
<Timeline type="status" :items="items" :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 { z } from "zod";
import Timeline from "./timeline.vue";
const props = defineProps<{
id: string;
}>();
const {
error,
hasReachedEnd,
isLoading,
items,
loadNext,
loadPrev,
removeItem,
updateItem,
} = useAccountTimeline(client.value, props.id);
useListen("note:delete", ({ id }) => {
removeItem(id);
});
useListen("note:edit", (updatedNote) => {
updateItem(updatedNote);
});
useListen("composer:send", () => {
loadPrev();
});
</script>

View file

@ -0,0 +1,34 @@
<template>
<Timeline type="status" :items="items" :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 { z } from "zod";
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

@ -0,0 +1,33 @@
<template>
<Timeline type="status" :items="items" :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 { useHomeTimeline } from "~/composables/HomeTimeline";
import Timeline from "./timeline.vue";
import type { z } from "zod";
const {
error,
hasReachedEnd,
isLoading,
items,
loadNext,
loadPrev,
removeItem,
updateItem,
} = useHomeTimeline(client.value);
useListen("note:delete", ({ id }) => {
removeItem(id);
});
useListen("note:edit", (updatedNote) => {
updateItem(updatedNote);
});
useListen("composer:send", () => {
loadPrev();
});
</script>

View file

@ -0,0 +1,34 @@
<template>
<Timeline type="status" :items="items" :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 { z } from "zod";
import { useLocalTimeline } from "~/composables/LocalTimeline";
import Timeline from "./timeline.vue";
const {
error,
hasReachedEnd,
isLoading,
items,
loadNext,
loadPrev,
removeItem,
updateItem,
} = useLocalTimeline(client.value);
useListen("note:delete", ({ id }) => {
removeItem(id);
});
useListen("note:edit", (updatedNote) => {
updateItem(updatedNote);
});
useListen("composer:send", () => {
loadPrev();
});
</script>

View file

@ -0,0 +1,21 @@
<template>
<Timeline type="notification" :items="items" :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 { useNotificationTimeline } from "~/composables/NotificationTimeline";
import Timeline from "./timeline.vue";
const {
error,
hasReachedEnd,
isLoading,
items,
loadNext,
loadPrev,
removeItem,
updateItem,
} = useNotificationTimeline(client.value);
</script>

View file

@ -0,0 +1,33 @@
<template>
<Timeline type="status" :items="items" :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 { usePublicTimeline } from "~/composables/PublicTimeline";
import Timeline from "./timeline.vue";
const {
error,
hasReachedEnd,
isLoading,
items,
loadNext,
loadPrev,
removeItem,
updateItem,
} = usePublicTimeline(client.value);
useListen("note:delete", ({ id }) => {
removeItem(id);
});
useListen("note:edit", (updatedNote) => {
updateItem(updatedNote);
});
useListen("composer:send", () => {
loadPrev();
});
</script>

View file

@ -0,0 +1,28 @@
<template>
<component :is="itemComponent" :note="type === 'status' ? item : undefined" :notification="type === 'notification' ? item : (undefined as any)" @update="$emit('update', $event)"
@delete="$emit('delete', item?.id)" />
</template>
<script lang="ts" setup>
import type { Notification, Status } from "@versia/client/schemas";
import type { z } from "zod";
import Thread from "../notes/thread.vue";
import NotificationItem from "../notifications/notification.vue";
const props = defineProps<{
item?: z.infer<typeof Status> | z.infer<typeof Notification>;
type: "status" | "notification";
}>();
const itemComponent = computed(() => {
if (props.type === "status") {
return Thread;
}
if (props.type === "notification") {
return NotificationItem;
}
return null;
});
</script>

View file

@ -0,0 +1,26 @@
<template>
<slot />
</template>
<script lang="ts" setup>
const root = useParentElement(useParentElement());
// Store and keep y to restore it on page change
const route = useRoute();
const yStored = useLocalStorage("versia:scroll", {
[route.fullPath]: 0,
});
const { y } = useScroll(root);
useEventListener("popstate", async () => {
if (yStored.value[route.fullPath] !== undefined) {
// Wait for the Vue component to load
await new Promise((resolve) => setTimeout(resolve, 100));
y.value = yStored.value[route.fullPath] ?? 0;
}
});
onBeforeRouteLeave(() => {
yStored.value[route.fullPath] = y.value;
yStored.value = { ...yStored.value };
});
</script>

View file

@ -0,0 +1,87 @@
<template>
<div
role="status"
class="flex flex-col gap-4 items-center *:max-w-2xl *:w-full p-4"
>
<TimelineItem
:type="type"
v-for="item in items"
:key="item.id"
:item="item"
@update="updateItem"
@delete="removeItem"
/>
<Spinner v-if="isLoading" />
<div v-if="error" class="timeline-error">
{{ error.message }}
</div>
<!-- If there are some posts, but the user scrolled to the end -->
<ReachedEnd v-if="hasReachedEnd && items.length > 0" />
<!-- If there are no posts at all -->
<NoPosts v-else-if="hasReachedEnd && items.length === 0" />
<div v-else-if="!preferences.infinite_scroll" class="py-10 px-4">
<Button
variant="secondary"
@click="loadNext"
:disabled="isLoading"
class="w-full"
>
{{ m.gaudy_bland_gorilla_talk() }}
</Button>
</div>
<div v-else ref="loadMoreTrigger" class="h-20"></div>
</div>
</template>
<script lang="ts" setup>
import type { Notification, Status } from "@versia/client/schemas";
import { useIntersectionObserver } from "@vueuse/core";
import type { z } from "zod";
import * as m from "~~/paraglide/messages.js";
import NoPosts from "../errors/NoPosts.vue";
import ReachedEnd from "../errors/ReachedEnd.vue";
import Spinner from "../graphics/spinner.vue";
import { Button } from "../ui/button";
import TimelineItem from "./timeline-item.vue";
const props = defineProps<{
items: z.infer<typeof Status>[] | z.infer<typeof Notification>[];
type: "status" | "notification";
isLoading: boolean;
hasReachedEnd: boolean;
error: Error | null;
loadNext: () => void;
loadPrev: () => void;
removeItem: (id: string) => void;
updateItem:
| ((item: z.infer<typeof Status>) => void)
| ((item: z.infer<typeof Notification>) => void);
}>();
const emit = defineEmits<(e: "update") => void>();
const loadMoreTrigger = ref<HTMLElement | null>(null);
useIntersectionObserver(loadMoreTrigger, ([observer]) => {
if (observer?.isIntersecting && !props.isLoading && !props.hasReachedEnd) {
props.loadNext();
}
});
watch(
() => props.items,
() => {
emit("update");
},
);
onMounted(() => {
props.loadNext();
});
</script>