♻️ Moved the components to use naive ui + daisyui
This commit is contained in:
20
app/app.vue
20
app/app.vue
@@ -1,8 +1,20 @@
|
||||
<template>
|
||||
<nuxt-loading-indicator :color="colorMode.value == 'dark' ? 'white' : '#3f51b5'" />
|
||||
<nuxt-layout>
|
||||
<nuxt-page />
|
||||
</nuxt-layout>
|
||||
<naive-config>
|
||||
<n-config-provider>
|
||||
<n-dialog-provider>
|
||||
<n-notification-provider>
|
||||
<n-message-provider>
|
||||
<n-loading-bar-provider>
|
||||
<nuxt-loading-indicator :color="colorMode.value == 'dark' ? 'white' : '#3f51b5'" />
|
||||
<nuxt-layout>
|
||||
<nuxt-page />
|
||||
</nuxt-layout>
|
||||
</n-loading-bar-provider>
|
||||
</n-message-provider>
|
||||
</n-notification-provider>
|
||||
</n-dialog-provider>
|
||||
</n-config-provider>
|
||||
</naive-config>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
@forward "vuetify/settings" with (
|
||||
$layers: true
|
||||
);
|
||||
@@ -1,3 +0,0 @@
|
||||
@use "vuetify" with (
|
||||
$reset: false
|
||||
);
|
||||
@@ -1,49 +1,30 @@
|
||||
@import "tailwindcss";
|
||||
@plugin "daisyui";
|
||||
@plugin "@tailwindcss/typography";
|
||||
|
||||
@layer theme, base, components, utilities;
|
||||
@import "tailwindcss/theme.css" layer(theme);
|
||||
@import "tailwindcss/preflight.css" layer(base);
|
||||
@import "tailwindcss/utilities.css" layer(utilities);
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--font-family: "Nunito Variable", "Helvatica", sans-serif;
|
||||
}
|
||||
|
||||
.prose p,
|
||||
.prose h1,
|
||||
.prose h2,
|
||||
.prose h3,
|
||||
.prose h4,
|
||||
.prose h5,
|
||||
.prose h6,
|
||||
.prose ul,
|
||||
.prose ol,
|
||||
.prose blockquote {
|
||||
margin: revert;
|
||||
html,
|
||||
body {
|
||||
font-family: var(--font-family);
|
||||
}
|
||||
}
|
||||
|
||||
@plugin "@tailwindcss/typography";
|
||||
|
||||
@import "@fontsource-variable/nunito";
|
||||
@import "@mdi/font/css/materialdesignicons.css";
|
||||
|
||||
@layer theme, base, components, utilities;
|
||||
@import "tailwindcss/theme.css" layer(theme);
|
||||
@import "tailwindcss/utilities.css" layer(utilities);
|
||||
|
||||
html,
|
||||
body {
|
||||
font-family: var(--font-family);
|
||||
background-color: rgba(var(--v-theme-background), 1);
|
||||
}
|
||||
|
||||
.page-enter-active,
|
||||
.page-leave-active {
|
||||
transition: all 0.4s;
|
||||
}
|
||||
|
||||
.page-enter-from,
|
||||
.page-leave-to {
|
||||
opacity: 0;
|
||||
filter: blur(1rem);
|
||||
}
|
||||
|
||||
.prose pre {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
13
app/auto-imports.d.ts
vendored
Normal file
13
app/auto-imports.d.ts
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
// @ts-nocheck
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
// Generated by unplugin-auto-import
|
||||
// biome-ignore lint: disable
|
||||
export {}
|
||||
declare global {
|
||||
const useDialog: typeof import('naive-ui').useDialog
|
||||
const useLoadingBar: typeof import('naive-ui').useLoadingBar
|
||||
const useMessage: typeof import('naive-ui').useMessage
|
||||
const useNotification: typeof import('naive-ui').useNotification
|
||||
}
|
||||
46
app/components.d.ts
vendored
Normal file
46
app/components.d.ts
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
// biome-ignore lint: disable
|
||||
// oxlint-disable
|
||||
// ------
|
||||
// Generated by unplugin-vue-components
|
||||
// Read more: https://github.com/vuejs/core/pull/3399
|
||||
import { GlobalComponents } from 'vue'
|
||||
|
||||
export {}
|
||||
|
||||
/* prettier-ignore */
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
NAvatar: typeof import('naive-ui')['NAvatar']
|
||||
NButton: typeof import('naive-ui')['NButton']
|
||||
NConfigProvider: typeof import('naive-ui')['NConfigProvider']
|
||||
NDialogProvider: typeof import('naive-ui')['NDialogProvider']
|
||||
NDropdown: typeof import('naive-ui')['NDropdown']
|
||||
NInput: typeof import('naive-ui')['NInput']
|
||||
NLoadingBarProvider: typeof import('naive-ui')['NLoadingBarProvider']
|
||||
NMessageProvider: typeof import('naive-ui')['NMessageProvider']
|
||||
NNotificationProvider: typeof import('naive-ui')['NNotificationProvider']
|
||||
NSelect: typeof import('naive-ui')['NSelect']
|
||||
NThemeEditor: typeof import('naive-ui')['NThemeEditor']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
}
|
||||
}
|
||||
|
||||
// For TSX support
|
||||
declare global {
|
||||
const NAvatar: typeof import('naive-ui')['NAvatar']
|
||||
const NButton: typeof import('naive-ui')['NButton']
|
||||
const NConfigProvider: typeof import('naive-ui')['NConfigProvider']
|
||||
const NDialogProvider: typeof import('naive-ui')['NDialogProvider']
|
||||
const NDropdown: typeof import('naive-ui')['NDropdown']
|
||||
const NInput: typeof import('naive-ui')['NInput']
|
||||
const NLoadingBarProvider: typeof import('naive-ui')['NLoadingBarProvider']
|
||||
const NMessageProvider: typeof import('naive-ui')['NMessageProvider']
|
||||
const NNotificationProvider: typeof import('naive-ui')['NNotificationProvider']
|
||||
const NSelect: typeof import('naive-ui')['NSelect']
|
||||
const NThemeEditor: typeof import('naive-ui')['NThemeEditor']
|
||||
const RouterLink: typeof import('vue-router')['RouterLink']
|
||||
const RouterView: typeof import('vue-router')['RouterView']
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<div class="d-flex justify-center">
|
||||
<div class="flex justify-center">
|
||||
<div v-if="provider === 'cloudflare'">
|
||||
<turnstile v-if="!!apiKey" :sitekey="apiKey" @callback="handleSuccess" />
|
||||
<div v-else class="mx-auto">
|
||||
<v-progress-circular indeterminate />
|
||||
<n-spin />
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="provider === 'hcaptcha'">
|
||||
@@ -13,7 +13,7 @@
|
||||
@verify="(tk: string) => handleSuccess(tk)"
|
||||
/>
|
||||
<div v-else class="mx-auto">
|
||||
<v-progress-circular indeterminate />
|
||||
<n-spin />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@@ -21,8 +21,8 @@
|
||||
class="h-captcha"
|
||||
:data-sitekey="apiKey"
|
||||
/>
|
||||
<div v-else class="d-flex flex-column align-center justify-center gap-1">
|
||||
<v-icon size="32"> mdi-alert-circle-outline </v-icon>
|
||||
<div v-else class="flex flex-col items-center justify-center gap-1">
|
||||
<span class="mdi mdi-alert-circle-outline text-3xl"></span>
|
||||
<span>Captcha provider not configured correctly.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,30 +1,17 @@
|
||||
<template>
|
||||
<v-container class="footer">
|
||||
<div class="d-flex justify-space-between align-center">
|
||||
<v-select
|
||||
:items="['English (United States)']"
|
||||
model-value="English (United States)"
|
||||
variant="plain"
|
||||
density="compact"
|
||||
hide-details
|
||||
<div class="container absolute bottom-5 left-1/2 -translate-x-1/2">
|
||||
<div class="flex justify-between items-center">
|
||||
<n-select
|
||||
:options="[{ label: 'English (United States)', value: 'en-us' }]"
|
||||
model-value="en-us"
|
||||
size="small"
|
||||
class="flex-grow-0"
|
||||
/>
|
||||
<div class="d-flex">
|
||||
<v-btn variant="text" size="small" class="text-capitalize">Help</v-btn>
|
||||
<v-btn variant="text" size="small" class="text-capitalize"
|
||||
>Privacy</v-btn
|
||||
>
|
||||
<v-btn variant="text" size="small" class="text-capitalize">Terms</v-btn>
|
||||
<div class="flex">
|
||||
<n-button text size="small">Help</n-button>
|
||||
<n-button text size="small">Privacy</n-button>
|
||||
<n-button text size="small">Terms</n-button>
|
||||
</div>
|
||||
</div>
|
||||
</v-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.footer {
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
<template>
|
||||
<div class="flex flex-col gap-2">
|
||||
<pub-select v-model:value="publisher" />
|
||||
<v-textarea
|
||||
v-model="content"
|
||||
<n-input
|
||||
v-model:value="content"
|
||||
type="textarea"
|
||||
placeholder="What's happended?!"
|
||||
@keydown.meta.enter.exact="submit"
|
||||
@keydown.ctrl.enter.exact="submit"
|
||||
/>
|
||||
<div class="flex justify-between">
|
||||
<v-btn type="primary" :loading="submitting" @click="submit">
|
||||
<n-button type="primary" :loading="submitting" @click="submit">
|
||||
Post
|
||||
<template #append>
|
||||
<v-icon>mdi-send</v-icon>
|
||||
<template #icon>
|
||||
<span class="mdi mdi-send"></span>
|
||||
</template>
|
||||
</v-btn>
|
||||
</n-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<v-card :flat="props.flat">
|
||||
<v-card-text :style="props.slim ? 'padding: 0' : null">
|
||||
<div :class="['card', { 'shadow-none': props.flat }]">
|
||||
<div :class="['card-body', { 'p-0': props.slim }]">
|
||||
<div :class="['flex flex-col', compact ? 'gap-1' : 'gap-3']">
|
||||
<post-header :item="props.item" :compact="compact" />
|
||||
|
||||
@@ -21,50 +21,42 @@
|
||||
</article>
|
||||
|
||||
<template v-if="showReferenced">
|
||||
<div v-if="props.item.repliedPost || props.item.repliedGone">
|
||||
<v-card
|
||||
title="Replying to"
|
||||
prepend-icon="mdi-reply"
|
||||
density="compact"
|
||||
<div v-if="props.item.repliedPost || props.item.repliedGone" class="border rounded-md">
|
||||
<div class="p-2 flex items-center gap-2">
|
||||
<span class="mdi mdi-reply"></span>
|
||||
<span class="font-bold">Replying to</span>
|
||||
</div>
|
||||
<div v-if="props.item.repliedGone" class="px-4 pb-3 text-sm opacity-60">
|
||||
Post unavailable
|
||||
</div>
|
||||
<post-item
|
||||
v-else-if="props.item.repliedPost"
|
||||
class="px-4 pb-3"
|
||||
:item="props.item.repliedPost"
|
||||
slim
|
||||
compact
|
||||
flat
|
||||
border
|
||||
>
|
||||
<div v-if="props.item.repliedGone" class="px-4 pb-3 text-sm opacity-60">
|
||||
Post unavailable
|
||||
</div>
|
||||
<post-item
|
||||
v-else-if="props.item.repliedPost"
|
||||
class="px-4 pb-3"
|
||||
:item="props.item.repliedPost"
|
||||
slim
|
||||
compact
|
||||
flat
|
||||
@react="handleReaction"
|
||||
/>
|
||||
</v-card>
|
||||
@react="handleReaction"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-if="props.item.forwardedPost || props.item.forwardedGone">
|
||||
<v-card
|
||||
title="Forwarded"
|
||||
prepend-icon="mdi-forward"
|
||||
density="compact"
|
||||
<div v-if="props.item.forwardedPost || props.item.forwardedGone" class="border rounded-md">
|
||||
<div class="p-2 flex items-center gap-2">
|
||||
<span class="mdi mdi-forward"></span>
|
||||
<span class="font-bold">Forwarded</span>
|
||||
</div>
|
||||
<div v-if="props.item.forwardedGone" class="px-4 pb-3 text-sm opacity-60">
|
||||
Post unavailable
|
||||
</div>
|
||||
<post-item
|
||||
v-else-if="props.item.forwardedPost"
|
||||
class="px-4 pb-3"
|
||||
:item="props.item.forwardedPost"
|
||||
slim
|
||||
compact
|
||||
flat
|
||||
border
|
||||
>
|
||||
<div v-if="props.item.forwardedGone" class="px-4 pb-3 text-sm opacity-60">
|
||||
Post unavailable
|
||||
</div>
|
||||
<post-item
|
||||
v-else-if="props.item.forwardedPost"
|
||||
class="px-4 pb-3"
|
||||
:item="props.item.forwardedPost"
|
||||
slim
|
||||
compact
|
||||
flat
|
||||
@react="handleReaction"
|
||||
/>
|
||||
</v-card>
|
||||
@react="handleReaction"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -74,22 +66,19 @@
|
||||
:max-height="640"
|
||||
/>
|
||||
|
||||
<v-lazy
|
||||
v-if="props.item.repliesCount && !compact"
|
||||
:options="{ threshold: 0.5 }"
|
||||
transition="fade-transition"
|
||||
>
|
||||
<div ref="repliesTarget">
|
||||
<replies-compact-list
|
||||
v-if="props.item.repliesCount && !compact && repliesVisible"
|
||||
:params="{ postId: props.item.id }"
|
||||
:hide-quick-reply="true"
|
||||
@react="handleReplyReaction"
|
||||
/>
|
||||
</v-lazy>
|
||||
</div>
|
||||
<div
|
||||
v-if="props.item.isTruncated"
|
||||
class="flex gap-2 text-xs opacity-80"
|
||||
class="flex gap-2 text-xs opacity-80 items-center"
|
||||
>
|
||||
<v-icon icon="mdi-dots-horizontal" size="small" />
|
||||
<span class="mdi mdi-dots-horizontal"></span>
|
||||
<p>Post truncated, tap to see details...</p>
|
||||
</div>
|
||||
|
||||
@@ -104,14 +93,15 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch } from "vue"
|
||||
import { useMarkdownProcessor } from "~/composables/useMarkdownProcessor"
|
||||
import type { SnPost } from "~/types/api"
|
||||
import { useIntersectionObserver } from '@vueuse/core'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
@@ -156,4 +146,19 @@ watch(
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
)
|
||||
|
||||
const repliesTarget = ref(null)
|
||||
const repliesVisible = ref(false)
|
||||
|
||||
useIntersectionObserver(
|
||||
repliesTarget,
|
||||
([{ isIntersecting }]) => {
|
||||
if (isIntersecting) {
|
||||
repliesVisible.value = true
|
||||
}
|
||||
},
|
||||
{
|
||||
threshold: 0.5
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
@@ -1,38 +1,19 @@
|
||||
<template>
|
||||
<v-select
|
||||
:items="pubStore.publishers"
|
||||
item-title="nick"
|
||||
item-value="name"
|
||||
:model-value="props.value"
|
||||
@update:model-value="(v) => emits('update:value', v)"
|
||||
>
|
||||
<template #item="{ props: itemProps, item }">
|
||||
<v-list-item v-bind="itemProps">
|
||||
<template #prepend>
|
||||
<v-avatar
|
||||
:image="item.raw.picture ? `${apiBase}/drive/files/${item.raw.picture.id}` : undefined"
|
||||
size="small"
|
||||
/>
|
||||
</template>
|
||||
<v-list-item-subtitle>@{{ item.raw?.name }}</v-list-item-subtitle>
|
||||
</v-list-item>
|
||||
</template>
|
||||
<template #selection="{ item }">
|
||||
<div class="d-flex align-center">
|
||||
<v-avatar
|
||||
:image="item.raw.picture ? `${apiBase}/drive/files/${item.raw.picture.id}` : undefined"
|
||||
size="24"
|
||||
class="me-2"
|
||||
/>
|
||||
{{ item.raw?.nick }}
|
||||
</div>
|
||||
</template>
|
||||
</v-select>
|
||||
<n-select
|
||||
:options="pubStore.publishers"
|
||||
label-field="nick"
|
||||
value-field="name"
|
||||
:value="props.value"
|
||||
@update:value="(v) => emits('update:value', v)"
|
||||
:render-label="renderLabel"
|
||||
:render-tag="renderTag"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { usePubStore } from '~/stores/pub'
|
||||
import { watch } from 'vue'
|
||||
import { watch, h } from 'vue'
|
||||
import type { SelectRenderLabel, SelectRenderTag } from 'naive-ui'
|
||||
|
||||
const pubStore = usePubStore()
|
||||
const apiBase = useSolarNetworkUrl()
|
||||
@@ -40,6 +21,38 @@ const apiBase = useSolarNetworkUrl()
|
||||
const props = defineProps<{ value: string | undefined }>()
|
||||
const emits = defineEmits(['update:value'])
|
||||
|
||||
const renderLabel: SelectRenderLabel = (option) => {
|
||||
return h('div', { class: 'flex items-center' }, [
|
||||
h(NAvatar, {
|
||||
src: option.picture ? `${apiBase.value}/drive/files/${option.picture.id}` : undefined,
|
||||
size: 'small',
|
||||
class: 'mr-2'
|
||||
}),
|
||||
h('div', null, [
|
||||
h('div', null, option.nick as string),
|
||||
h('div', { class: 'text-xs text-gray-500' }, `@${option.name as string}`)
|
||||
])
|
||||
])
|
||||
}
|
||||
|
||||
const renderTag: SelectRenderTag = ({ option }) => {
|
||||
return h(
|
||||
'div',
|
||||
{
|
||||
class: 'flex items-center'
|
||||
},
|
||||
[
|
||||
h(NAvatar, {
|
||||
src: option.picture ? `${apiBase.value}/drive/files/${option.picture.id}` : undefined,
|
||||
size: 'small',
|
||||
class: 'mr-2'
|
||||
}),
|
||||
option.nick as string
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
watch(
|
||||
pubStore,
|
||||
(value) => {
|
||||
|
||||
@@ -6,15 +6,15 @@
|
||||
<span>FloatingIsland</span>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-1.5">
|
||||
<a class="link" target="_blank" href="https://solsynth.dev/terms">
|
||||
<a class="hover:underline" target="_blank" href="https://solsynth.dev/terms">
|
||||
Terms of Services
|
||||
</a>
|
||||
<span class="font-bold">·</span>
|
||||
<a class="link" target="_blank" href="https://status.solsynth.dev">
|
||||
<a class="hover:underline" target="_blank" href="https://status.solsynth.dev">
|
||||
Service Status
|
||||
</a>
|
||||
<span class="font-bold">·</span>
|
||||
<nuxt-link class="link" target="_blank" to="/swagger"> API </nuxt-link>
|
||||
<nuxt-link class="hover:underline" target="_blank" to="/swagger"> API </nuxt-link>
|
||||
</div>
|
||||
<p class="mt-2 opacity-80">
|
||||
The FloatingIsland do not provides all the features the Solar Network has,
|
||||
@@ -23,9 +23,3 @@
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,66 +1,34 @@
|
||||
<template>
|
||||
<v-app :theme="colorMode.preference">
|
||||
<v-app-bar elevation="2" color="surface-lighten-5">
|
||||
<v-container class="mx-auto flex align-center justify-center">
|
||||
<img
|
||||
:src="colorMode.value == 'dark' ? IconDark : IconLight"
|
||||
width="32"
|
||||
height="32"
|
||||
class="me-4"
|
||||
alt="The Solar Network"
|
||||
/>
|
||||
<div class="flex flex-col min-h-screen" :data-theme="colorMode.preference">
|
||||
<header class="navbar bg-base-100 shadow-lg">
|
||||
<div class="container mx-auto flex items-center justify-center">
|
||||
<img :src="colorMode.value == 'dark' ? IconDark : IconLight" width="32" height="32" class="mr-4"
|
||||
alt="The Solar Network" />
|
||||
|
||||
<v-btn
|
||||
v-for="link in links"
|
||||
:key="link.title"
|
||||
:text="link.title"
|
||||
:to="link.href"
|
||||
:prepend-icon="link.icon"
|
||||
variant="text"
|
||||
/>
|
||||
|
||||
<v-spacer />
|
||||
|
||||
<v-menu>
|
||||
<template #activator="{ props }">
|
||||
<v-avatar
|
||||
v-bind="props"
|
||||
class="me-4"
|
||||
color="grey-darken-1"
|
||||
size="32"
|
||||
icon="mdi-account-circle"
|
||||
:image="
|
||||
user?.profile.picture
|
||||
? `${apiBase}/drive/files/${user?.profile.picture?.id}`
|
||||
: undefined
|
||||
"
|
||||
/>
|
||||
<n-button v-for="link in links" :key="link.title" text @click="() => router.push(link.href)">
|
||||
<template #icon>
|
||||
<span :class="`mdi ${link.icon}`"></span>
|
||||
</template>
|
||||
<v-list density="compact">
|
||||
<v-list-item v-if="!user" to="/auth/login" prepend-icon="mdi-login"
|
||||
>Login</v-list-item
|
||||
>
|
||||
<v-list-item
|
||||
v-if="!user"
|
||||
to="/auth/create-account"
|
||||
prepend-icon="mdi-account-plus"
|
||||
>Create Account</v-list-item
|
||||
>
|
||||
<v-list-item
|
||||
v-if="user"
|
||||
to="/accounts/me"
|
||||
prepend-icon="mdi-view-dashboard"
|
||||
>Dashboard</v-list-item
|
||||
>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</v-container>
|
||||
</v-app-bar>
|
||||
{{ link.title }}
|
||||
</n-button>
|
||||
|
||||
<v-main>
|
||||
<div class="grow" />
|
||||
|
||||
<n-dropdown :options="dropdownOptions" @select="handleDropdownSelect">
|
||||
<n-avatar round class="mr-4 cursor-pointer" :size="32" :src="user?.profile.picture
|
||||
? `${apiBase}/drive/files/${user?.profile.picture?.id}`
|
||||
: undefined
|
||||
">
|
||||
<span v-if="!user" class="mdi mdi-account-circle text-3xl"></span>
|
||||
</n-avatar>
|
||||
</n-dropdown>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="grow container mx-auto py-4">
|
||||
<slot />
|
||||
</v-main>
|
||||
</v-app>
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
@@ -68,9 +36,12 @@ import IconLight from "~/assets/images/cloudy-lamb.png"
|
||||
import IconDark from "~/assets/images/cloudy-lamb@dark.png"
|
||||
|
||||
import type { NavLink } from "~/types/navlink"
|
||||
import { computed, h } from "vue"
|
||||
import { useRouter } from "vue-router"
|
||||
|
||||
const apiBase = useSolarNetworkUrl()
|
||||
const colorMode = useColorMode()
|
||||
const router = useRouter()
|
||||
|
||||
const { user } = useUserStore()
|
||||
|
||||
@@ -81,4 +52,33 @@ const links: NavLink[] = [
|
||||
icon: "mdi-compass"
|
||||
}
|
||||
]
|
||||
|
||||
const dropdownOptions = computed(() => {
|
||||
if (user) {
|
||||
return [
|
||||
{
|
||||
label: "Dashboard",
|
||||
key: "/accounts/me",
|
||||
icon: () => h('span', { class: 'mdi mdi-view-dashboard' })
|
||||
}
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
{
|
||||
label: "Login",
|
||||
key: "/auth/login",
|
||||
icon: () => h('span', { class: 'mdi mdi-login' })
|
||||
},
|
||||
{
|
||||
label: "Create Account",
|
||||
key: "/auth/create-account",
|
||||
icon: () => h('span', { class: 'mdi mdi-account-plus' })
|
||||
}
|
||||
];
|
||||
}
|
||||
});
|
||||
|
||||
function handleDropdownSelect(key: string) {
|
||||
router.push(key);
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
<template>
|
||||
<v-app :theme="colorMode.preference">
|
||||
<v-main>
|
||||
<div class="min-h-screen" :data-theme="colorMode.preference">
|
||||
<main>
|
||||
<slot />
|
||||
</v-main>
|
||||
</main>
|
||||
|
||||
<nuxt-link to="/">
|
||||
<v-footer app fixed flat height="48">
|
||||
<v-container class="mx-auto d-flex align-center justify-between">
|
||||
<footer
|
||||
class="footer items-center h-12 px-4 bg-neutral text-neutral-content sticky bottom-0"
|
||||
>
|
||||
<div class="container mx-auto flex items-center">
|
||||
<img
|
||||
:src="Icon"
|
||||
alt="Cloudy Lamb"
|
||||
@@ -15,10 +17,10 @@
|
||||
class="mr-2"
|
||||
/>
|
||||
<p class="text-sm">Solar Network</p>
|
||||
</v-container>
|
||||
</v-footer>
|
||||
</div>
|
||||
</footer>
|
||||
</nuxt-link>
|
||||
</v-app>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<v-container>
|
||||
<div class="container mx-auto">
|
||||
<div class="layout">
|
||||
<div class="main">
|
||||
<div v-for="activity in activites" :key="activity.id" class="mb-4">
|
||||
@@ -11,8 +11,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar flex flex-col gap-3">
|
||||
<v-card v-if="!userStore.isAuthenticated" class="w-full" title="About">
|
||||
<v-card-text>
|
||||
<div v-if="!userStore.isAuthenticated" class="card w-full bg-base-100 shadow-xl">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title">About</h2>
|
||||
<p>Welcome to the <b>Solar Network</b></p>
|
||||
<p>The open social network. Friendly to everyone.</p>
|
||||
|
||||
@@ -24,17 +25,17 @@
|
||||
{{ version.updatedAt }}
|
||||
</span>
|
||||
</p>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
<v-card v-else class="w-full">
|
||||
<v-card-text>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="card w-full bg-base-100 shadow-xl">
|
||||
<div class="card-body">
|
||||
<post-editor @posted="refreshActivities" />
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</div>
|
||||
</div>
|
||||
<sidebar-footer class="max-lg:hidden" />
|
||||
</div>
|
||||
</div>
|
||||
</v-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import tailwindcss from "@tailwindcss/vite"
|
||||
import tailwindcss from '@tailwindcss/vite'
|
||||
import AutoImport from 'unplugin-auto-import/vite'
|
||||
import Components from 'unplugin-vue-components/vite'
|
||||
import { NaiveUiResolver } from 'unplugin-vue-components/resolvers'
|
||||
|
||||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||
export default defineNuxtConfig({
|
||||
@@ -8,15 +11,13 @@ export default defineNuxtConfig({
|
||||
"@nuxt/image",
|
||||
"@nuxt/eslint",
|
||||
"@pinia/nuxt",
|
||||
"vuetify-nuxt-module",
|
||||
"@nuxtjs/i18n",
|
||||
"@nuxtjs/color-mode",
|
||||
"nuxt-og-image"
|
||||
"nuxt-og-image",
|
||||
"@bg-dev/nuxt-naiveui",
|
||||
],
|
||||
css: [
|
||||
"~/assets/css/main.css",
|
||||
"~/assets/css/globals.scss",
|
||||
"katex/dist/katex.min.css"
|
||||
],
|
||||
app: {
|
||||
pageTransition: { name: "page", mode: "out-in" },
|
||||
@@ -67,15 +68,23 @@ export default defineNuxtConfig({
|
||||
}
|
||||
},
|
||||
vite: {
|
||||
plugins: [tailwindcss()]
|
||||
plugins: [
|
||||
tailwindcss(),
|
||||
AutoImport({
|
||||
imports: [
|
||||
{
|
||||
'naive-ui': [
|
||||
'useDialog',
|
||||
'useMessage',
|
||||
'useNotification',
|
||||
'useLoadingBar'
|
||||
]
|
||||
}
|
||||
]
|
||||
}),
|
||||
Components({
|
||||
resolvers: [NaiveUiResolver()],
|
||||
})
|
||||
]
|
||||
},
|
||||
vuetify: {
|
||||
moduleOptions: {
|
||||
disableVuetifyStyles: true,
|
||||
styles: {
|
||||
configFile: "assets/css/components.scss"
|
||||
}
|
||||
},
|
||||
vuetifyOptions: "./vuetify.config.ts"
|
||||
}
|
||||
})
|
||||
|
||||
14
package.json
14
package.json
@@ -19,7 +19,6 @@
|
||||
"@nuxtjs/color-mode": "3.5.2",
|
||||
"@nuxtjs/i18n": "10.1.0",
|
||||
"@pinia/nuxt": "0.11.2",
|
||||
"@tailwindcss/typography": "^0.5.19",
|
||||
"@tailwindcss/vite": "^4.1.17",
|
||||
"@vueuse/core": "^13.9.0",
|
||||
"blurhash": "^2.0.5",
|
||||
@@ -33,20 +32,23 @@
|
||||
"markdown-it-texmath": "^1.0.0",
|
||||
"nuxt": "^4.2.1",
|
||||
"nuxt-og-image": "^5.1.12",
|
||||
"nuxtjs-naive-ui": "1.0.2",
|
||||
"pinia": "^3.0.4",
|
||||
"sharp": "^0.34.5",
|
||||
"swagger-themes": "^1.4.3",
|
||||
"swagger-ui-dist": "^5.30.2",
|
||||
"tailwindcss": "^4.1.17",
|
||||
"tus-js-client": "^4.3.1",
|
||||
"vue": "^3.5.24",
|
||||
"vue-router": "^4.6.3",
|
||||
"vuetify-nuxt-module": "0.18.7"
|
||||
"vue-router": "^4.6.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@bg-dev/nuxt-naiveui": "^2.0.0",
|
||||
"@mdi/font": "^7.4.47",
|
||||
"@tailwindcss/typography": "^0.5.19",
|
||||
"@types/luxon": "^3.7.1",
|
||||
"@types/node": "^24.10.0",
|
||||
"sass-embedded": "^1.93.3"
|
||||
"daisyui": "^5.5.5",
|
||||
"naive-ui": "^2.43.2",
|
||||
"tailwindcss": "^4.1.17"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
import { defineVuetifyConfiguration } from "vuetify-nuxt-module/custom-configuration"
|
||||
import { md3 } from "vuetify/blueprints"
|
||||
|
||||
export default defineVuetifyConfiguration({
|
||||
blueprint: md3,
|
||||
icons: {
|
||||
defaultSet: "mdi"
|
||||
},
|
||||
theme: {
|
||||
defaultTheme: "system",
|
||||
themes: {
|
||||
light: {
|
||||
colors: {
|
||||
background: "#f0f4fa",
|
||||
surface: "#ffffff",
|
||||
primary: "#3f51b5",
|
||||
secondary: "#2196f3",
|
||||
accent: "#009688",
|
||||
error: "#f44336",
|
||||
warning: "#ffc107",
|
||||
info: "#03a9f4",
|
||||
success: "#4caf50"
|
||||
}
|
||||
},
|
||||
dark: {
|
||||
dark: true,
|
||||
colors: {
|
||||
background: "#1e1f20",
|
||||
surface: "#0e0e0e",
|
||||
primary: "#3f51b5",
|
||||
secondary: "#2196f3",
|
||||
accent: "#009688",
|
||||
error: "#f44336",
|
||||
warning: "#ffc107",
|
||||
info: "#03a9f4",
|
||||
success: "#4caf50"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
date: {
|
||||
adapter: "luxon"
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user