mirror of
https://github.com/versia-pub/frontend.git
synced 2025-12-06 16:38:20 +01:00
refactor: ♻️ Reimplement Notes
This commit is contained in:
parent
9ced2c98e4
commit
d29f181000
69
components/notes/content.vue
Normal file
69
components/notes/content.vue
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
<template>
|
||||||
|
<div :class="['prose block relative dark:prose-invert duration-200 !max-w-full break-words', $style.content]" v-html="content">
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
const { content } = defineProps<{
|
||||||
|
content: string;
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style module>
|
||||||
|
.content pre:has(code) {
|
||||||
|
word-wrap: normal;
|
||||||
|
background: transparent;
|
||||||
|
background-color: #ffffff0d;
|
||||||
|
border-radius: .25rem;
|
||||||
|
hyphens: none;
|
||||||
|
margin-top: 1rem;
|
||||||
|
overflow-x: auto;
|
||||||
|
padding: .75rem 1rem;
|
||||||
|
tab-size: 4;
|
||||||
|
white-space: pre;
|
||||||
|
word-break: normal;
|
||||||
|
word-spacing: normal;
|
||||||
|
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
||||||
|
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
||||||
|
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), 0 0 #0000;
|
||||||
|
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
|
||||||
|
--tw-ring-color: hsla(0, 0%, 100%, .1)
|
||||||
|
}
|
||||||
|
|
||||||
|
.content pre code {
|
||||||
|
display: block;
|
||||||
|
padding: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
.content code:not(pre code)::after,
|
||||||
|
.content code:not(pre code)::before {
|
||||||
|
content: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
.content ol li input[type=checkbox],
|
||||||
|
.content ul li input[type=checkbox] {
|
||||||
|
border-radius:.25rem;
|
||||||
|
margin-bottom:0.2rem;
|
||||||
|
margin-right:.5rem;
|
||||||
|
margin-top:0;
|
||||||
|
vertical-align: middle;
|
||||||
|
--tw-text-opacity:1;
|
||||||
|
color: var(--theme-primary-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
.content code:not(pre code) {
|
||||||
|
border-radius: .25rem;
|
||||||
|
padding: .25rem .5rem;
|
||||||
|
word-wrap: break-word;
|
||||||
|
background: transparent;
|
||||||
|
background-color: #ffffff0d;
|
||||||
|
hyphens: none;
|
||||||
|
margin-top: 1rem;
|
||||||
|
tab-size: 4;
|
||||||
|
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
||||||
|
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
||||||
|
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), 0 0 #0000;
|
||||||
|
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
|
||||||
|
--tw-ring-color: hsla(0, 0%, 100%, .1)
|
||||||
|
}
|
||||||
|
</style>
|
||||||
39
components/notes/copyable-text.vue
Normal file
39
components/notes/copyable-text.vue
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
<template>
|
||||||
|
<span :class="cn('text-primary group', $props.class)">
|
||||||
|
<span class="group-hover:hidden">
|
||||||
|
<slot />
|
||||||
|
</span>
|
||||||
|
<span class="hidden group-hover:inline">
|
||||||
|
<span @click="copyText" v-if="!hasCopied"
|
||||||
|
class="select-none cursor-pointer space-x-1">
|
||||||
|
<Clipboard class="size-4 -translate-y-0.5 inline" />
|
||||||
|
Click to copy
|
||||||
|
</span>
|
||||||
|
<span v-else class="select-none space-x-1">
|
||||||
|
<Check class="size-4 -translate-y-0.5 inline" />
|
||||||
|
Copied!
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import { Check, Clipboard } from "lucide-vue-next";
|
||||||
|
import type { HTMLAttributes } from "vue";
|
||||||
|
|
||||||
|
const { text } = defineProps<{
|
||||||
|
text: string;
|
||||||
|
class?: HTMLAttributes["class"];
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const hasCopied = ref(false);
|
||||||
|
const { copy } = useClipboard();
|
||||||
|
const copyText = () => {
|
||||||
|
copy(text);
|
||||||
|
hasCopied.value = true;
|
||||||
|
setTimeout(() => {
|
||||||
|
hasCopied.value = false;
|
||||||
|
}, 2000);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
70
components/notes/header.vue
Normal file
70
components/notes/header.vue
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
<template>
|
||||||
|
<div class="rounded flex flex-row gap-4">
|
||||||
|
<Avatar class="size-14 rounded border border-card">
|
||||||
|
<AvatarImage :src="avatar" alt="" />
|
||||||
|
<AvatarFallback class="rounded-lg"> AA </AvatarFallback>
|
||||||
|
</Avatar>
|
||||||
|
<div class="flex flex-col gap-0.5 justify-center flex-1 text-left leading-tight">
|
||||||
|
<span class="truncate font-semibold">{{
|
||||||
|
displayName
|
||||||
|
}}</span>
|
||||||
|
<span class="truncate text-sm">
|
||||||
|
<CopyableText :text="acct">
|
||||||
|
<span
|
||||||
|
class="font-semibold bg-gradient-to-tr from-pink-300 via-purple-300 to-indigo-400 text-transparent bg-clip-text">
|
||||||
|
@{{ username }}
|
||||||
|
</span>
|
||||||
|
<span class="text-muted-foreground">{{ instance && "@" }}{{ instance }}</span>
|
||||||
|
</CopyableText>
|
||||||
|
·
|
||||||
|
<span class="text-muted-foreground ml-auto" :title="fullTime">{{ timeAgo }}</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-1 justify-center items-end">
|
||||||
|
<span class="text-xs text-muted-foreground" :title="visibilities[visibility].text">
|
||||||
|
<component :is="visibilities[visibility].icon" class="size-5" />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import type { StatusVisibility } from "@versia/client/types";
|
||||||
|
import { AtSign, Globe, Lock, LockOpen } from "lucide-vue-next";
|
||||||
|
import CopyableText from "./copyable-text.vue";
|
||||||
|
|
||||||
|
const { acct, createdAt } = defineProps<{
|
||||||
|
avatar: string;
|
||||||
|
acct: string;
|
||||||
|
displayName: string;
|
||||||
|
visibility: StatusVisibility;
|
||||||
|
url: string;
|
||||||
|
createdAt: Date;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const [username, instance] = acct.split("@");
|
||||||
|
const timeAgo = useTimeAgo(createdAt);
|
||||||
|
const fullTime = new Intl.DateTimeFormat("en-US", {
|
||||||
|
dateStyle: "medium",
|
||||||
|
timeStyle: "short",
|
||||||
|
}).format(createdAt);
|
||||||
|
|
||||||
|
const visibilities = {
|
||||||
|
public: {
|
||||||
|
icon: Globe,
|
||||||
|
text: "This note is public: it can be seen by anyone.",
|
||||||
|
},
|
||||||
|
unlisted: {
|
||||||
|
icon: LockOpen,
|
||||||
|
text: "This note is unlisted: it can be seen by anyone with the link.",
|
||||||
|
},
|
||||||
|
private: {
|
||||||
|
icon: Lock,
|
||||||
|
text: "This note is private: it can only be seen by followers.",
|
||||||
|
},
|
||||||
|
direct: {
|
||||||
|
icon: AtSign,
|
||||||
|
text: "This note is direct: it can only be seen by mentioned users.",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
26
components/notes/note.vue
Normal file
26
components/notes/note.vue
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
<template>
|
||||||
|
<Card as="article" class="rounded-none border-0 hover:bg-muted/50 duration-200">
|
||||||
|
<CardHeader class="pb-4">
|
||||||
|
<Header :avatar="note.account.avatar" :acct="note.account.acct" :display-name="note.account.display_name"
|
||||||
|
:visibility="note.visibility" :url="accountUrl" :created-at="new Date(note.created_at)" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<Content :content="note.content" />
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { Status } from "@versia/client/types";
|
||||||
|
import { Card, CardHeader } from "../ui/card";
|
||||||
|
import { Separator } from "../ui/separator";
|
||||||
|
import Content from "./content.vue";
|
||||||
|
import Header from "./header.vue";
|
||||||
|
|
||||||
|
const { note } = defineProps<{
|
||||||
|
note: Status;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const url = `/@${note.account.acct}/${note.id}`;
|
||||||
|
const accountUrl = `/@${note.account.acct}`;
|
||||||
|
</script>
|
||||||
|
|
@ -121,7 +121,7 @@ const instance = useInstance();
|
||||||
<SidebarHeader>
|
<SidebarHeader>
|
||||||
<SidebarMenu>
|
<SidebarMenu>
|
||||||
<SidebarMenuItem>
|
<SidebarMenuItem>
|
||||||
<DropdownMenu>
|
<NuxtLink href="/">
|
||||||
<SidebarMenuButton size="lg"
|
<SidebarMenuButton size="lg"
|
||||||
class="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground">
|
class="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground">
|
||||||
<Avatar shape="square" class="size-8">
|
<Avatar shape="square" class="size-8">
|
||||||
|
|
@ -135,7 +135,7 @@ const instance = useInstance();
|
||||||
</div>
|
</div>
|
||||||
<!-- <ChevronsUpDown class="ml-auto" /> -->
|
<!-- <ChevronsUpDown class="ml-auto" /> -->
|
||||||
</SidebarMenuButton>
|
</SidebarMenuButton>
|
||||||
</DropdownMenu>
|
</NuxtLink>
|
||||||
</SidebarMenuItem>
|
</SidebarMenuItem>
|
||||||
</SidebarMenu>
|
</SidebarMenu>
|
||||||
</SidebarHeader>
|
</SidebarHeader>
|
||||||
|
|
@ -180,12 +180,6 @@ const instance = useInstance();
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
</SidebarMenuButton>
|
</SidebarMenuButton>
|
||||||
</SidebarMenuItem>
|
</SidebarMenuItem>
|
||||||
<SidebarMenuItem>
|
|
||||||
<SidebarMenuButton class="text-sidebar-foreground/70">
|
|
||||||
<MoreHorizontal class="text-sidebar-foreground/70" />
|
|
||||||
<span>More</span>
|
|
||||||
</SidebarMenuButton>
|
|
||||||
</SidebarMenuItem>
|
|
||||||
</SidebarMenu>
|
</SidebarMenu>
|
||||||
</SidebarGroup>
|
</SidebarGroup>
|
||||||
</SidebarContent>
|
</SidebarContent>
|
||||||
|
|
@ -270,7 +264,7 @@ const instance = useInstance();
|
||||||
</Breadcrumb>
|
</Breadcrumb>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<div class="flex flex-1 flex-col gap-4 pt-0 overflow-auto">
|
<div class="flex flex-1 flex-col gap-4 md:p-1 overflow-auto">
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</SidebarInset>
|
</SidebarInset>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Moon, Sun } from "lucide-vue-next";
|
import { Moon, Sun, Wrench } from "lucide-vue-next";
|
||||||
import { Button } from "../ui/button";
|
import { Button } from "../ui/button";
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
|
|
@ -9,25 +9,34 @@ import {
|
||||||
} from "../ui/dropdown-menu";
|
} from "../ui/dropdown-menu";
|
||||||
|
|
||||||
const colorMode = useColorMode();
|
const colorMode = useColorMode();
|
||||||
|
|
||||||
|
const themeNames = {
|
||||||
|
light: "Light",
|
||||||
|
dark: "Dark",
|
||||||
|
system: "System",
|
||||||
|
} as Record<string, string>;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger as-child>
|
<DropdownMenuTrigger as-child>
|
||||||
<Button variant="ghost">
|
<Button variant="outline" class="w-full justify-start">
|
||||||
<Sun class="size-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
|
<Sun class="size-[1.2rem] scale-100 transition-all dark:scale-0 dark:hidden inline" />
|
||||||
<Moon class="absolute size-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
|
<Moon class="size-[1.2rem] scale-0 transition-all dark:scale-100 hidden dark:inline" />
|
||||||
<span class="sr-only">Toggle theme</span>
|
{{ themeNames[colorMode.preference] }}
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent align="end">
|
<DropdownMenuContent align="start" >
|
||||||
<DropdownMenuItem @click="colorMode.preference = 'light'">
|
<DropdownMenuItem @click="colorMode.preference = 'light'">
|
||||||
|
<Sun class="size-4 mr-2" />
|
||||||
Light
|
Light
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuItem @click="colorMode.preference = 'dark'">
|
<DropdownMenuItem @click="colorMode.preference = 'dark'">
|
||||||
|
<Moon class="size-4 mr-2" />
|
||||||
Dark
|
Dark
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuItem @click="colorMode.preference = 'system'">
|
<DropdownMenuItem @click="colorMode.preference = 'system'">
|
||||||
|
<Wrench class="size-4 mr-2" />
|
||||||
System
|
System
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<component :is="itemComponent" :element="item" @update="$emit('update', $event)"
|
<component :is="itemComponent" :note="item" @update="$emit('update', $event)"
|
||||||
@delete="$emit('delete', item?.id)" />
|
@delete="$emit('delete', item?.id)" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { Notification, Status } from "@versia/client/types";
|
import type { Notification, Status } from "@versia/client/types";
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
|
import NewNoteItem from "../notes/note.vue";
|
||||||
import NoteItem from "../social-elements/notes/note.vue";
|
import NoteItem from "../social-elements/notes/note.vue";
|
||||||
import NotificationItem from "../social-elements/notifications/notif.vue";
|
import NotificationItem from "../social-elements/notifications/notif.vue";
|
||||||
|
|
||||||
|
|
@ -16,7 +17,7 @@ const props = defineProps<{
|
||||||
|
|
||||||
const itemComponent = computed(() => {
|
const itemComponent = computed(() => {
|
||||||
if (props.type === "status") {
|
if (props.type === "status") {
|
||||||
return NoteItem;
|
return NewNoteItem;
|
||||||
}
|
}
|
||||||
if (props.type === "notification") {
|
if (props.type === "notification") {
|
||||||
return NotificationItem;
|
return NotificationItem;
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
<!-- Timeline.vue -->
|
<!-- Timeline.vue -->
|
||||||
<template>
|
<template>
|
||||||
<div class="timeline rounded overflow-hidden">
|
<div class="timeline rounded overflow-hidden ring-1 ring-ring/15">
|
||||||
<TransitionGroup name="timeline-item" tag="div" class="timeline-items">
|
<TransitionGroup name="timeline-item" tag="div" class="timeline-items *:!border-b *:last:border-0">
|
||||||
<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>
|
||||||
|
|
||||||
<TimelineItem v-if="isLoading" :type="type" v-for="_ in 5" />
|
<!-- <TimelineItem v-if="isLoading" :type="type" v-for="_ in 5" /> -->
|
||||||
|
|
||||||
<div v-if="error" class="timeline-error">
|
<div v-if="error" class="timeline-error">
|
||||||
{{ error.message }}
|
{{ error.message }}
|
||||||
|
|
|
||||||
27
components/ui/card/Card.vue
Normal file
27
components/ui/card/Card.vue
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import { Primitive, type PrimitiveProps } from "radix-vue";
|
||||||
|
import type { HTMLAttributes } from "vue";
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<PrimitiveProps & { class?: HTMLAttributes["class"] }>(),
|
||||||
|
{
|
||||||
|
as: "div",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Primitive
|
||||||
|
:as="props.as"
|
||||||
|
:as-child="props.asChild"
|
||||||
|
:class="
|
||||||
|
cn(
|
||||||
|
'rounded-lg border bg-card text-card-foreground shadow-sm',
|
||||||
|
props.class,
|
||||||
|
)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</Primitive>
|
||||||
|
</template>
|
||||||
14
components/ui/card/CardContent.vue
Normal file
14
components/ui/card/CardContent.vue
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import type { HTMLAttributes } from "vue";
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
class?: HTMLAttributes["class"];
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div :class="cn('p-6 pt-0', props.class)">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
14
components/ui/card/CardDescription.vue
Normal file
14
components/ui/card/CardDescription.vue
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import type { HTMLAttributes } from "vue";
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
class?: HTMLAttributes["class"];
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<p :class="cn('text-sm text-muted-foreground', props.class)">
|
||||||
|
<slot />
|
||||||
|
</p>
|
||||||
|
</template>
|
||||||
14
components/ui/card/CardFooter.vue
Normal file
14
components/ui/card/CardFooter.vue
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import type { HTMLAttributes } from "vue";
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
class?: HTMLAttributes["class"];
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div :class="cn('flex items-center p-6 pt-0', props.class)">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
14
components/ui/card/CardHeader.vue
Normal file
14
components/ui/card/CardHeader.vue
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import type { HTMLAttributes } from "vue";
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
class?: HTMLAttributes["class"];
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div :class="cn('flex flex-col gap-y-1.5 p-6', props.class)">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
18
components/ui/card/CardTitle.vue
Normal file
18
components/ui/card/CardTitle.vue
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import type { HTMLAttributes } from "vue";
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
class?: HTMLAttributes["class"];
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<h3
|
||||||
|
:class="
|
||||||
|
cn('text-2xl font-semibold leading-none tracking-tight', props.class)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</h3>
|
||||||
|
</template>
|
||||||
6
components/ui/card/index.ts
Normal file
6
components/ui/card/index.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
export { default as Card } from "./Card.vue";
|
||||||
|
export { default as CardContent } from "./CardContent.vue";
|
||||||
|
export { default as CardDescription } from "./CardDescription.vue";
|
||||||
|
export { default as CardFooter } from "./CardFooter.vue";
|
||||||
|
export { default as CardHeader } from "./CardHeader.vue";
|
||||||
|
export { default as CardTitle } from "./CardTitle.vue";
|
||||||
|
|
@ -1,14 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="mx-auto max-w-2xl w-full">
|
<div class="mx-auto max-w-2xl w-full">
|
||||||
<TimelineScroller>
|
<TimelineScroller>
|
||||||
<Greeting />
|
|
||||||
<Home />
|
<Home />
|
||||||
</TimelineScroller>
|
</TimelineScroller>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Greeting from "~/components/headers/greeting.vue";
|
|
||||||
import Home from "~/components/timelines/home.vue";
|
import Home from "~/components/timelines/home.vue";
|
||||||
import TimelineScroller from "~/components/timelines/timeline-scroller.vue";
|
import TimelineScroller from "~/components/timelines/timeline-scroller.vue";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="mx-auto max-w-2xl w-full">
|
<div class="mx-auto max-w-2xl w-full">
|
||||||
<TimelineScroller>
|
<TimelineScroller>
|
||||||
<Greeting />
|
|
||||||
<Local />
|
<Local />
|
||||||
</TimelineScroller>
|
</TimelineScroller>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -9,7 +8,6 @@
|
||||||
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import Greeting from "~/components/headers/greeting.vue";
|
|
||||||
import Local from "~/components/timelines/local.vue";
|
import Local from "~/components/timelines/local.vue";
|
||||||
import TimelineScroller from "~/components/timelines/timeline-scroller.vue";
|
import TimelineScroller from "~/components/timelines/timeline-scroller.vue";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<TimelineScroller v-else>
|
<TimelineScroller v-else>
|
||||||
<Greeting />
|
|
||||||
<div class="rounded overflow-hidden">
|
<div class="rounded overflow-hidden">
|
||||||
<Notifications />
|
<Notifications />
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -21,7 +20,6 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import Greeting from "~/components/headers/greeting.vue";
|
|
||||||
import Notifications from "~/components/timelines/notifications.vue";
|
import Notifications from "~/components/timelines/notifications.vue";
|
||||||
import TimelineScroller from "~/components/timelines/timeline-scroller.vue";
|
import TimelineScroller from "~/components/timelines/timeline-scroller.vue";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="mx-auto max-w-2xl w-full">
|
<div class="mx-auto max-w-2xl w-full">
|
||||||
<TimelineScroller>
|
<TimelineScroller>
|
||||||
<Greeting />
|
|
||||||
<Public />
|
<Public />
|
||||||
</TimelineScroller>
|
</TimelineScroller>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Greeting from "~/components/headers/greeting.vue";
|
|
||||||
import Public from "~/components/timelines/public.vue";
|
import Public from "~/components/timelines/public.vue";
|
||||||
import TimelineScroller from "~/components/timelines/timeline-scroller.vue";
|
import TimelineScroller from "~/components/timelines/timeline-scroller.vue";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,4 @@
|
||||||
@tailwind base;
|
@tailwind base;
|
||||||
@tailwind components;
|
|
||||||
@tailwind utilities;
|
|
||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
:root {
|
:root {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue