Compare commits

...

3 Commits

Author SHA1 Message Date
e4111dc06e 💄 Optimized header & landing page 2025-03-17 22:23:40 +08:00
3e7f259834 🗑️ Clean up layouts 2025-03-17 21:10:33 +08:00
97449bdc1e 🗑️ Clean up posts 2025-03-17 20:58:36 +08:00
13 changed files with 272 additions and 210 deletions

View File

@ -3,10 +3,12 @@
<v-card-text>
<div class="mb-3 flex flex-row gap-4">
<nuxt-link :to="`/users/${post.publisher?.name}`">
<v-avatar :image="post.publisher?.avatar" />
<v-avatar :image="getAttachmentUrl(post.publisher?.avatar)" icon="mdi-account-circle" />
</nuxt-link>
<div class="flex flex-col">
<span>{{ post.publisher?.nick }} <span class="text-xs">@{{ post.publisher?.name }}</span></span>
<span
>{{ post.publisher?.nick }} <span class="text-xs">@{{ post.publisher?.name }}</span></span
>
<span v-if="post.body?.title" class="text-md">{{ post.body?.title }}</span>
<span v-if="post.body?.description" class="text-sm">{{ post.body?.description }}</span>
<span v-if="!post.body?.title && !post.body?.description" class="text-sm">
@ -29,7 +31,7 @@
/>
</div>
<article v-if="post.type == 'story' || props.forceShowContent" class="text-base prose max-w-none">
<article v-if="(post.type == 'story' || props.forceShowContent) && post.body?.content" class="text-base prose max-w-none">
<m-d-c :value="post.body?.content"></m-d-c>
</article>
@ -42,9 +44,7 @@
<div class="text-sm flex flex-col">
<span class="flex flex-row gap-1">
<span>
{{ post.metric.reply_count }} {{ post.metric.reply_count > 1 ? "replies" : "reply" }},
</span>
<span> {{ post.metric.reply_count }} {{ post.metric.reply_count > 1 ? "replies" : "reply" }}, </span>
<span>
{{ post.metric.reaction_count }} {{ post.metric.reaction_count > 1 ? "reactions" : "reaction" }}
</span>
@ -55,10 +55,7 @@
</span>
</div>
<div
v-if="post.tags?.length > 0"
class="text-xs text-grey flex flex-row gap-1 mt-3"
>
<div v-if="post.tags?.length > 0" class="text-xs text-grey flex flex-row gap-1 mt-3">
<nuxt-link
v-for="tag in post.tags"
:to="`/posts/tags/${tag.alias}`"
@ -73,10 +70,12 @@
</template>
<script setup lang="ts">
const props = defineProps<{ post: any, forceShowContent?: boolean, noClickableAttachment?: boolean }>()
const props = defineProps<{ post: any; forceShowContent?: boolean; noClickableAttachment?: boolean }>()
const config = useRuntimeConfig()
const { t } = useI18n()
const url = computed(() => props.post.alias ? `/posts/${props.post.area_alias}/${props.post.alias}` : `/posts/${props.post.id}`)
const url = computed(() =>
props.post.alias ? `/posts/${props.post.area_alias}/${props.post.alias}` : `/posts/${props.post.id}`,
)
</script>

View File

@ -5,13 +5,11 @@
</v-alert>
</v-expand-transition>
<v-data-table-server
<v-data-table
density="compact"
:headers="dataDefinitions.stickers"
:items="stickers"
:items-length="pagination.stickers.total"
:loading="reverting.stickers"
v-model:items-per-page="pagination.stickers.pageSize"
@update:options="readStickers"
item-value="id"
>
@ -74,23 +72,24 @@
<template v-slot:default="{ isActive }">
<v-card :title="`Delete sticker #${item.id}?`">
<v-card-text>
This action will delete this sticker, all content used it will no longer show your sticker.
But the attachment will still exists.
This action will delete this sticker, all content used it will no longer show your sticker. But the
attachment will still exists.
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
text="Cancel"
color="grey"
@click="isActive.value = false"
></v-btn>
<v-btn text="Cancel" color="grey" @click="isActive.value = false"></v-btn>
<v-btn
text="Delete"
color="error"
@click="() => { deleteSticker(item); isActive.value = false }"
@click="
() => {
deleteSticker(item)
isActive.value = false
}
"
/>
</v-card-actions>
</v-card>
@ -99,7 +98,7 @@
</td>
</tr>
</template>
</v-data-table-server>
</v-data-table>
</template>
<script setup lang="ts">
@ -108,7 +107,7 @@ import { solarFetch } from "~/utils/request"
const config = useRuntimeConfig()
const { t } = useI18n()
const props = defineProps<{ packId: number, packPrefix?: string }>()
const props = defineProps<{ packId: number; packPrefix?: string }>()
const error = ref<null | string>(null)
@ -125,34 +124,20 @@ const dataDefinitions: { [id: string]: any[] } = {
const stickers = ref<any>([])
const reverting = reactive({ stickers: false })
const pagination = reactive({
stickers: { page: 1, pageSize: 5, total: 0 },
})
async function readStickers({ page, itemsPerPage }: { page?: number; itemsPerPage?: number }) {
if (itemsPerPage) pagination.stickers.pageSize = itemsPerPage
if (page) pagination.stickers.page = page
async function readStickers() {
reverting.stickers = true
const res = await solarFetch(
"/cgi/uc/stickers?" +
new URLSearchParams({
pack: props.packId.toString(),
take: pagination.stickers.pageSize.toString(),
offset: ((pagination.stickers.page - 1) * pagination.stickers.pageSize).toString(),
}),
)
const res = await solarFetch("/cgi/uc/stickers/packs/" + props.packId)
if (res.status !== 200) {
error.value = await res.text()
} else {
const data = await res.json()
stickers.value = data["data"]
pagination.stickers.total = data["count"]
stickers.value = data["stickers"]
}
reverting.stickers = false
}
onMounted(() => readStickers({}))
onMounted(() => readStickers())
const submitting = ref(false)
@ -165,7 +150,7 @@ async function deleteSticker(item: any) {
if (res.status !== 200) {
error.value = await res.text()
} else {
await readStickers({})
await readStickers()
}
submitting.value = false

View File

@ -1,17 +1,10 @@
<template>
<v-app-bar flat color="primary" scroll-behavior="hide" scroll-threshold="800">
<v-container fluid class="mx-auto d-flex align-center justify-center px-8">
<v-tooltip>
<template #activator="{ props }">
<div @click="openDrawer = !openDrawer" v-bind="props" class="cursor-pointer">
<v-img class="me-4 ms-1" width="32" height="32" alt="Logo" :src="Logo" />
</div>
</template>
Open / close drawer
</v-tooltip>
<v-app-bar-nav-icon @click="openDrawer = !openDrawer" />
<nuxt-link to="/dev" exact>
<h2 class="mt-1">Creator Hub</h2>
<nuxt-link to="/creator" exact>
<h2>Creator Hub</h2>
</nuxt-link>
<v-spacer></v-spacer>
@ -45,12 +38,10 @@
</template>
<script setup lang="ts">
import Logo from "../assets/logo-w-shadow.png"
const { t } = useI18n()
const openDrawer = ref(false)
useHead({
titleTemplate: "%s | Solsynth Creator Hub"
titleTemplate: "%s | Solsynth Creator Hub",
})
</script>

View File

@ -1,41 +1,38 @@
<template>
<v-app-bar flat color="primary">
<v-container fluid class="mx-auto d-flex align-center justify-center px-8">
<v-tooltip>
<template #activator="{ props }">
<div @click="openDrawer = !openDrawer" v-bind="props" class="cursor-pointer">
<v-img class="me-4 ms-1" width="32" height="32" alt="Logo" :src="Logo" />
</div>
</template>
Open / close drawer
</v-tooltip>
<v-app-bar app flat color="surface" class="app-bar-blur">
<v-container fluid class="mx-auto d-flex align-center justify-center pr-8">
<v-app-bar-nav-icon @click="openDrawer = !openDrawer" />
<nuxt-link to="/" exact>
<h2 class="mt-1">Solsynth LLC</h2>
<h2>Solsynth LLC</h2>
</nuxt-link>
<v-spacer></v-spacer>
<div class="flex gap-2">
<v-btn to="/products" exact prepend-icon="mdi-shape">{{ t("navProducts") }}</v-btn>
<v-btn to="/posts" exact prepend-icon="mdi-note-text">{{ t("navPosts") }}</v-btn>
<v-btn to="/gallery" exact prepend-icon="mdi-image-multiple">{{ t("navGallery") }}</v-btn>
</div>
<v-spacer></v-spacer>
<locale-select />
<user-menu />
</v-container>
</v-app-bar>
<v-navigation-drawer v-model="openDrawer" location="left" width="300" floating>
<v-navigation-drawer v-model="openDrawer" location="left" width="300" temporary order="-1">
<v-list density="compact" nav color="primary">
<v-list-item :title="t('navProducts')" prepend-icon="mdi-shape" to="/products" exact />
<v-list-item :title="t('navPosts')" prepend-icon="mdi-note-text" to="/posts" exact />
<v-list-item :title="t('navActivity')" prepend-icon="mdi-newspaper-variant-multiple-outline" to="/activity" exact />
<v-list-item :title="t('navGallery')" prepend-icon="mdi-image-multiple" to="/gallery" exact />
<v-list-item title="Knowledge Base" prepend-icon="mdi-library" to="/docs" exact />
<v-list-item title="Developer Portal" prepend-icon="mdi-code-tags" to="/dev" exact />
<v-list-item title="Creator Hub" prepend-icon="mdi-pencil" to="/creator" exact />
</v-list>
<v-divider class="border-opacity-50 my-1" />
<v-list density="compact" nav color="primary">
<v-list-item title="Knowledge Base" prepend-icon="mdi-library" to="/docs" exact />
<v-list-item title="Developer Portal" prepend-icon="mdi-code-tags" to="/dev" exact />
<v-list-item title="Creator Hub" prepend-icon="mdi-pencil" to="/creator" exact />
<v-list-item title="Code Repository" prepend-icon="mdi-git" href="https://git.solsynth.dev" target="_blank" />
</v-list>
<v-divider class="border-opacity-50 mb-4 mt-0.5" />
@ -51,9 +48,16 @@
</template>
<script setup lang="ts">
import Logo from "../assets/logo-w-shadow.png"
const { t } = useI18n()
const openDrawer = ref(false)
</script>
<style lang="css" scoped>
.app-bar-blur {
-webkit-mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 1) 40%, rgba(0, 0, 0, 0.5) 65%, rgba(0, 0, 0, 0) 100%);
mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 1) 40%, rgba(0, 0, 0, 0.5) 65%, rgba(0, 0, 0, 0) 100%);
mask-repeat: no-repeat;
mask-size: 100%;
}
</style>

View File

@ -1,17 +1,10 @@
<template>
<v-app-bar flat color="primary" scroll-behavior="hide" scroll-threshold="800">
<v-container fluid class="mx-auto d-flex align-center justify-center px-8">
<v-tooltip>
<template #activator="{ props }">
<div @click="openDrawer = !openDrawer" v-bind="props" class="cursor-pointer">
<v-img class="me-4 ms-1" width="32" height="32" alt="Logo" :src="Logo" />
</div>
</template>
Open / close drawer
</v-tooltip>
<v-container fluid class="mx-auto d-flex align-center justify-center pr-8">
<v-app-bar-nav-icon @click="openDrawer = !openDrawer" />
<nuxt-link to="/dev" exact>
<h2 class="mt-1">Developer Portal</h2>
<h2>Developer Portal</h2>
</nuxt-link>
<v-spacer></v-spacer>
@ -51,6 +44,6 @@ const { t } = useI18n()
const openDrawer = ref(false)
useHead({
titleTemplate: "%s | Solsynth Dev Portal"
titleTemplate: "%s | Solsynth Dev Portal",
})
</script>

View File

@ -151,7 +151,7 @@ export default defineNuxtConfig({
"@pinia/nuxt",
"@nuxtjs/i18n",
"nuxt-schema-org",
"nuxt-gtag",
"@vueuse/motion/nuxt",
(_options, nuxt) => {
nuxt.hooks.hook("vite:extendConfig", (config) => {
// @ts-expect-error

View File

@ -17,6 +17,7 @@
"@nuxtjs/i18n": "^8.5.6",
"@nuxtjs/sitemap": "^6.1.5",
"@pinia/nuxt": "^0.5.5",
"@vueuse/motion": "^3.0.3",
"feed": "^4.2.2",
"nuxt": "^3.16.0",
"nuxt-gtag": "^2.1.0",

View File

@ -1,37 +0,0 @@
<template>
<v-container class="content-container mx-auto">
<div class="my-3 mx-[1.5ch]">
<div class="flex gap-1">
<h1 class="text-2xl">{{ t("navActivity") }}</h1>
<v-btn size="x-small" variant="text" icon="mdi-rss" slim to="/activity/feed" />
</div>
<span>{{ t("navActivityCaption") }}</span>
</div>
<post-list class="mx-[-2.5ch]" :realm="config.public.solarRealm" />
</v-container>
</template>
<script setup lang="ts">
const { t } = useI18n()
useHead({
title: t("navActivity"),
})
useSeoMeta({
title: t("navActivity"),
ogTitle: t("navActivity"),
description: t("navActivityCaption"),
ogDescription: t("navActivityCaption"),
ogType: "website",
})
const config = useRuntimeConfig()
</script>
<style scoped>
.content-container {
max-width: 70ch !important;
}
</style>

View File

@ -6,13 +6,7 @@
</div>
<div class="flex gap-2">
<v-btn
color="primary"
text="New"
append-icon="mdi-plus"
variant="tonal"
to="/creator/stickers/new"
/>
<v-btn color="primary" text="New" append-icon="mdi-plus" variant="tonal" to="/creator/stickers/new" />
</div>
</div>
@ -24,10 +18,7 @@
<div class="mt-5">
<v-expansion-panels>
<v-expansion-panel
v-for="item in data"
:key="'sticker-pack#'+item.id"
>
<v-expansion-panel v-for="item in data" :key="'sticker-pack#' + item.id">
<template #title>
<div class="flex items-center gap-2">
<p>{{ item.name }}</p>
@ -87,16 +78,17 @@
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
text="Cancel"
color="grey"
@click="isActive.value = false"
></v-btn>
<v-btn text="Cancel" color="grey" @click="isActive.value = false"></v-btn>
<v-btn
text="Delete"
color="error"
@click="() => { deletePack(item); isActive.value = false }"
@click="
() => {
deletePack(item)
isActive.value = false
}
"
/>
</v-card-actions>
</v-card>
@ -131,6 +123,7 @@ useHead({
})
const { t } = useI18n()
const ua = useUserinfo()
const loading = ref(false)
const error = ref<null | string>(null)
@ -140,7 +133,7 @@ const data = ref<any[]>([])
async function readPacks() {
loading.value = true
const res = await solarFetch(`/cgi/uc/stickers/packs?take=10&offset=${data.value.length}`)
const res = await solarFetch(`/cgi/uc/stickers/packs?take=10&author=${ua.userinfo?.id}&offset=${data.value.length}`)
if (res.status != 200) {
error.value = await res.text()
} else {

View File

@ -1,39 +1,71 @@
<template>
<v-container class="flex flex-col my-2 px-12 gap-[4rem]">
<v-row class="content-section">
<v-col cols="12" md="4" class="flex justify-start">
<div class="flex flex-col items-start">
<h1 class="text-4xl font-bold">{{ t("brandName") }}</h1>
<p class="text-lg mt-3 max-w-2/3">
{{ t("indexIntroduce") }}
</p>
<p class="text-grey mt-2">
{{ t("indexProductListHint") }}
<v-icon icon="mdi-arrow-right" size="16" class="mb-0.5" />
</p>
</div>
</v-col>
<v-col cols="12" md="8">
<v-card>
<section class="content-section flex flex-col items-center justify-center text-center px-4">
<img
v-motion="{
initial: {
y: 100,
opacity: 0,
},
enter: {
y: 0,
opacity: 1,
},
}"
:src="Logo"
alt="Company Logo"
class="w-32 h-32 mb-4"
/>
<h1 class="text-4xl font-bold">Welcome to {{ t("brandName") }}</h1>
<p class="mt-2 text-lg">Building cool, open-source, and elegant apps for human.</p>
<v-btn class="mt-4" color="primary" prepend-icon="mdi-arrow-down" href="#products">{{ t("learnMore") }}</v-btn>
</section>
<section class="content-section py-16" id="products">
<div class="container mx-auto text-center">
<h2 class="text-3xl font-bold">Our Projects</h2>
<p>Take a peek of our works.</p>
<v-card class="mt-12">
<product-carousel class="carousel-section" :products="products as any[]" />
</v-card>
</v-col>
</v-row>
</div>
</section>
<v-row class="content-section">
<v-col cols="12" md="8">
<v-card class="h-[500px]">
<activity-list class="carousel-section" />
<v-col cols="12" md="6">
<v-card>
<v-list>
<v-list-item
title="GitHub"
subtitle="The place hosts most of our public projects' code"
prepend-icon="mdi-github"
href="https://github.com/Solsynth"
target="_blank"
/>
<v-list-item
lines="two"
title="Solsynth Code Repository"
subtitle="Our self-hosted git server, may contains some unpublished projects' code"
prepend-icon="mdi-git"
href="https://git.solsynth.dev/explore"
target="_blank"
/>
</v-list>
</v-card>
</v-col>
<v-col cols="12" md="4" class="flex justify-end" order="first" order-md="last">
<v-col cols="12" md="6" class="flex justify-end" order="first" order-md="last">
<div class="text-right flex flex-col items-end">
<h2 class="text-4xl font-bold">{{ t("indexActivities") }}</h2>
<p class="text-lg mt-3 max-w-2/3">
{{ t("indexActivitiesCaption") }}
<h2 class="text-4xl font-bold">
We<br />
Open-source
</h2>
<p class="text-md mt-3 max-w-2/3">
No software can run without the support of open source software, and our software is no exception.
Therefore, we feel it is important to contribute to open source as well.
</p>
<p class="text-grey mt-2">
<v-icon icon="mdi-arrow-left" size="16" class="mb-0.5" />
{{ t("indexActivitiesHint") }}
Check out our GitHub
</p>
</div>
</v-col>
@ -42,6 +74,8 @@
</template>
<script setup lang="ts">
import Logo from "../assets/logo-w-shadow.png"
import { getLocale } from "~/utils/locale"
const { t } = useI18n()
@ -61,13 +95,16 @@ useSeoMeta({
})
const { data: products } = await useAsyncData("products", () => {
return queryContent("/products").where({ _locale: getLocale(), archived: { $ne: true } }).limit(5).find()
return queryContent("/products")
.where({ _locale: getLocale(), archived: { $ne: true } })
.limit(5)
.find()
})
</script>
<style scoped>
.carousel-section {
height: 96rem;
height: 120rem;
}
.content-section {
@ -76,3 +113,10 @@ const { data: products } = await useAsyncData("products", () => {
place-items: center;
}
</style>
<style>
body,
html {
scroll-behavior: smooth;
}
</style>

View File

@ -1,14 +1,19 @@
<template>
<v-container class="content-container mx-auto">
<div class="my-3 flex flex-row gap-4">
<nuxt-link :to="`/users/${post.publisher?.name}`">
<v-avatar :image="post.publisher?.avatar" />
<nuxt-link :to="`/publishers/${post.publisher?.name}`">
<v-avatar :image="getAttachmentUrl(post.publisher?.avatar)" />
</nuxt-link>
<div class="flex flex-col">
<span>{{ post.publisher?.nick }} <span class="text-xs">@{{ post.publisher?.name }}</span></span>
<span>
{{ post.publisher?.nick }}
<span class="text-xs">@{{ post.publisher?.name }}</span>
</span>
<span v-if="post.body?.title" class="text-md">{{ post.body?.title }}</span>
<span v-if="post.body?.description" class="text-sm">{{ post.body?.description }}</span>
<span v-if="!post.body?.title && !post.body?.description" class="text-sm">{{ post.publisher?.description }}</span>
<span v-if="!post.body?.title && !post.body?.description" class="text-sm">{{
post.publisher?.description
}}</span>
</div>
</div>
@ -20,22 +25,18 @@
/>
</v-card>
<article class="text-base prose xl:text-lg mx-auto">
<article v-if="post.body?.content" class="text-base prose xl:text-lg mx-auto">
<m-d-c :value="post.body?.content"></m-d-c>
</article>
<v-card v-if="post.body?.attachments?.length > 0" class="mb-5">
<attachment-carousel :attachments="post.body?.attachments" @update:metadata="args => attachments = args" />
<attachment-carousel :attachments="post.body?.attachments" @update:metadata="(args) => (attachments = args)" />
</v-card>
<div class="mb-3 text-sm flex flex-col">
<span class="flex flex-row gap-1">
<span>
{{ post.metric.reply_count }} {{ post.metric.reply_count > 1 ? "replies" : "reply" }},
</span>
<span>
{{ post.metric.reaction_count }} {{ post.metric.reaction_count > 1 ? "reactions" : "reaction" }}
</span>
<span> {{ post.metric.reply_count }} {{ post.metric.reply_count > 1 ? "replies" : "reply" }}, </span>
<span> {{ post.metric.reaction_count }} {{ post.metric.reaction_count > 1 ? "reactions" : "reaction" }} </span>
</span>
<span>
{{ post.type.startsWith("a") ? "An" : "A" }} {{ post.type }} posted on
@ -43,10 +44,7 @@
</span>
</div>
<div
v-if="post.tags?.length > 0"
class="text-xs text-grey flex flex-row gap-1 mb-3"
>
<div v-if="post.tags?.length > 0" class="text-xs text-grey flex flex-row gap-1 mb-3">
<nuxt-link
v-for="tag in post.tags"
:to="`/posts/tags/${tag.alias}`"
@ -108,10 +106,16 @@ if (!post.value) {
navigateTo(`/posts/${post.value.area_alias}/${post.value.alias}`)
}
const title = computed(() => post.value.body?.title ? `${post.value.body?.title} by @${post.value.publisher.name}` : `Post by @${post.value.publisher.name}`)
const title = computed(() =>
post.value.body?.title
? `${post.value.body?.title} by @${post.value.publisher.name}`
: `Post by @${post.value.publisher.name}`,
)
const description = computed(() => post.value.body?.description ?? post.value.body?.content.substring(0, 280).trim())
watch(attachments, (value) => {
watch(
attachments,
(value) => {
if (post.value.body?.thumbnail) {
firstImage.value = `${config.public.solarNetworkApi}/cgi/uc/attachments/${post.value.body?.thumbnail}`
}
@ -122,7 +126,9 @@ watch(attachments, (value) => {
if (value.length > 0 && value[0].mimetype.split("/")[0] == "video") {
firstVideo.value = `${config.public.solarNetworkApi}/cgi/uc/attachments/${attachments.value[0].rid}`
}
}, { immediate: true, deep: true })
},
{ immediate: true, deep: true },
)
useHead({
title: title.value,

View File

@ -0,0 +1,73 @@
<template>
<v-container class="mx-auto">
<v-img v-if="urlOfBanner" :src="urlOfBanner" :aspect-ratio="16 / 5" class="rounded-md mb-3" cover />
<div class="mx-[2.5ch]">
<div class="my-5 mx-4 flex flex-row gap-4">
<v-avatar :image="urlOfAvatar" />
<div class="flex flex-col">
<span
>{{ account?.nick }} <span class="text-xs">@{{ account?.name }}</span></span
>
<span class="text-sm">{{ account?.description }}</span>
</div>
</div>
<div class="mb-7">
<v-card rounded="xl" class="mx-[-5px]">
<v-tabs v-model="tab" align-tabs="start" color="primary" hide-slider>
<v-tab :value="1">{{ t("userActivity") }}</v-tab>
</v-tabs>
</v-card>
</div>
<v-row>
<v-col row="12" lg="8">
<post-list class="mx-[-2.5ch] mt-[-16px]" v-if="account" :author="account.name" />
</v-col>
<v-col row="12" lg="4" order="first" order-lg="last">
<div class="sticky top-0 h-fit">
<v-card prepend-icon="mdi-identifier" title="About">
<v-card-text>
<p><b>Description</b></p>
<p>{{ account.description }}</p>
<p class="mt-3"><b>Joined At</b></p>
<p>{{ new Date(account.created_at).toLocaleString() }}</p>
</v-card-text>
</v-card>
</div>
</v-col>
</v-row>
</div>
</v-container>
</template>
<script setup lang="ts">
definePageMeta({
alias: ["/@:name(.*)*"],
})
const { t } = useI18n()
const route = useRoute()
const config = useRuntimeConfig()
const tab = ref(1)
const { data: account } = await useFetch<any>(`${config.public.solarNetworkApi}/cgi/co/publisher/${route.params.name}`)
if (account.value == null) {
throw createError({
statusCode: 404,
statusMessage: "User Not Found",
})
}
const urlOfAvatar = computed(() =>
account.value?.avatar ? `${config.public.solarNetworkApi}/cgi/uc/attachments/${account.value.avatar}` : void 0,
)
const urlOfBanner = computed(() =>
account.value?.banner ? `${config.public.solarNetworkApi}/cgi/uc/attachments/${account.value.banner}` : void 0,
)
const externalOpenLink = computed(() => `${config.public.solianUrl}/accounts/view/${route.params.name}`)
</script>

View File

@ -14,3 +14,13 @@ export async function solarFetch(input: string, init?: RequestInit) {
},
})
}
export function getAttachmentUrl(identifier: string | undefined): string | undefined {
if (identifier == null || identifier.length == 0) {
return undefined
}
if (identifier.startsWith("http")) {
return identifier
}
return `${useRuntimeConfig().public.solarNetworkApi}/cgi/uc/attachments/${identifier}`
}