♻️ 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>
|
<template>
|
||||||
<nuxt-loading-indicator :color="colorMode.value == 'dark' ? 'white' : '#3f51b5'" />
|
<naive-config>
|
||||||
<nuxt-layout>
|
<n-config-provider>
|
||||||
<nuxt-page />
|
<n-dialog-provider>
|
||||||
</nuxt-layout>
|
<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>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<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";
|
@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 {
|
@layer base {
|
||||||
:root {
|
:root {
|
||||||
--font-family: "Nunito Variable", "Helvatica", sans-serif;
|
--font-family: "Nunito Variable", "Helvatica", sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
.prose p,
|
html,
|
||||||
.prose h1,
|
body {
|
||||||
.prose h2,
|
font-family: var(--font-family);
|
||||||
.prose h3,
|
|
||||||
.prose h4,
|
|
||||||
.prose h5,
|
|
||||||
.prose h6,
|
|
||||||
.prose ul,
|
|
||||||
.prose ol,
|
|
||||||
.prose blockquote {
|
|
||||||
margin: revert;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@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-enter-active,
|
||||||
.page-leave-active {
|
.page-leave-active {
|
||||||
transition: all 0.4s;
|
transition: all 0.4s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-enter-from,
|
.page-enter-from,
|
||||||
.page-leave-to {
|
.page-leave-to {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
filter: blur(1rem);
|
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>
|
<template>
|
||||||
<div class="d-flex justify-center">
|
<div class="flex justify-center">
|
||||||
<div v-if="provider === 'cloudflare'">
|
<div v-if="provider === 'cloudflare'">
|
||||||
<turnstile v-if="!!apiKey" :sitekey="apiKey" @callback="handleSuccess" />
|
<turnstile v-if="!!apiKey" :sitekey="apiKey" @callback="handleSuccess" />
|
||||||
<div v-else class="mx-auto">
|
<div v-else class="mx-auto">
|
||||||
<v-progress-circular indeterminate />
|
<n-spin />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="provider === 'hcaptcha'">
|
<div v-else-if="provider === 'hcaptcha'">
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
@verify="(tk: string) => handleSuccess(tk)"
|
@verify="(tk: string) => handleSuccess(tk)"
|
||||||
/>
|
/>
|
||||||
<div v-else class="mx-auto">
|
<div v-else class="mx-auto">
|
||||||
<v-progress-circular indeterminate />
|
<n-spin />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@@ -21,8 +21,8 @@
|
|||||||
class="h-captcha"
|
class="h-captcha"
|
||||||
:data-sitekey="apiKey"
|
:data-sitekey="apiKey"
|
||||||
/>
|
/>
|
||||||
<div v-else class="d-flex flex-column align-center justify-center gap-1">
|
<div v-else class="flex flex-col items-center justify-center gap-1">
|
||||||
<v-icon size="32"> mdi-alert-circle-outline </v-icon>
|
<span class="mdi mdi-alert-circle-outline text-3xl"></span>
|
||||||
<span>Captcha provider not configured correctly.</span>
|
<span>Captcha provider not configured correctly.</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,30 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-container class="footer">
|
<div class="container absolute bottom-5 left-1/2 -translate-x-1/2">
|
||||||
<div class="d-flex justify-space-between align-center">
|
<div class="flex justify-between items-center">
|
||||||
<v-select
|
<n-select
|
||||||
:items="['English (United States)']"
|
:options="[{ label: 'English (United States)', value: 'en-us' }]"
|
||||||
model-value="English (United States)"
|
model-value="en-us"
|
||||||
variant="plain"
|
size="small"
|
||||||
density="compact"
|
|
||||||
hide-details
|
|
||||||
class="flex-grow-0"
|
class="flex-grow-0"
|
||||||
/>
|
/>
|
||||||
<div class="d-flex">
|
<div class="flex">
|
||||||
<v-btn variant="text" size="small" class="text-capitalize">Help</v-btn>
|
<n-button text size="small">Help</n-button>
|
||||||
<v-btn variant="text" size="small" class="text-capitalize"
|
<n-button text size="small">Privacy</n-button>
|
||||||
>Privacy</v-btn
|
<n-button text size="small">Terms</n-button>
|
||||||
>
|
|
||||||
<v-btn variant="text" size="small" class="text-capitalize">Terms</v-btn>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</v-container>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.footer {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 20px;
|
|
||||||
left: 50%;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -1,19 +1,20 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
<pub-select v-model:value="publisher" />
|
<pub-select v-model:value="publisher" />
|
||||||
<v-textarea
|
<n-input
|
||||||
v-model="content"
|
v-model:value="content"
|
||||||
|
type="textarea"
|
||||||
placeholder="What's happended?!"
|
placeholder="What's happended?!"
|
||||||
@keydown.meta.enter.exact="submit"
|
@keydown.meta.enter.exact="submit"
|
||||||
@keydown.ctrl.enter.exact="submit"
|
@keydown.ctrl.enter.exact="submit"
|
||||||
/>
|
/>
|
||||||
<div class="flex justify-between">
|
<div class="flex justify-between">
|
||||||
<v-btn type="primary" :loading="submitting" @click="submit">
|
<n-button type="primary" :loading="submitting" @click="submit">
|
||||||
Post
|
Post
|
||||||
<template #append>
|
<template #icon>
|
||||||
<v-icon>mdi-send</v-icon>
|
<span class="mdi mdi-send"></span>
|
||||||
</template>
|
</template>
|
||||||
</v-btn>
|
</n-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-card :flat="props.flat">
|
<div :class="['card', { 'shadow-none': props.flat }]">
|
||||||
<v-card-text :style="props.slim ? 'padding: 0' : null">
|
<div :class="['card-body', { 'p-0': props.slim }]">
|
||||||
<div :class="['flex flex-col', compact ? 'gap-1' : 'gap-3']">
|
<div :class="['flex flex-col', compact ? 'gap-1' : 'gap-3']">
|
||||||
<post-header :item="props.item" :compact="compact" />
|
<post-header :item="props.item" :compact="compact" />
|
||||||
|
|
||||||
@@ -21,50 +21,42 @@
|
|||||||
</article>
|
</article>
|
||||||
|
|
||||||
<template v-if="showReferenced">
|
<template v-if="showReferenced">
|
||||||
<div v-if="props.item.repliedPost || props.item.repliedGone">
|
<div v-if="props.item.repliedPost || props.item.repliedGone" class="border rounded-md">
|
||||||
<v-card
|
<div class="p-2 flex items-center gap-2">
|
||||||
title="Replying to"
|
<span class="mdi mdi-reply"></span>
|
||||||
prepend-icon="mdi-reply"
|
<span class="font-bold">Replying to</span>
|
||||||
density="compact"
|
</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
|
flat
|
||||||
border
|
@react="handleReaction"
|
||||||
>
|
/>
|
||||||
<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>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="props.item.forwardedPost || props.item.forwardedGone">
|
<div v-if="props.item.forwardedPost || props.item.forwardedGone" class="border rounded-md">
|
||||||
<v-card
|
<div class="p-2 flex items-center gap-2">
|
||||||
title="Forwarded"
|
<span class="mdi mdi-forward"></span>
|
||||||
prepend-icon="mdi-forward"
|
<span class="font-bold">Forwarded</span>
|
||||||
density="compact"
|
</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
|
flat
|
||||||
border
|
@react="handleReaction"
|
||||||
>
|
/>
|
||||||
<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>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -74,22 +66,19 @@
|
|||||||
:max-height="640"
|
:max-height="640"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<v-lazy
|
<div ref="repliesTarget">
|
||||||
v-if="props.item.repliesCount && !compact"
|
|
||||||
:options="{ threshold: 0.5 }"
|
|
||||||
transition="fade-transition"
|
|
||||||
>
|
|
||||||
<replies-compact-list
|
<replies-compact-list
|
||||||
|
v-if="props.item.repliesCount && !compact && repliesVisible"
|
||||||
:params="{ postId: props.item.id }"
|
:params="{ postId: props.item.id }"
|
||||||
:hide-quick-reply="true"
|
:hide-quick-reply="true"
|
||||||
@react="handleReplyReaction"
|
@react="handleReplyReaction"
|
||||||
/>
|
/>
|
||||||
</v-lazy>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="props.item.isTruncated"
|
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>
|
<p>Post truncated, tap to see details...</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -104,14 +93,15 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</v-card-text>
|
</div>
|
||||||
</v-card>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, watch } from "vue"
|
import { ref, watch } from "vue"
|
||||||
import { useMarkdownProcessor } from "~/composables/useMarkdownProcessor"
|
import { useMarkdownProcessor } from "~/composables/useMarkdownProcessor"
|
||||||
import type { SnPost } from "~/types/api"
|
import type { SnPost } from "~/types/api"
|
||||||
|
import { useIntersectionObserver } from '@vueuse/core'
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
@@ -156,4 +146,19 @@ watch(
|
|||||||
},
|
},
|
||||||
{ immediate: true, deep: true }
|
{ immediate: true, deep: true }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const repliesTarget = ref(null)
|
||||||
|
const repliesVisible = ref(false)
|
||||||
|
|
||||||
|
useIntersectionObserver(
|
||||||
|
repliesTarget,
|
||||||
|
([{ isIntersecting }]) => {
|
||||||
|
if (isIntersecting) {
|
||||||
|
repliesVisible.value = true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
threshold: 0.5
|
||||||
|
}
|
||||||
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,38 +1,19 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-select
|
<n-select
|
||||||
:items="pubStore.publishers"
|
:options="pubStore.publishers"
|
||||||
item-title="nick"
|
label-field="nick"
|
||||||
item-value="name"
|
value-field="name"
|
||||||
:model-value="props.value"
|
:value="props.value"
|
||||||
@update:model-value="(v) => emits('update:value', v)"
|
@update:value="(v) => emits('update:value', v)"
|
||||||
>
|
:render-label="renderLabel"
|
||||||
<template #item="{ props: itemProps, item }">
|
:render-tag="renderTag"
|
||||||
<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>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { usePubStore } from '~/stores/pub'
|
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 pubStore = usePubStore()
|
||||||
const apiBase = useSolarNetworkUrl()
|
const apiBase = useSolarNetworkUrl()
|
||||||
@@ -40,6 +21,38 @@ const apiBase = useSolarNetworkUrl()
|
|||||||
const props = defineProps<{ value: string | undefined }>()
|
const props = defineProps<{ value: string | undefined }>()
|
||||||
const emits = defineEmits(['update:value'])
|
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(
|
watch(
|
||||||
pubStore,
|
pubStore,
|
||||||
(value) => {
|
(value) => {
|
||||||
|
|||||||
@@ -6,15 +6,15 @@
|
|||||||
<span>FloatingIsland</span>
|
<span>FloatingIsland</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-wrap gap-1.5">
|
<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
|
Terms of Services
|
||||||
</a>
|
</a>
|
||||||
<span class="font-bold">·</span>
|
<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
|
Service Status
|
||||||
</a>
|
</a>
|
||||||
<span class="font-bold">·</span>
|
<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>
|
</div>
|
||||||
<p class="mt-2 opacity-80">
|
<p class="mt-2 opacity-80">
|
||||||
The FloatingIsland do not provides all the features the Solar Network has,
|
The FloatingIsland do not provides all the features the Solar Network has,
|
||||||
@@ -23,9 +23,3 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.link:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -1,66 +1,34 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-app :theme="colorMode.preference">
|
<div class="flex flex-col min-h-screen" :data-theme="colorMode.preference">
|
||||||
<v-app-bar elevation="2" color="surface-lighten-5">
|
<header class="navbar bg-base-100 shadow-lg">
|
||||||
<v-container class="mx-auto flex align-center justify-center">
|
<div class="container mx-auto flex items-center justify-center">
|
||||||
<img
|
<img :src="colorMode.value == 'dark' ? IconDark : IconLight" width="32" height="32" class="mr-4"
|
||||||
:src="colorMode.value == 'dark' ? IconDark : IconLight"
|
alt="The Solar Network" />
|
||||||
width="32"
|
|
||||||
height="32"
|
|
||||||
class="me-4"
|
|
||||||
alt="The Solar Network"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<v-btn
|
<n-button v-for="link in links" :key="link.title" text @click="() => router.push(link.href)">
|
||||||
v-for="link in links"
|
<template #icon>
|
||||||
:key="link.title"
|
<span :class="`mdi ${link.icon}`"></span>
|
||||||
: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
|
|
||||||
"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
<v-list density="compact">
|
{{ link.title }}
|
||||||
<v-list-item v-if="!user" to="/auth/login" prepend-icon="mdi-login"
|
</n-button>
|
||||||
>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>
|
|
||||||
|
|
||||||
<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 />
|
<slot />
|
||||||
</v-main>
|
</main>
|
||||||
</v-app>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<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 IconDark from "~/assets/images/cloudy-lamb@dark.png"
|
||||||
|
|
||||||
import type { NavLink } from "~/types/navlink"
|
import type { NavLink } from "~/types/navlink"
|
||||||
|
import { computed, h } from "vue"
|
||||||
|
import { useRouter } from "vue-router"
|
||||||
|
|
||||||
const apiBase = useSolarNetworkUrl()
|
const apiBase = useSolarNetworkUrl()
|
||||||
const colorMode = useColorMode()
|
const colorMode = useColorMode()
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
const { user } = useUserStore()
|
const { user } = useUserStore()
|
||||||
|
|
||||||
@@ -81,4 +52,33 @@ const links: NavLink[] = [
|
|||||||
icon: "mdi-compass"
|
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>
|
</script>
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-app :theme="colorMode.preference">
|
<div class="min-h-screen" :data-theme="colorMode.preference">
|
||||||
<v-main>
|
<main>
|
||||||
<slot />
|
<slot />
|
||||||
</v-main>
|
</main>
|
||||||
|
|
||||||
<nuxt-link to="/">
|
<nuxt-link to="/">
|
||||||
<v-footer app fixed flat height="48">
|
<footer
|
||||||
<v-container class="mx-auto d-flex align-center justify-between">
|
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
|
<img
|
||||||
:src="Icon"
|
:src="Icon"
|
||||||
alt="Cloudy Lamb"
|
alt="Cloudy Lamb"
|
||||||
@@ -15,10 +17,10 @@
|
|||||||
class="mr-2"
|
class="mr-2"
|
||||||
/>
|
/>
|
||||||
<p class="text-sm">Solar Network</p>
|
<p class="text-sm">Solar Network</p>
|
||||||
</v-container>
|
</div>
|
||||||
</v-footer>
|
</footer>
|
||||||
</nuxt-link>
|
</nuxt-link>
|
||||||
</v-app>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-container>
|
<div class="container mx-auto">
|
||||||
<div class="layout">
|
<div class="layout">
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<div v-for="activity in activites" :key="activity.id" class="mb-4">
|
<div v-for="activity in activites" :key="activity.id" class="mb-4">
|
||||||
@@ -11,8 +11,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sidebar flex flex-col gap-3">
|
<div class="sidebar flex flex-col gap-3">
|
||||||
<v-card v-if="!userStore.isAuthenticated" class="w-full" title="About">
|
<div v-if="!userStore.isAuthenticated" class="card w-full bg-base-100 shadow-xl">
|
||||||
<v-card-text>
|
<div class="card-body">
|
||||||
|
<h2 class="card-title">About</h2>
|
||||||
<p>Welcome to the <b>Solar Network</b></p>
|
<p>Welcome to the <b>Solar Network</b></p>
|
||||||
<p>The open social network. Friendly to everyone.</p>
|
<p>The open social network. Friendly to everyone.</p>
|
||||||
|
|
||||||
@@ -24,17 +25,17 @@
|
|||||||
{{ version.updatedAt }}
|
{{ version.updatedAt }}
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
</v-card-text>
|
</div>
|
||||||
</v-card>
|
</div>
|
||||||
<v-card v-else class="w-full">
|
<div v-else class="card w-full bg-base-100 shadow-xl">
|
||||||
<v-card-text>
|
<div class="card-body">
|
||||||
<post-editor @posted="refreshActivities" />
|
<post-editor @posted="refreshActivities" />
|
||||||
</v-card-text>
|
</div>
|
||||||
</v-card>
|
</div>
|
||||||
<sidebar-footer class="max-lg:hidden" />
|
<sidebar-footer class="max-lg:hidden" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</v-container>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<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
|
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||||
export default defineNuxtConfig({
|
export default defineNuxtConfig({
|
||||||
@@ -8,15 +11,13 @@ export default defineNuxtConfig({
|
|||||||
"@nuxt/image",
|
"@nuxt/image",
|
||||||
"@nuxt/eslint",
|
"@nuxt/eslint",
|
||||||
"@pinia/nuxt",
|
"@pinia/nuxt",
|
||||||
"vuetify-nuxt-module",
|
|
||||||
"@nuxtjs/i18n",
|
"@nuxtjs/i18n",
|
||||||
"@nuxtjs/color-mode",
|
"@nuxtjs/color-mode",
|
||||||
"nuxt-og-image"
|
"nuxt-og-image",
|
||||||
|
"@bg-dev/nuxt-naiveui",
|
||||||
],
|
],
|
||||||
css: [
|
css: [
|
||||||
"~/assets/css/main.css",
|
"~/assets/css/main.css",
|
||||||
"~/assets/css/globals.scss",
|
|
||||||
"katex/dist/katex.min.css"
|
|
||||||
],
|
],
|
||||||
app: {
|
app: {
|
||||||
pageTransition: { name: "page", mode: "out-in" },
|
pageTransition: { name: "page", mode: "out-in" },
|
||||||
@@ -67,15 +68,23 @@ export default defineNuxtConfig({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
vite: {
|
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/color-mode": "3.5.2",
|
||||||
"@nuxtjs/i18n": "10.1.0",
|
"@nuxtjs/i18n": "10.1.0",
|
||||||
"@pinia/nuxt": "0.11.2",
|
"@pinia/nuxt": "0.11.2",
|
||||||
"@tailwindcss/typography": "^0.5.19",
|
|
||||||
"@tailwindcss/vite": "^4.1.17",
|
"@tailwindcss/vite": "^4.1.17",
|
||||||
"@vueuse/core": "^13.9.0",
|
"@vueuse/core": "^13.9.0",
|
||||||
"blurhash": "^2.0.5",
|
"blurhash": "^2.0.5",
|
||||||
@@ -33,20 +32,23 @@
|
|||||||
"markdown-it-texmath": "^1.0.0",
|
"markdown-it-texmath": "^1.0.0",
|
||||||
"nuxt": "^4.2.1",
|
"nuxt": "^4.2.1",
|
||||||
"nuxt-og-image": "^5.1.12",
|
"nuxt-og-image": "^5.1.12",
|
||||||
|
"nuxtjs-naive-ui": "1.0.2",
|
||||||
"pinia": "^3.0.4",
|
"pinia": "^3.0.4",
|
||||||
"sharp": "^0.34.5",
|
"sharp": "^0.34.5",
|
||||||
"swagger-themes": "^1.4.3",
|
"swagger-themes": "^1.4.3",
|
||||||
"swagger-ui-dist": "^5.30.2",
|
"swagger-ui-dist": "^5.30.2",
|
||||||
"tailwindcss": "^4.1.17",
|
|
||||||
"tus-js-client": "^4.3.1",
|
"tus-js-client": "^4.3.1",
|
||||||
"vue": "^3.5.24",
|
"vue": "^3.5.24",
|
||||||
"vue-router": "^4.6.3",
|
"vue-router": "^4.6.3"
|
||||||
"vuetify-nuxt-module": "0.18.7"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@bg-dev/nuxt-naiveui": "^2.0.0",
|
||||||
"@mdi/font": "^7.4.47",
|
"@mdi/font": "^7.4.47",
|
||||||
|
"@tailwindcss/typography": "^0.5.19",
|
||||||
"@types/luxon": "^3.7.1",
|
"@types/luxon": "^3.7.1",
|
||||||
"@types/node": "^24.10.0",
|
"@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