Compare commits

...

10 Commits

Author SHA1 Message Date
5f1f965292 🚀 Ready to vercel 2024-12-19 22:56:07 +08:00
1bc50aecc5 :magify: Improve SEO 2024-12-19 22:40:26 +08:00
15e1b3971f Post listing 2024-12-19 22:14:32 +08:00
ee33a43ac8 🌐 Basic i18n setup 2024-12-19 00:23:46 +08:00
9ca513f91d Legal informations e.g. terms & conditions 2024-12-18 23:46:25 +08:00
7a0a282451 Complete solar network product page 2024-12-18 22:59:08 +08:00
2d2ec80185 Simple solar network product page 2024-12-17 23:50:10 +08:00
44572badcc Support more type of attachments 2024-12-17 22:22:04 +08:00
fc4c884ade Basic post viewer 2024-12-17 22:12:19 +08:00
f730579eeb 💄 Update navbar 2024-12-16 23:06:08 +08:00
24 changed files with 1184 additions and 112 deletions

6
.prettierrc Normal file
View File

@ -0,0 +1,6 @@
{
"tabWidth": 2,
"singleQuote": true,
"semi": false,
"trailingComma": "es5"
}

View File

@ -1,48 +0,0 @@
# Astro Starter Kit: Basics
```sh
npm create astro@latest -- --template basics
```
[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/astro/tree/latest/examples/basics)
[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/basics)
[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/withastro/astro?devcontainer_path=.devcontainer/basics/devcontainer.json)
> 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun!
![just-the-basics](https://github.com/withastro/astro/assets/2244813/a0a5533c-a856-4198-8470-2d67b1d7c554)
## 🚀 Project Structure
Inside of your Astro project, you'll see the following folders and files:
```text
/
├── public/
│ └── favicon.svg
├── src/
│ ├── layouts/
│ │ └── Layout.astro
│ └── pages/
│ └── index.astro
└── package.json
```
To learn more about the folder structure of an Astro project, refer to [our guide on project structure](https://docs.astro.build/en/basics/project-structure/).
## 🧞 Commands
All commands are run from the root of the project, from a terminal:
| Command | Action |
| :------------------------ | :----------------------------------------------- |
| `npm install` | Installs dependencies |
| `npm run dev` | Starts local dev server at `localhost:4321` |
| `npm run build` | Build your production site to `./dist/` |
| `npm run preview` | Preview your build locally, before deploying |
| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
| `npm run astro -- --help` | Get help using the Astro CLI |
## 👀 Want to learn more?
Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).

View File

@ -1,12 +1,40 @@
// @ts-check
import { defineConfig } from 'astro/config';
import { defineConfig } from 'astro/config'
import tailwind from '@astrojs/tailwind';
import tailwind from '@astrojs/tailwind'
import icon from 'astro-icon';
import icon from 'astro-icon'
import mdx from '@astrojs/mdx'
import sitemap from '@astrojs/sitemap'
import vercel from '@astrojs/vercel';
// https://astro.build/config
export default defineConfig({
integrations: [tailwind(), icon()],
prefetch: true
});
site: 'https://solsynth.dev',
integrations: [
tailwind(),
icon(),
mdx(),
sitemap({
xslURL: '/sitemap.xsl',
i18n: { defaultLocale: 'en', locales: { en: 'en-US', 'zh-cn': 'zh-CN' } },
}),
],
prefetch: true,
i18n: {
locales: ['en', 'zh-cn'],
defaultLocale: 'en',
routing: {
fallbackType: 'rewrite',
prefixDefaultLocale: false,
},
},
adapter: vercel(),
})

BIN
bun.lockb

Binary file not shown.

View File

@ -9,14 +9,22 @@
"astro": "astro"
},
"dependencies": {
"@astrojs/mdx": "^4.0.2",
"@astrojs/sitemap": "^3.2.1",
"@astrojs/tailwind": "^5.1.3",
"@astrojs/vercel": "^8.0.1",
"@iconify-json/material-symbols": "^1.2.10",
"@iconify-json/simple-icons": "^1.2.16",
"astro": "^5.0.5",
"astro-icon": "^1.1.4",
"astro-seo": "^0.8.4",
"marked": "^15.0.4",
"sanitize-html": "^2.13.1",
"tailwindcss": "^3.4.16"
},
"devDependencies": {
"@tailwindcss/typography": "^0.5.15",
"@types/sanitize-html": "^2.13.0",
"daisyui": "^4.12.22"
}
}

4
public/robots.txt Normal file
View File

@ -0,0 +1,4 @@
User-agent: *
Allow: /
Sitemap: https://solsynth.dev/sitemap-index.xml

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 696 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

@ -0,0 +1,29 @@
---
import { getAttachmentUrl } from '../scripts/attachment'
interface Props {
data: any
}
const { data: attachment } = Astro.props
---
{
attachment.mimetype.startsWith('image') ? (
<a href={getAttachmentUrl(attachment.rid)} target="_blank">
<img
src={getAttachmentUrl(attachment.rid)}
alt={attachment.alt}
class="rounded-lg"
/>
</a>
) : attachment.mimetype.startsWith('video') ? (
<video src={getAttachmentUrl(attachment.rid)} controls class="rounded-lg" />
) : attachment.mimetype.startsWith('audio') ? (
<audio src={getAttachmentUrl(attachment.rid)} controls class="rounded-lg" />
) : (
<a href={getAttachmentUrl(attachment.rid)} target="_blank">
Unable to preview, but you can open it in your broswer.
</a>
)
}

View File

@ -1,29 +1,48 @@
---
import { Image } from 'astro:assets'
import { version } from '../../package.json'
import CompanyLogo from '../assets/images/company-logo.png'
import { getRelativeLocaleUrl } from 'astro:i18n'
interface Props {
title?: string
trailingTitle?: string
}
let { title, trailingTitle } = Astro.props
if(trailingTitle == null) trailingTitle = 'Solsynth LLC'
const locale = Astro.currentLocale ?? 'en'
---
<!doctype html>
<html lang="en">
<html lang={Astro.currentLocale ?? 'en'}>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/png" href="/favicon.png" />
<title>Solsynth LLC</title>
<link rel="sitemap" href="/sitemap-index.xml" />
<title>{title ? `${title} | ${trailingTitle}` : trailingTitle}</title>
</head>
<body>
<div class="navbar backdrop-blur fixed top-0 left-0 right-0 z-10">
<div class="px-5 flex-1">
<div class="flex-1">
<a class="btn btn-ghost text-xl">Solsynth</a>
</div>
<div class="flex-none">
<a class="btn btn-ghost text-xl flex items-center gap-2" href="/">
<Image
src={CompanyLogo}
alt="company logo"
class="h-8 w-8 p-1 bg-white rounded-lg shadow-sm"
/>
<span>Solsynth</span>
</a>
</div>
<div class="flex-1 flex justify-end">
<ul class="menu menu-horizontal px-1">
<li><a>Link</a></li>
<li>
<details>
<summary>Parent</summary>
<ul class="bg-base-100 rounded-t-none p-2">
<li><a>Link 1</a></li>
<li><a>Link 2</a></li>
</ul>
</details>
</li>
<li><a href="/posts">Explore</a></li>
</ul>
</div>
</div>
@ -32,6 +51,62 @@
<main class="mt-[68px]">
<slot />
</main>
<footer class="bg-neutral text-neutral-content p-10 mt-32">
<div class="container mx-auto footer">
<aside>
<Image
src={CompanyLogo}
alt="company logo"
class="h-12 w-12 p-1 bg-white rounded-lg shadow-sm"
/>
<div class="flex flex-col">
<span class="font-bold text-lg">Solsynth LLC</span>
Building wonderful software since 2019.
<span class="font-mono text-xs mt-3">Powered by RoadSign v2</span>
<span class="font-mono text-xs">Capital v{version}</span>
<a href="https://status.solsynth.dev" class="mt-4">
<img
src="https://uptime.betterstack.com/status-badges/v1/monitor/1ki5r.svg"
/>
</a>
</div>
</aside>
<nav>
<h6 class="footer-title">Services</h6>
<a class="link link-hover" href="https://sn.solsynth.dev"> Solian </a>
<a class="link link-hover" href="https://files.solsynth.dev">
Solarfiles
</a>
<a class="link link-hover" href="https://git.solsynth.dev">
Solargit
</a>
</nav>
<nav>
<h6 class="footer-title">Legal</h6>
<a
class="link link-hover"
href={getRelativeLocaleUrl(locale, '/terms/user-agreements')}
>
User Agreements
</a>
<a
class="link link-hover"
href={getRelativeLocaleUrl(locale, '/terms/privacy-policy')}
>
Privacy Policy
</a>
<a
class="link link-hover"
href={getRelativeLocaleUrl(locale, '/terms')}
>
All Terms & Conditions
</a>
</nav>
</div>
</footer>
</body>
</html>

View File

@ -1,12 +1,12 @@
---
import { Image } from "astro:assets";
import { Icon } from "astro-icon/components";
import { Image } from 'astro:assets'
import { Icon } from 'astro-icon/components'
import Layout from "../layouts/Layout.astro";
import Layout from '@/layouts/Layout.astro'
import CompanyAsideImage from "../assets/images/company-aside.webp";
import AppStoreGetImage from "../assets/images/app-store/get-it-on-black.svg";
import ProductSnPreviewImage from "../assets/images/product-solar-network.webp";
import CompanyAsideImage from '@/assets/images/company-aside.webp'
import AppStoreGetImage from '@/assets/images/app-store/get-it-on-black.svg'
import ProductSnPreviewImage from '@/assets/images/products/solar-network.webp'
---
<Layout>
@ -33,7 +33,7 @@ import ProductSnPreviewImage from "../assets/images/product-solar-network.webp";
</div>
</div>
<div class="section-flex shadow-lg bg-base-300" id="work-featured">
<div class="section-flex py-12 shadow-lg bg-base-300" id="work-featured">
<div class="section container mx-auto grid-cols-1 lg:grid-cols-3">
<div
class="sub-section flex flex-col items-start lg:items-end justify-center lg:col-span-1"
@ -53,25 +53,34 @@ import ProductSnPreviewImage from "../assets/images/product-solar-network.webp";
Social Network, Redefined.
</blockquote>
<div class="flex gap-2 mt-4">
<a href="https://apps.apple.com/us/app/solian/id6499032345?itscg=30200&itsct=apps_box_link&mttnsubad=6499032345">
<div class="flex gap-3 mt-4 items-center text-right">
<span
class="opacity-75 text-xs max-lg:order-last"
style="line-height: 1"
>
Also supports Android, Windows, and any modern web browser
</span>
<a
href="https://apps.apple.com/us/app/solian/id6499032345?itscg=30200&itsct=apps_box_link&mttnsubad=6499032345"
>
<Image src={AppStoreGetImage} alt="get it on app store" />
</a>
</div>
<a class="link flex items-center gap-1 mt-3">
<a
class="link flex items-center gap-1 mt-3"
href="/products/solar-network"
>
<span>Learn more about Solar Network</span>
<Icon name="material-symbols:arrow-right-alt" />
</a>
</div>
<div class="sub-section flex items-center lg:col-span-2">
<div class="card">
<Image
src={ProductSnPreviewImage}
alt="solar network cross-platform preview"
class="rounded-lg shadow-xl"
/>
</div>
<Image
src={ProductSnPreviewImage}
alt="solar network cross-platform preview"
class="rounded-lg shadow-xl"
/>
</div>
</div>
</div>

View File

@ -0,0 +1,137 @@
---
export const prerender = false
import sanitizeHtml from 'sanitize-html'
import { Icon } from 'astro-icon/components'
import {SEO} from 'astro-seo'
import { marked } from 'marked'
import Layout from '@/layouts/Layout.astro'
import AttachmentRenderer from '@/components/AttachmentRenderer.astro'
import { getAttachmentUrl, fetchAttachmentMeta } from '@/scripts/attachment'
const { slug } = Astro.params
const baseUrl = import.meta.env.PUBLIC_SOLAR_NETWORK_URL
const resp = await fetch(`${baseUrl}/cgi/co/posts/${slug}`)
if (resp.status !== 200) {
return new Response(null, { status: 404 })
}
const data = await resp.json()
const rawContent = await marked(data.body.content as string, {
breaks: data.type == 'story',
})
const content = sanitizeHtml(rawContent)
const attachments = await fetchAttachmentMeta(data.body.attachments)
---
<head>
<SEO
title={data.body?.title ? data.body.title : `Post #${data.id}`}
description={data.body?.content}
openGraph={{
basic: {
title: data.body?.title ? data.body.title : `Post #${data.id}`,
type: "article",
image: data.body?.thumbnail ? getAttachmentUrl(data.body.thumbnail) : getAttachmentUrl(attachments.find(a => a.mimetype.startsWith('image'))?.rid),
url: `https://solsynth.dev/posts/${data.id}`
},
article: {
publishedTime: new Date(data.created_at).toISOString(),
modifiedTime: new Date(data.updated_at).toISOString(),
authors: ["@"+data.publisher.name],
}
}}
twitter={{
title: data.body?.title ? data.body.title : `Post #${data.id}`,
description: data.body?.content,
creator: "@"+data.publisher.name,
image: data.body?.thumbnail ? getAttachmentUrl(data.body.thumbnail) : getAttachmentUrl(attachments.find(a => a.mimetype.startsWith('image'))?.rid),
}}
/>
</head>
<Layout title={data.body?.title ? data.body.title : `Post #${data.id}`} trailingTitle='Solar Network'>
<div role="alert" class="alert shadow-lg px-12 m-0 rounded-none mb-5">
<Icon
name="material-symbols:ungroup"
class="stroke-info fill-info h-6 w-6 shrink-0"
/>
<div>
<h3 class="font-bold">Open in the Solian</h3>
<div class="text-xs">
The most modern, user-friendly, and official Solar Network app.
</div>
</div>
<div class="flex gap-2">
<a class="btn btn-sm" href="/products/solar-network#downloads">Get</a>
<a class="btn btn-sm" href={`https://sn.solsynth.dev/posts/${data.id}`}
>Open</a
>
</div>
</div>
<div class="container lg:max-w-[75ch] px-8 mx-auto">
<div class="flex gap-4 items-center mb-5">
<div class="avatar">
<div class="w-12 rounded-full">
<img src={getAttachmentUrl(data.publisher.avatar)} alt="avatar" />
</div>
</div>
<div class="userinfo flex flex-col">
<span class="flex gap-2 items-baseline">
<span class="text-md font-bold">{data.publisher.nick}</span>
<span class="text-xs font-mono">@{data.publisher.name}</span>
</span>
<span class="text-sm line-clamp-2 overflow-ellipsis"
>{data.publisher.description}</span
>
</div>
</div>
{
data.repost_id && (
<div role="alert" class="alert mb-5 py-2 mx-[-4px]">
<Icon
name="material-symbols:format-quote"
class="stroke-info fill-info h-6 w-6 shrink-0"
/>
<span>
This post is reposting post{' '}
<span class="font-mono">#{data.repost_id}</span>
</span>
<div>
<a class="btn btn-sm" href={`/posts/${data.repost_id}`}>
See reposted post
</a>
</div>
</div>
)
}
<article>
<div class="prose max-w-none max-md:prose-lg" set:html={content} />
{
attachments && (
<div
class="attachment-list mt-5 gap-4 grid grid-cols-1"
class:list={
attachments.length >= 2 ? 'md:grid-cols-2' : 'md:grid-cols-1'
}
>
{attachments.map((attachment) => (
<div class="attachment">
<AttachmentRenderer data={attachment} />
</div>
))}
</div>
)
}
</article>
</div>
</Layout>

149
src/pages/posts/index.astro Normal file
View File

@ -0,0 +1,149 @@
---
export const prerender = false
import sanitizeHtml from 'sanitize-html'
import { Icon } from 'astro-icon/components'
import { marked } from 'marked'
import Layout from '@/layouts/Layout.astro'
import AttachmentRenderer from '@/components/AttachmentRenderer.astro'
import { getAttachmentUrl, fetchAttachmentMeta } from '@/scripts/attachment'
const page = parseInt(Astro.url.searchParams.get('page') ?? '1') || 1
async function getPosts() {
const baseUrl = import.meta.env.PUBLIC_SOLAR_NETWORK_URL
const res = await fetch(
`${baseUrl}/cgi/co/posts?take=10&offset=${Math.max(page - 1, 0) * 10}`
)
const data = await res.json()
const posts = await Promise.all(
data['data'].map(async (ele: any) => {
if (ele.body?.content) {
ele.body.content = await parseContent(
ele.body.content,
ele.type == 'story'
)
}
if (ele.body?.attachments) {
ele.body.attachments = await fetchAttachmentMeta(ele.body.attachments)
}
return ele
})
)
return posts
}
const posts = await getPosts()
async function parseContent(data: string, useBreaks: boolean = false) {
const rawContent = await marked(data, {
breaks: useBreaks,
})
return sanitizeHtml(rawContent)
}
---
<Layout title="Posts" trailingTitle='Solar Network'>
<div role="alert" class="alert shadow-lg px-12 m-0 rounded-none mb-5">
<Icon
name="material-symbols:ungroup"
class="stroke-info fill-info h-6 w-6 shrink-0"
/>
<div>
<h3 class="font-bold">Open in the Solian</h3>
<div class="text-xs">
The most modern, user-friendly, and official Solar Network app.
</div>
</div>
<div class="flex gap-2">
<a class="btn btn-sm" href="/products/solar-network#downloads">Get</a>
<a class="btn btn-sm" href="https://sn.solsynth.dev/posts">Open</a>
</div>
</div>
<div
class="container max-w-[85ch] mx-auto mt-[15vh] px-12 flex flex-col gap-4"
>
<h1 class="text-2xl font-bold">Posts</h1>
<p>Explore the posts all over the Solar Network.</p>
<div class="flex flex-col gap-4 mt-4 mx-[-16px]">
{
posts.map((ele: any) => (
<a href={`/posts/${ele.id}`}>
<div class="card bg-base-100 w-full border-neutral border">
<div class="card-body">
<div class="flex gap-4 items-center mb-5">
<div class="avatar">
<div class="w-12 rounded-full">
<img
src={getAttachmentUrl(ele.publisher.avatar)}
alt="avatar"
/>
</div>
</div>
<div class="userinfo flex flex-col">
<span class="flex gap-2 items-baseline">
<span class="text-md font-bold">
{ele.publisher.nick}
</span>
<span class="text-xs font-mono">
@{ele.publisher.name}
</span>
</span>
<span class="text-sm overflow-ellipsis">
{new Date(ele.created_at).toLocaleString()}
</span>
</div>
</div>
{ele.body.title && (
<h2 class="card-title">
{ele.body?.title ?? `Post #${ele.id}`}
</h2>
)}
<article>
<div
class="prose max-w-none max-md:prose-lg"
set:html={ele.body?.content ?? ''}
/>
{ele.body?.attachments && (
<div
class="attachment-list mt-5 gap-4 grid grid-cols-1"
class:list={
ele.body.attachments.length >= 2
? 'md:grid-cols-2'
: 'md:grid-cols-1'
}
>
{ele.body.attachments.map((attachment: any) => (
<div class="attachment">
<AttachmentRenderer data={attachment} />
</div>
))}
</div>
)}
</article>
</div>
</div>
</a>
))
}
<div class="flex justify-center items-center mt-12">
<div class="join">
<a
class="join-item btn"
class:list={page == 1 ? 'btn-disabled' : ''}
href={`/posts?page=${page - 1}`}>«</a
>
<button class="join-item btn">Page {page}</button>
<a class="join-item btn" href={`/posts?page=${page + 1}`}>»</a>
</div>
</div>
</div>
</div>
</Layout>

View File

@ -0,0 +1,176 @@
---
import { Image } from 'astro:assets'
import { Icon } from 'astro-icon/components'
import Layout from '@/layouts/Layout.astro'
import ProductSnPreviewImage from '../../assets/images/products/solar-network-alpha.webp'
---
<Layout title="Solar Network">
<div class="container mx-auto mt-[35vh]" id="intro">
<div class="text-center">
<h1 class="text-4xl font-bold">Solar Network</h1>
<p>The next generation Social Network platform.</p>
<div class="flex justify-center gap-2 mt-5">
<a class="btn btn-primary" href="#downloads">
Download <Icon name="material-symbols:download" size={20} />
</a>
</div>
</div>
<Image
src={ProductSnPreviewImage}
alt="solar network cross-platform preview"
class="mt-5"
/>
<div id="downloads" class="mt-24 text-center">
<div class="flex flex-col justify-center">
<h2 class="text-2xl font-bold">Downloads</h2>
</div>
<div class="flex flex-wrap mx-8 items-center justify-center gap-4 my-5">
<a
href="https://apps.apple.com/us/app/solian/id6499032345?itscg=30200&itsct=apps_box_link&mttnsubad=6499032345"
class="btn btn-secondary max-md:btn-wide"
>
<Icon name="simple-icons:appstore" />
iOS / macOS (App Store)
</a>
<a
href="https://testflight.apple.com/join/YJ0lmN6O"
class="btn btn-secondary btn-outline max-md:btn-wide"
>
<Icon name="simple-icons:apple" />
iOS / macOS (TestFlight)
</a>
<a
href="https://files.solsynth.dev/production01/solian/app-arm64-v8a-release.apk"
class="btn btn-secondary max-md:btn-wide"
>
<Icon name="simple-icons:android" />
Android (apk file)
</a>
<a
href="https://files.solsynth.dev/production01/solian/windows-x86_64-release.zip"
class="btn btn-secondary max-md:btn-wide"
>
<Icon name="simple-icons:windows" />
Windows (executable)
</a>
<a
href="https://sn.solsynth.dev"
class="btn btn-secondary btn-outline max-md:btn-wide"
>
<Icon name="material-symbols:globe" />
Web (browser)
</a>
</div>
<div class="mx-8">
<p class="opacity-80 mb-2">
You will download Solian, which is the official app made for Solar
Network.
</p>
<p class="opacity-75 text-sm">
Explore more platform distribution files on the{' '}
<a class="link" href="https://files.solsynth.dev/production01/solian"
>Solarfiles</a
>
</p>
<p class="opacity-75 text-sm">
Check out the Solian source code on{' '}
<a class="link" href="https://git.solsynth.dev/HyperNet/Surface"
>Solargit</a
>
</p>
</div>
</div>
<div id="faq" class="mt-24">
<div class="flex text-center justify-center">
<h2 class="text-2xl font-bold">Frequently Asked Questions</h2>
</div>
<div
class="max-w-[85ch] mx-auto bg-neutral text-neutral-content shadow-lg rounded-lg p-2 mt-5"
>
<div class="join join-vertical w-full">
<div class="collapse collapse-arrow join-item">
<input type="radio" name="my-accordion-4" checked="checked" />
<div class="collapse-title text-xl font-medium">
What's the relationship between Solar Network and Solian?
</div>
<div class="collapse-content">
<p>
Solian is the official app made for Solar Network. And the Solar
Network is the official HyperNet instance hosted by Solsynth
LLC.
</p>
<p>
For simple, Solian is the app, and the Solar Network is the
platform.
</p>
</div>
</div>
<div class="collapse collapse-arrow join-item">
<input type="radio" name="my-accordion-4" checked="checked" />
<div class="collapse-title text-xl font-medium">
What's the relationship between Solar Network and HyperNet?
</div>
<div class="collapse-content">
<p>
HyperNet is the entire project including frontend app (also
knowns as Solian for public) and the backend server. And the
Solar Network is the official HyperNet instance which hosted and
managed by Solsynth LLC who developed the HyperNet Project.
</p>
</div>
</div>
<div class="collapse collapse-arrow join-item">
<input type="radio" name="my-accordion-4" />
<div class="collapse-title text-xl font-medium">
Which rules do I need to follow while using Solar Network?
</div>
<div class="collapse-content">
<p>
Check out our{' '}
<a href="/terms/user-agreements" class="link">
User Agreements
</a>
for a detailed explanation of what you can do and cannot do on Solar
Network. If you violate any of these rules, we have the right to
suspend or terminate your account.
</p>
</div>
</div>
<div class="collapse collapse-arrow join-item">
<input type="radio" name="my-accordion-4" />
<div class="collapse-title text-xl font-medium">
If I have any question about Solar Network, where can I get help?
</div>
<div class="collapse-content">
<p>
Feel free to email us at{' '}
<a href="mailto:lily@solsynth.dev" class="link">
<address>lily@solsynth.dev</address>
</a>
Our customer service team will try our best to help you solve your
issue.
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</Layout>
<style>
html,
body {
scroll-behavior: smooth;
}
</style>

View File

@ -0,0 +1,52 @@
---
import Layout from '@/layouts/Layout.astro'
---
<Layout title="Terms & Conditions">
<div
class="container max-w-[85ch] mx-auto mt-[25vh] px-12 flex flex-col gap-4"
>
<h1 class="text-2xl font-bold">Terms & Conditions</h1>
<p>
This place is the collections of all the terms and conditions that you
will have to agree to in order to use our products.
</p>
<p>
We're trying to make it as simple as possible. And it's good for both of
us. You do not need care about this in normal. Just makes our lawyers
happy. <i>Do we really have a lawyer?</i>
</p>
<p>
The information here may changed from time to time. Please refresh to
check this page for the latest version.
</p>
<div class="flex flex-col gap-4 mt-4 mx-[-16px]">
<a href="/terms/user-agreements">
<div class="card bg-base-100 w-full border-neutral border">
<div class="card-body">
<h2 class="card-title">User Agreements</h2>
<p>
The User Agreements for users who using the Solar Network and
other products from us.
</p>
</div>
</div>
</a>
<a href="/terms/privacy-policy">
<div class="card bg-base-100 w-full border-neutral border">
<div class="card-body">
<h2 class="card-title">Privacy Policy</h2>
<p>
The Privacy Policy shows we how to process and handle the data
provided by you.
</p>
</div>
</div>
</a>
</div>
</div>
</Layout>

View File

@ -0,0 +1,61 @@
---
import Layout from '@/layouts/Layout.astro'
---
<Layout title="User Agreements">
<div
class="container max-w-[85ch] mx-auto mt-[25vh] px-12 flex flex-col gap-4"
>
<h1 class="text-4xl font-bold">Privacy Policy</h1>
<article class="prose prose-lg max-w-none mt-5">
<h2 id="introduction">Introduction</h2>
<p>
We take your privacy seriously. This privacy policy outlines the types
of personal information we collect, how we use it, and the measures we
take to protect your data.
</p>
<h2 id="information-collection">Information Collection</h2>
<p>
We collect personal information only when necessary to provide our
services. This may include your name, email address, and other relevant
details.
</p>
<h2 id="use-of-information">Use of Information</h2>
<p>We use your personal information to:</p>
<ul>
<li>Provide and improve our services</li>
<li>Communicate with you about updates or important information</li>
<li>Ensure compliance with legal obligations</li>
</ul>
<h2 id="data-sharing">Data Sharing</h2>
<p>
We do not sell, trade, or share your personal information with third
parties except as required by law.
</p>
<h2 id="data-security">Data Security</h2>
<p>
We implement robust security measures to protect your personal
information from unauthorized access, alteration, disclosure, or
destruction.
</p>
<h2 id="your-rights">Your Rights</h2>
<p>You have the right to:</p>
<ul>
<li>Access the personal information we hold about you</li>
<li>Request corrections to your personal information</li>
<li>Request the deletion of your personal information</li>
</ul>
<h2 id="contact-us">Contact Us</h2>
<p>
If you have any questions or concerns about this privacy policy or our
data practices, please contact us at lily@solsynth.dev.
</p>
<h2 id="changes-to-this-policy">Changes to This Policy</h2>
<p>
We may update this privacy policy from time to time. Any changes will be
posted on this page, and we will notify you of any significant changes.
</p>
</article>
</div>
</Layout>

View File

@ -0,0 +1,157 @@
---
import Layout from '@/layouts/Layout.astro'
---
<Layout title="User Agreements">
<div
class="container max-w-[85ch] mx-auto mt-[25vh] px-12 flex flex-col gap-4"
>
<h1 class="text-4xl font-bold">User Agreements</h1>
<article class="prose prose-lg max-w-none mt-5">
<p>
This Agreement applies to all Solsynth LLC products, including but not
limited to Solar Network, Solian, DietaryGuard, AceField.
</p>
<h2 id="provision-and-discontinuance-of-service">
Provision and Discontinuance of Service
</h2>
<p>
Solsynth LLC will provide equal service to all living things in the
world, including grasshoppers. We also reserve the right to stop service
to any user. We do not require prior notice for discontinuing services
to some users.
</p>
<h2 id="user-generated-content">User Generated Content</h2>
<p>
Any content posted on Solar Network (including but not limited to posts,
articles, attachments) grants Solsynth LLC the right to display it by
default. Unless otherwise stated by the user, all rights are reserved by
the original poster, and reprints should be authorized by the original
poster.
</p>
<h3 id="reproduction-recognition">Reproduction Recognition</h3>
<p>
Unless specifically stated by the poster, all content is subject to the
definition of reprint in this section.
</p>
<p>
Republishing means uploading the content of the original post to another
platform or to the Solar Network, either unchanged or with minor
modifications, provided that simultaneous reposting of the post,
embedded components, and links to the presentation do not constitute
republishing. Republishing also requires attribution when authorized by
the original poster.
</p>
<h3 id="freedom-of-speech">Freedom of Speech</h3>
<p>
We do not remove user-generated content except in cases of misuse of
resources. We will not ask any user to remove any content.
</p>
<p>
However, Solsynth LLC reserves the right to restrict and stop the
display of content to the public that violates community guidelines
(e.g., obscenity, violence, gore, anti-social, terrorist organizations,
etc.).
</p>
<p>
Although you have 100% freedom of speech on Solar Network. However,
please be aware that freedom of speech does not mean that you will not
be held accountable for what you say.
</p>
<h4 id="restriction-and-discontinuation">
Restriction and Discontinuation
</h4>
<ul>
<li>
<p>
Restriction of Display: Discontinuation of related tweets, while
retaining the right to access them directly through resource
identifiers and sharing links.
</p>
</li>
<li>
<p>
Cease display: stop all access to the resource by anyone other than
the author.
</p>
</li>
</ul>
<h2 id="resource-misuse-prevention-policy">
Resource Misuse Prevention Policy
</h2>
<p>
Although there are no capacity limitations for using Solar Network&#39;s
data hosting services, resources determined to be abusive will be
disenfranchised from some features. Solsynth LLC reserves the right to
reclaim space on previously uploaded resources for deletion.
</p>
<h3 id="determination-of-misuse">Determination of Misuse</h3>
<ul>
<li>
Uploading without using: e.g. uploading excessive attachments in Solar
Network&#39;s Interactive Attachment Pool and not linking them to
posts.
</li>
<li>
Meaningless Posts: meaningless shuffling or wasting of Solar
Network&#39;s storage resources
</li>
<li>
Misuse: using Solar Network&#39;s public resources as if they were
your own dedicated pool (see the Wiki&#39;s Dedicated Pools page for
details).
</li>
</ul>
<p>
The Solsynth Trust &amp; Safety Team is ultimately responsible for
determining misuse.
</p>
<h2 id="secondary-releases">Secondary Releases</h2>
<p>
A secondary release is when our assets are downloaded and re-hosted on
another site.
</p>
<h3 id="product-secondary-release">Product Secondary Release</h3>
<p>
Unless otherwise stated, Solsynth LLC products are not available for
secondary distribution, please do not download our product builds and
upload them twice to another site. Please do not download our product
builds and upload them to other sites. <strong
>Secondary distribution for commercial use is not permitted.
</strong>.
</p>
<p>
What you should do is post a link to our product on another site. Or use
the embedded component. And indicate Solsynth LLC All Rights Reserved.
</p>
<p>
If you want to build a mirror site of our products, please contact us to
waive this rule.
</p>
<h3 id="secondary-distribution-of-source-code">
Secondary distribution of source code
</h3>
<p>
We do not allow any form of redistribution of source code (except for
Forks). This includes, but is not limited to, mirroring code
repositories on GitHub or the Solsynth Code Repository to other Git
providers such as GitLab, Gitee, and so on.
<strong>Selling source code twice is not allowed. </strong>
</p>
<p>
For more information on source code usage regulations, please follow the
open source license used by the project.
</p>
<p>
If you would like to set up a mirror of our source code, please contact
us to waive this policy.
</p>
<hr />
<p>
Solsynth LLC reserves the right of final interpretation of this
agreement.
</p>
</article>
</div>
</Layout>

View File

@ -0,0 +1,39 @@
---
import Layout from '@/layouts/Layout.astro'
---
<Layout title="Terms & Conditions">
<div
class="container max-w-[85ch] mx-auto mt-[25vh] px-2 flex flex-col gap-4"
>
<h1 class="text-2xl font-bold">条款和条件</h1>
<p>这里罗列了您使用我们的产品将需要同意的所有条款和条件。</p>
<p>
我们正努力让事情尽可能简单。这对我们双方都有好处。通常情况下你不需要关心这件事。只是为了让我们的律师高兴。
<i>我们真的有律师吗?</i>
</p>
<p>此处的信息可能会不时更改。请刷新 查看此页面以获取最新版本。</p>
<div class="flex flex-col gap-4 mt-4 mx-[-16px]">
<a href="/terms/user-agreements">
<div class="card bg-base-100 w-full border-neutral border">
<div class="card-body">
<h2 class="card-title">用户协议</h2>
<p>使用 Solar Network 和 我们其他产品的用户须遵守的用户协议。</p>
</div>
</div>
</a>
<a href="/terms/privacy-policy">
<div class="card bg-base-100 w-full border-neutral border">
<div class="card-body">
<h2 class="card-title">隐私政策</h2>
<p>隐私政策向我们展示了如何处理和处理您提供的数据。</p>
</div>
</div>
</a>
</div>
</div>
</Layout>

View File

@ -0,0 +1,51 @@
---
import Layout from '@/layouts/Layout.astro'
---
<Layout title="User Agreements">
<div
class="container max-w-[85ch] mx-auto mt-[25vh] px-12 flex flex-col gap-4"
>
<h1 class="text-4xl font-bold">隐私政策</h1>
<article class="prose prose-lg max-w-none mt-5">
<h2 id="introduction">简介</h2>
<p>
我们非常重视您的隐私。本隐私政策概述了我们收集的个人信息类型、使用方式以及我们采取的保护措施。
</p>
<h2 id="information-collection">信息收集</h2>
<p>
我们仅在提供服务时收集必要的个人信息。这可能包括您的姓名、电子邮件地址以及其他相关信息。
</p>
<h2 id="use-of-information">信息使用</h2>
<p>我们使用您的个人信息来:</p>
<ul>
<li>提供和改进我们的服务</li>
<li>与您沟通更新或重要信息</li>
<li>确保遵守法律义务</li>
</ul>
<h2 id="data-sharing">数据共享</h2>
<p>我们不会出售、交易或与第三方分享您的个人信息,法律要求除外。</p>
<h2 id="data-security">数据安全</h2>
<p>
我们实施了强有力的安全措施,以保护您的个人信息免受未经授权的访问、更改、披露或销毁。
</p>
<h2 id="your-rights">您的权利</h2>
<p>您有权:</p>
<ul>
<li>访问我们持有的关于您的个人信息</li>
<li>请求更正您的个人信息</li>
<li>请求删除您的个人信息</li>
</ul>
<h2 id="contact-us">联系我们</h2>
<p>
如果您对本隐私政策或我们的数据处理方式有任何疑问或顾虑,请通过
lily@solsynth.dev 与我们联系。
</p>
<h2 id="changes-to-this-policy">政策变更</h2>
<p>
我们可能会不时更新本隐私政策。任何更改将发布在此页面上,且我们会通知您任何重大更改。
</p>
</article>
</div>
</Layout>

View File

@ -0,0 +1,101 @@
---
import Layout from '@/layouts/Layout.astro'
---
<Layout title="User Agreements">
<div
class="container max-w-[85ch] mx-auto mt-[25vh] px-12 flex flex-col gap-4"
>
<h1 class="text-4xl font-bold">用户协议</h1>
<article class="prose prose-lg max-w-none mt-5">
<p>
本协议适用于所有 Solsynth LLC 的产品,包括但不限于 Solar
Network、Solian、DietaryGuard、AceField。
</p>
<h2 id="provision-and-discontinuance-of-service">服务的提供和停止</h2>
<p>
Solsynth LLC 将向世界上所有的生物提供同等的服务,包括草履虫。
同时也保留向任意用户停止提供服务的权利。关于停止部分用户的服务,我们不需要提前通知。
</p>
<h2 id="user-generated-content">用户生成内容</h2>
<p>
任意发布在 Solar Network
上的内容(包括但不限于帖子、文章、附件)都默认授权 Solsynth LLC
予以展示的权利。
除非用户特别声明,所有内容均为原帖主保留所有权利,转载请先向原帖主授权。
</p>
<h3 id="reproduction-recognition">转载的认定</h3>
<p>无帖主特别声明,所有内容均适用本条转载的定义。</p>
<p>
转载指将原帖的内容原封不动或略作改动上传到别的平台或 Solar
Network。但同时转帖、嵌入式组件与展示展开的链接不构成转载。
转载即时在原帖主授权的情况下也需表明出处。
</p>
<h3 id="freedom-of-speech">言论的自由</h3>
<p>
除滥用资源的情况,我们不会将用户生成内容进行删除。也不会做出要求任何用户删除任何内容的要求。
</p>
<p>
但 Solsynth LLC
始终保留对于违反社区准则的内容(如淫秽、暴力、血腥、反社会、恐怖组织等)限制与停止向公众展示的权利。
</p>
<p>
尽管在 Solar Network 上你拥有 100%
的言论自由。但还请清楚,言论自由不代表不用对自己的言论负责。
</p>
<h4 id="restriction-and-discontinuation">限制展示与停止展示</h4>
<ul>
<li>
<p>
限制展示:停止相关的推送,但是任保留直接通过资源标识符和分享连接访问的权利
</p>
</li>
<li><p>停止展示:全面停止除作者之外任何人访问该资源的权利</p></li>
</ul>
<h2 id="resource-misuse-prevention-policy">防止资源滥用条例</h2>
<p>
尽管使用 Solar Network
的数据托管服务并无任何的容量限制,但经过判定的滥用资源将会被取消使用部分功能的权利。
并且之前上传的资源 Solsynth LLC 有权对其进行删除空间回收。
</p>
<h3 id="determination-of-misuse">滥用的认定</h3>
<ul>
<li>
传而不用:例如在 Solar Network 的 Interactive
附件池中过度上传附件并不将附件与帖子连接
</li>
<li>无意义帖:无意义洗版或浪费 Solar Network 的存储资源</li>
<li>
走错片场:将 Solar Network
公有资源当作自己的专用资源池使用(详见维基《专用资源池》页面)
</li>
</ul>
<p>滥用的认定最终解释权归属于 Solsynth Trust &amp; Safety Team</p>
<h2 id="secondary-releases">二次发布</h2>
<p>二次发布指将我们的资产下载并重新托管到别站。</p>
<h3 id="product-secondary-release">制品二次发布</h3>
<p>
除特殊声明Solsynth LLC
的产品均不允许二次发布,请勿将我们的产品构建下载并二次上传于其他站点。
<strong>二次作为商用发布更是不允许的。</strong>
</p>
<p>
你应该做的是将我们的产品链接贴上他站。或使用嵌入式组件。并且表明
Solsynth LLC 版权所有。
</p>
<p>若您想搭建我们制品的镜像站,请与我们取得联系以豁免此条例。</p>
<h3 id="secondary-distribution-of-source-code">源码二次发布</h3>
<p>我们不允许任何形式的源码二次发布Fork 除外)。</p>
<p>
包括但不限于,将 GitHub 或 Solsynth Code Repository 上的代码仓库镜像于
GitLab、Gitee 等其他 Git 提供者。
<strong>二次售卖源码更是不允许的。</strong>
</p>
<p>关于更多的源码使用条例,请遵循项目使用的开源许可证。</p>
<p>若您想搭建我们源码的镜像站,请与我们取得联系以豁免此条例。</p>
<hr />
<p>Solsynth LLC 保留对此协议的最终解释权</p>
</article>
</div>
</Layout>

26
src/scripts/attachment.ts Normal file
View File

@ -0,0 +1,26 @@
export function getAttachmentUrl(identifier?: string): string {
if (!identifier) return ''
if (identifier.startsWith('http')) {
return identifier
}
const baseUrl = import.meta.env.PUBLIC_SOLAR_NETWORK_URL
return `${baseUrl}/cgi/uc/attachments/${identifier}`
}
export async function fetchAttachmentMeta(
identifiers: string[]
): Promise<any[]> {
if (!identifiers) return []
const baseUrl = import.meta.env.PUBLIC_SOLAR_NETWORK_URL
const resp = await fetch(
`${baseUrl}/cgi/uc/attachments?take=${
identifiers.length
}&id=${identifiers.join(',')}`
)
if (resp.status !== 200) {
throw new Error(`Failed to fetch attachment meta: ${await resp.text()}`)
}
const out = await resp.json()
return out['data']
}

View File

@ -1,38 +1,38 @@
/** @type {import('tailwindcss').Config} */
export default {
content: ["./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}"],
content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
theme: {
extend: {},
},
plugins: [require("@tailwindcss/typography"), require("daisyui")],
plugins: [require('@tailwindcss/typography'), require('daisyui')],
daisyui: {
themes: [
{
dark: {
primary: "#3f51b5",
secondary: "#4ba6ee",
accent: "#03a9f4",
neutral: "#1f2937",
"base-100": "#000011",
info: "#4994ec",
success: "#67ad5b",
warning: "#f5c344",
error: "#e15241",
light: {
primary: '#3f51b5',
secondary: '#4ba6ee',
accent: '#03a9f4',
neutral: '#4b5563',
'base-100': '#ffffff',
info: '#4994ec',
success: '#67ad5b',
warning: '#f5c344',
error: '#e15241',
},
},
{
light: {
primary: "#3f51b5",
secondary: "#4ba6ee",
accent: "#03a9f4",
neutral: "#4b5563",
"base-100": "#ffffff",
info: "#4994ec",
success: "#67ad5b",
warning: "#f5c344",
error: "#e15241",
dark: {
primary: '#3f51b5',
secondary: '#4ba6ee',
accent: '#03a9f4',
neutral: '#1f2937',
'base-100': '#000011',
info: '#4994ec',
success: '#67ad5b',
warning: '#f5c344',
error: '#e15241',
},
},
],
},
};
}

View File

@ -1,5 +1,17 @@
{
"extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"]
"include": [
".astro/types.d.ts",
"**/*",
"src/**/*.d.ts",
"src/**/*.ts",
"src/**/*.astro"
],
"exclude": ["dist"],
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
}
}