feat: 主页内容测试
This commit is contained in:
parent
34713cc9fb
commit
9ae820a796
@ -1,6 +1,7 @@
|
||||
{
|
||||
"plugins": [
|
||||
"prettier-plugin-astro"
|
||||
"prettier-plugin-astro",
|
||||
"prettier-plugin-tailwindcss"
|
||||
],
|
||||
"overrides": [
|
||||
{
|
||||
|
||||
@ -11,5 +11,5 @@ export default defineConfig({
|
||||
plugins: [tailwindcss()]
|
||||
},
|
||||
|
||||
integrations: [svelte()]
|
||||
integrations: [svelte()],
|
||||
});
|
||||
@ -14,6 +14,7 @@
|
||||
"@skeletonlabs/skeleton-svelte": "^1.2.1",
|
||||
"@tailwindcss/vite": "^4.1.4",
|
||||
"astro": "^5.7.5",
|
||||
"lucide-svelte": "^0.503.0",
|
||||
"svelte": "^5.28.2",
|
||||
"tailwindcss": "^4.1.4",
|
||||
"typescript": "^5.8.3"
|
||||
@ -24,6 +25,7 @@
|
||||
"eslint": "^9.25.1",
|
||||
"eslint-plugin-astro": "^1.3.1",
|
||||
"prettier": "3.5.3",
|
||||
"prettier-plugin-astro": "0.14.1"
|
||||
"prettier-plugin-astro": "0.14.1",
|
||||
"prettier-plugin-tailwindcss": "^0.6.11"
|
||||
}
|
||||
}
|
||||
76
pnpm-lock.yaml
generated
76
pnpm-lock.yaml
generated
@ -23,6 +23,9 @@ importers:
|
||||
astro:
|
||||
specifier: ^5.7.5
|
||||
version: 5.7.5(jiti@2.4.2)(lightningcss@1.29.2)(rollup@4.40.0)(typescript@5.8.3)(yaml@2.7.1)
|
||||
lucide-svelte:
|
||||
specifier: ^0.503.0
|
||||
version: 0.503.0(svelte@5.28.2)
|
||||
svelte:
|
||||
specifier: ^5.28.2
|
||||
version: 5.28.2
|
||||
@ -51,6 +54,9 @@ importers:
|
||||
prettier-plugin-astro:
|
||||
specifier: 0.14.1
|
||||
version: 0.14.1
|
||||
prettier-plugin-tailwindcss:
|
||||
specifier: ^0.6.11
|
||||
version: 0.6.11(prettier-plugin-astro@0.14.1)(prettier@3.5.3)
|
||||
|
||||
packages:
|
||||
|
||||
@ -1554,6 +1560,11 @@ packages:
|
||||
lru-cache@10.4.3:
|
||||
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
|
||||
|
||||
lucide-svelte@0.503.0:
|
||||
resolution: {integrity: sha512-oT1idMbgJKCCLWI4U7bdUYUZqxS78fiTGJuKGZ5u0NJNyuiUErDu3G7sXkYpfDwwspeid7gZSjrlJbTINEfErw==}
|
||||
peerDependencies:
|
||||
svelte: ^3 || ^4 || ^5.0.0-next.42
|
||||
|
||||
magic-string@0.30.17:
|
||||
resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
|
||||
|
||||
@ -1841,6 +1852,61 @@ packages:
|
||||
resolution: {integrity: sha512-RiBETaaP9veVstE4vUwSIcdATj6dKmXljouXc/DDNwBSPTp8FRkLGDSGFClKsAFeeg+13SB0Z1JZvbD76bigJw==}
|
||||
engines: {node: ^14.15.0 || >=16.0.0}
|
||||
|
||||
prettier-plugin-tailwindcss@0.6.11:
|
||||
resolution: {integrity: sha512-YxaYSIvZPAqhrrEpRtonnrXdghZg1irNg4qrjboCXrpybLWVs55cW2N3juhspVJiO0JBvYJT8SYsJpc8OQSnsA==}
|
||||
engines: {node: '>=14.21.3'}
|
||||
peerDependencies:
|
||||
'@ianvs/prettier-plugin-sort-imports': '*'
|
||||
'@prettier/plugin-pug': '*'
|
||||
'@shopify/prettier-plugin-liquid': '*'
|
||||
'@trivago/prettier-plugin-sort-imports': '*'
|
||||
'@zackad/prettier-plugin-twig': '*'
|
||||
prettier: ^3.0
|
||||
prettier-plugin-astro: '*'
|
||||
prettier-plugin-css-order: '*'
|
||||
prettier-plugin-import-sort: '*'
|
||||
prettier-plugin-jsdoc: '*'
|
||||
prettier-plugin-marko: '*'
|
||||
prettier-plugin-multiline-arrays: '*'
|
||||
prettier-plugin-organize-attributes: '*'
|
||||
prettier-plugin-organize-imports: '*'
|
||||
prettier-plugin-sort-imports: '*'
|
||||
prettier-plugin-style-order: '*'
|
||||
prettier-plugin-svelte: '*'
|
||||
peerDependenciesMeta:
|
||||
'@ianvs/prettier-plugin-sort-imports':
|
||||
optional: true
|
||||
'@prettier/plugin-pug':
|
||||
optional: true
|
||||
'@shopify/prettier-plugin-liquid':
|
||||
optional: true
|
||||
'@trivago/prettier-plugin-sort-imports':
|
||||
optional: true
|
||||
'@zackad/prettier-plugin-twig':
|
||||
optional: true
|
||||
prettier-plugin-astro:
|
||||
optional: true
|
||||
prettier-plugin-css-order:
|
||||
optional: true
|
||||
prettier-plugin-import-sort:
|
||||
optional: true
|
||||
prettier-plugin-jsdoc:
|
||||
optional: true
|
||||
prettier-plugin-marko:
|
||||
optional: true
|
||||
prettier-plugin-multiline-arrays:
|
||||
optional: true
|
||||
prettier-plugin-organize-attributes:
|
||||
optional: true
|
||||
prettier-plugin-organize-imports:
|
||||
optional: true
|
||||
prettier-plugin-sort-imports:
|
||||
optional: true
|
||||
prettier-plugin-style-order:
|
||||
optional: true
|
||||
prettier-plugin-svelte:
|
||||
optional: true
|
||||
|
||||
prettier@3.5.3:
|
||||
resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==}
|
||||
engines: {node: '>=14'}
|
||||
@ -4025,6 +4091,10 @@ snapshots:
|
||||
|
||||
lru-cache@10.4.3: {}
|
||||
|
||||
lucide-svelte@0.503.0(svelte@5.28.2):
|
||||
dependencies:
|
||||
svelte: 5.28.2
|
||||
|
||||
magic-string@0.30.17:
|
||||
dependencies:
|
||||
'@jridgewell/sourcemap-codec': 1.5.0
|
||||
@ -4495,6 +4565,12 @@ snapshots:
|
||||
prettier: 3.5.3
|
||||
sass-formatter: 0.7.9
|
||||
|
||||
prettier-plugin-tailwindcss@0.6.11(prettier-plugin-astro@0.14.1)(prettier@3.5.3):
|
||||
dependencies:
|
||||
prettier: 3.5.3
|
||||
optionalDependencies:
|
||||
prettier-plugin-astro: 0.14.1
|
||||
|
||||
prettier@3.5.3: {}
|
||||
|
||||
prismjs@1.30.0: {}
|
||||
|
||||
BIN
public/grotesk.woff2
Normal file
BIN
public/grotesk.woff2
Normal file
Binary file not shown.
4
src/components/Footer.svelte
Normal file
4
src/components/Footer.svelte
Normal file
@ -0,0 +1,4 @@
|
||||
<footer class="p-4 text-center text-sm text-surface-500">
|
||||
© {new Date().getFullYear()} 我的镜像站. All rights reserved. |
|
||||
<a href="/about#disclaimer" class="anchor">免责声明</a>
|
||||
</footer>
|
||||
180
src/components/Header.svelte
Normal file
180
src/components/Header.svelte
Normal file
@ -0,0 +1,180 @@
|
||||
<script>
|
||||
import { onMount } from "svelte";
|
||||
import { Toaster, createToaster } from "@skeletonlabs/skeleton-svelte";
|
||||
|
||||
// 导入Lucide图标
|
||||
import { Search, Moon, Sun, Menu, X } from "lucide-svelte";
|
||||
|
||||
// 状态管理
|
||||
let darkMode = false;
|
||||
let mobileMenuOpen = false;
|
||||
let searchQuery = "";
|
||||
|
||||
// Toast通知
|
||||
const toaster = createToaster();
|
||||
|
||||
// 切换主题
|
||||
function toggleTheme() {
|
||||
darkMode = !darkMode;
|
||||
document.documentElement.classList.toggle("dark", darkMode);
|
||||
|
||||
// // 保存用户偏好
|
||||
// if (typeof localStorage !== "undefined") {
|
||||
// localStorage.setItem("theme", darkMode ? "dark" : "light");
|
||||
// }
|
||||
|
||||
// 显示主题切换通知
|
||||
toaster.info({
|
||||
type: "info",
|
||||
title: "主题切换",
|
||||
description: `已切换到${darkMode ? "暗色" : "亮色"}主题`,
|
||||
background: "variant-filled-primary",
|
||||
timeout: 2000
|
||||
});
|
||||
}
|
||||
|
||||
// 处理搜索
|
||||
function handleSearch(e) {
|
||||
if (e.key === "Enter" || e.type === "click") {
|
||||
if (searchQuery.trim()) {
|
||||
toaster.trigger({
|
||||
message: `正在搜索: ${searchQuery}`,
|
||||
background: "variant-filled-secondary",
|
||||
timeout: 2000
|
||||
});
|
||||
// 这里可以添加实际的搜索逻辑
|
||||
searchQuery = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// // 在组件挂载时检查用户的主题偏好
|
||||
// onMount(() => {
|
||||
// if (typeof localStorage !== "undefined" && localStorage.getItem("theme") === "dark") {
|
||||
// darkMode = true;
|
||||
// document.documentElement.classList.add("dark");
|
||||
// } else if (typeof window !== "undefined" && window.matchMedia("(prefers-color-scheme: dark)").matches) {
|
||||
// darkMode = true;
|
||||
// document.documentElement.classList.add("dark");
|
||||
// }
|
||||
// });
|
||||
</script>
|
||||
|
||||
<header
|
||||
class="sticky top-0 z-50 w-full transition-all duration-300 bg-background/80 backdrop-blur-2xl border-b border-surface-300-600-token shadow-md">
|
||||
<div class="container mx-auto px-4">
|
||||
<div class="flex items-center justify-between h-16">
|
||||
<!-- 网站Logo和标题 -->
|
||||
<div class="flex items-center">
|
||||
<a href="/" class="flex items-center space-x-2">
|
||||
<div class="w-8 h-8 rounded-full bg-primary-500 flex items-center justify-center text-white font-bold">M</div>
|
||||
<span
|
||||
class="text-xl font-bold tracking-wider bg-gradient-to-r from-primary-500 to-tertiary-500 bg-clip-text text-transparent">我的镜像站</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- 桌面导航 -->
|
||||
<nav class="hidden md:flex items-center space-x-1">
|
||||
<a href="/" class="btn btn-sm variant-ghost-surface">首页</a>
|
||||
<a href="/browse" class="btn btn-sm variant-ghost-surface">浏览</a>
|
||||
<a href="/popular" class="btn btn-sm variant-ghost-surface">热门</a>
|
||||
<a href="/new" class="btn btn-sm variant-ghost-surface">最新</a>
|
||||
<a href="/about" class="btn btn-sm variant-ghost-surface">关于</a>
|
||||
</nav>
|
||||
|
||||
<!-- 搜索和主题切换 -->
|
||||
<div class="flex items-center space-x-2">
|
||||
<!-- 搜索框 -->
|
||||
<div class="relative hidden md:block">
|
||||
<input
|
||||
type="search"
|
||||
bind:value={searchQuery}
|
||||
on:keydown={handleSearch}
|
||||
placeholder="搜索镜像..."
|
||||
class="input input-sm pl-9 pr-4 rounded-full w-40 lg:w-64 focus:w-72 transition-all duration-300"
|
||||
/>
|
||||
<button
|
||||
class="absolute left-2 top-1/2 transform -translate-y-1/2 text-surface-500-400-token"
|
||||
on:click={handleSearch}
|
||||
>
|
||||
<Search size={18} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 主题切换 -->
|
||||
<button
|
||||
class="btn btn-sm variant-ghost-surface aspect-square"
|
||||
on:click={toggleTheme}
|
||||
aria-label="切换主题"
|
||||
>
|
||||
{#if darkMode}
|
||||
<Sun size={18} />
|
||||
{:else}
|
||||
<Moon size={18} />
|
||||
{/if}
|
||||
</button>
|
||||
|
||||
<!-- 移动端菜单按钮 -->
|
||||
<button
|
||||
class="btn btn-sm variant-ghost-surface md:hidden aspect-square"
|
||||
on:click={() => mobileMenuOpen = !mobileMenuOpen}
|
||||
aria-label="菜单"
|
||||
>
|
||||
{#if mobileMenuOpen}
|
||||
<X size={18} />
|
||||
{:else}
|
||||
<Menu size={18} />
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Toaster {toaster}></Toaster>
|
||||
|
||||
<!-- 移动端菜单 -->
|
||||
{#if mobileMenuOpen}
|
||||
<div class="md:hidden bg-surface-100-800-token border-t border-surface-300-600-token">
|
||||
<div class="container mx-auto px-4 py-3 space-y-2">
|
||||
<a href="/" class="btn btn-sm w-full variant-ghost-surface justify-start">首页</a>
|
||||
<a href="/browse" class="btn btn-sm w-full variant-ghost-surface justify-start">浏览</a>
|
||||
<a href="/popular" class="btn btn-sm w-full variant-ghost-surface justify-start">热门</a>
|
||||
<a href="/new" class="btn btn-sm w-full variant-ghost-surface justify-start">最新</a>
|
||||
<a href="/about" class="btn btn-sm w-full variant-ghost-surface justify-start">关于</a>
|
||||
|
||||
<!-- 移动端搜索框 -->
|
||||
<div class="relative w-full mt-2">
|
||||
<input
|
||||
type="search"
|
||||
bind:value={searchQuery}
|
||||
on:keydown={handleSearch}
|
||||
placeholder="搜索镜像..."
|
||||
class="input input-sm pl-9 pr-4 rounded-full w-full"
|
||||
/>
|
||||
<button
|
||||
class="absolute left-2 top-1/2 transform -translate-y-1/2 text-surface-500-400-token"
|
||||
on:click={handleSearch}
|
||||
>
|
||||
<Search size={18} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</header>
|
||||
|
||||
<style>
|
||||
/*!* 活动链接样式 *!*/
|
||||
/*:global(a.active) {*/
|
||||
/* @apply bg-primary-500/20 text-primary-500;*/
|
||||
/*}*/
|
||||
|
||||
/*!* 链接悬停效果 *!*/
|
||||
/*a.btn:hover {*/
|
||||
/* @apply bg-primary-500/10;*/
|
||||
/*}*/
|
||||
|
||||
/*!* 平滑过渡 *!*/
|
||||
/*a, button {*/
|
||||
/* @apply transition-all duration-200;*/
|
||||
/*}*/
|
||||
</style>
|
||||
158
src/components/MirrorList.svelte
Normal file
158
src/components/MirrorList.svelte
Normal file
@ -0,0 +1,158 @@
|
||||
<script>
|
||||
import { onMount } from "svelte";
|
||||
import { Toaster, createToaster } from "@skeletonlabs/skeleton-svelte";
|
||||
|
||||
// 状态变量
|
||||
let mirrors = [];
|
||||
let loading = true;
|
||||
let error = null;
|
||||
let searchTerm = "";
|
||||
let sortBy = "name"; // 默认按名称排序
|
||||
|
||||
// Toast通知
|
||||
const toaster = createToaster();
|
||||
|
||||
// 获取镜像数据
|
||||
async function fetchMirrors() {
|
||||
console.log("Fetching mirrors...");
|
||||
try {
|
||||
loading = true;
|
||||
const response = await fetch("http://localhost:8082/static/tunasync.json");
|
||||
console.log(response);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP错误: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
mirrors = Object.entries(data).map(([name, info]) => ({
|
||||
name,
|
||||
...info,
|
||||
// 格式化最后更新时间
|
||||
lastUpdated: new Date(info.last_update_ts * 1000).toLocaleString("zh-CN")
|
||||
}));
|
||||
|
||||
} catch (err) {
|
||||
error = err.message;
|
||||
console.error(err);
|
||||
toaster.error({
|
||||
title: "加载失败",
|
||||
description: `无法获取镜像列表: ${err.message}`,
|
||||
timeout: 5000
|
||||
});
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 排序镜像
|
||||
$: sortedMirrors = [...mirrors].sort((a, b) => {
|
||||
if (sortBy === "name") return a.name.localeCompare(b.name);
|
||||
if (sortBy === "status") return a.status.localeCompare(b.status);
|
||||
if (sortBy === "date") return b.last_update_ts - a.last_update_ts;
|
||||
return 0;
|
||||
});
|
||||
|
||||
// 过滤镜像
|
||||
$: filteredMirrors = sortedMirrors.filter(mirror =>
|
||||
mirror.name.toLowerCase().includes(searchTerm.toLowerCase())
|
||||
);
|
||||
|
||||
// 获取状态对应的样式
|
||||
function getStatusBadgeClass(status) {
|
||||
switch (status) {
|
||||
case "success":
|
||||
return "badge-success";
|
||||
case "failed":
|
||||
return "badge-error";
|
||||
case "syncing":
|
||||
return "badge-warning";
|
||||
default:
|
||||
return "badge-surface";
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
fetchMirrors();
|
||||
console.log("Mounted and fetching mirrors...");
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="container mx-auto p-4">
|
||||
<div class="card p-4 mb-4">
|
||||
<h2 class="h2 mb-4">镜像列表</h2>
|
||||
|
||||
<!-- 搜索和排序控制 -->
|
||||
<div class="flex flex-col sm:flex-row items-center gap-4 mb-4">
|
||||
<div class="input-group input-group-divider grid-cols-[auto_1fr] w-full sm:w-auto">
|
||||
<input
|
||||
type="search"
|
||||
bind:value={searchTerm}
|
||||
placeholder="搜索镜像..."
|
||||
class="input"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<span>排序:</span>
|
||||
<select bind:value={sortBy} class="select">
|
||||
<option value="name">名称</option>
|
||||
<option value="status">状态</option>
|
||||
<option value="date">更新时间</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<button class="btn variant-filled-primary ml-auto" on:click={fetchMirrors}>
|
||||
刷新列表
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 加载状态 -->
|
||||
{#if loading}
|
||||
<div class="flex justify-center p-10">
|
||||
<div class="loader h-8 w-8"></div>
|
||||
</div>
|
||||
<!-- 错误信息 -->
|
||||
{:else if error}
|
||||
<div class="alert variant-filled-error">
|
||||
<p>加载失败: {error}</p>
|
||||
<button class="btn variant-filled" on:click={fetchMirrors}>重试</button>
|
||||
</div>
|
||||
<!-- 数据列表 -->
|
||||
{:else}
|
||||
<div class="table-container">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>镜像名称</th>
|
||||
<th>状态</th>
|
||||
<th>大小</th>
|
||||
<th>最后更新时间</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each filteredMirrors as mirror (mirror.name)}
|
||||
<tr class="{mirror.status === 'success' ? '' :
|
||||
mirror.status === 'failed' ? 'bg-red-500/10' :
|
||||
mirror.status === 'syncing' ? 'bg-yellow-500/10' : ''} hover:bg-surface-200/50 transition-colors duration-300 cursor-pointer">
|
||||
<td><span class="space-grotesk-google">{mirror.name}</span></td>
|
||||
<td>
|
||||
<span class="badge {getStatusBadgeClass(mirror.status)}">
|
||||
{mirror.status === 'success' ? '正常' : mirror.status === 'failed' ? '失败' : mirror.status === 'syncing' ? '同步中' : mirror.status}
|
||||
</span>
|
||||
</td>
|
||||
<td><span class="space-grotesk-google">{mirror.size || 'N/A'}</span></td>
|
||||
<td><span class="space-grotesk-google">{mirror.lastUpdated}</span></td>
|
||||
</tr>
|
||||
{:else}
|
||||
<tr>
|
||||
<td colspan="4" class="text-center py-4">未找到符合条件的镜像</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p class="text-sm mt-2 text-surface-500-400-token">共 {filteredMirrors.length} 个镜像</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
@ -1,4 +1,4 @@
|
||||
<script>
|
||||
</script>
|
||||
|
||||
<button type="button" class="btn preset-filled">Button</button>
|
||||
<button type="button" class="btn preset-filled m-20">Button</button>
|
||||
32
src/layouts/BasicLayout.astro
Normal file
32
src/layouts/BasicLayout.astro
Normal file
@ -0,0 +1,32 @@
|
||||
---
|
||||
// src/layouts/BaseLayout.astro
|
||||
import Header from "../components/Header.svelte"; // 引入 Svelte 头部组件
|
||||
import Footer from "../components/Footer.svelte"; // 引入 Svelte 页脚组件
|
||||
import "@/styles/global.css"; // 引入全局样式(包含 Tailwind 和 Skeleton 基础)
|
||||
|
||||
// 设置 HTML 的 data-theme 属性,让 Skeleton 主题生效
|
||||
// 注意:你可能需要 client:load 来确保 store 在客户端可用,或者在 <head> 中直接设置
|
||||
// 一个简单的示例,实际可能更复杂,取决于你的主题切换实现
|
||||
// const currentTheme = $theme; // 如果在 Astro 中直接读取 store
|
||||
---
|
||||
|
||||
<html lang="zh-CN" data-theme="skeleton">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<meta name="generator" content={Astro.generator} />
|
||||
<title>{Astro.props.title || "我的镜像站"}</title>
|
||||
<meta
|
||||
name="description"
|
||||
content={Astro.props.description || "文件镜像服务"}
|
||||
/>
|
||||
</head>
|
||||
<body class="bg-surface-100-800-token">
|
||||
<Header client:load />
|
||||
<main class="container mx-auto p-4">
|
||||
<slot />
|
||||
</main>
|
||||
<Footer client:idle />
|
||||
</body>
|
||||
</html>
|
||||
@ -1,22 +1,22 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<meta name="generator" content={Astro.generator} />
|
||||
<title>Astro Basics</title>
|
||||
</head>
|
||||
<body>
|
||||
<slot />
|
||||
</body>
|
||||
<html lang="en" data-theme="cerberus">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<meta name="generator" content={Astro.generator} />
|
||||
<title>Astro Basics</title>
|
||||
</head>
|
||||
<body>
|
||||
<slot />
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,14 +1,16 @@
|
||||
---
|
||||
import Welcome from "../components/Welcome.astro";
|
||||
import Layout from "../layouts/Layout.astro";
|
||||
import BasicLayout from "../layouts/BasicLayout.astro";
|
||||
import Test from "../components/Test.svelte";
|
||||
import "@/styles/global.css";
|
||||
import MirrorList from "../components/MirrorList.svelte";
|
||||
|
||||
// Welcome to Astro! Wondering what to do next? Check out the Astro documentation at https://docs.astro.build
|
||||
// Don't want to use any of this? Delete everything in this file, the `assets`, `components`, and `layouts` directories, and start fresh.
|
||||
---
|
||||
|
||||
<Layout>
|
||||
<BasicLayout>
|
||||
<!--<Welcome />-->
|
||||
<Test />
|
||||
</Layout>
|
||||
<!--<Test />-->
|
||||
<MirrorList client:load />
|
||||
</BasicLayout>
|
||||
|
||||
@ -3,4 +3,89 @@
|
||||
@import '@skeletonlabs/skeleton';
|
||||
@import '@skeletonlabs/skeleton/optional/presets';
|
||||
@import '@skeletonlabs/skeleton/themes/cerberus';
|
||||
@source '@skeletonlabs/skeleton-svelte/dist';
|
||||
|
||||
@source '@skeletonlabs/skeleton-svelte/dist';
|
||||
|
||||
@custom-variant dark (&:where(.dark, .dark *));
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
/* 定义你的基础颜色变量 (OKLCH 格式) */
|
||||
--background: oklch(1 0 0);
|
||||
--foreground: oklch(0.159 0.01 264.1);
|
||||
|
||||
--card: oklch(1 0 0);
|
||||
--card-foreground: oklch(0.159 0.01 264.1);
|
||||
|
||||
--popover: oklch(1 0 0);
|
||||
--popover-foreground: oklch(0.159 0.01 264.1);
|
||||
|
||||
--primary: oklch(0.401 0.157 259.222);
|
||||
--primary-foreground: oklch(0.981 0 0);
|
||||
|
||||
--secondary: oklch(0.961 0.002 264.1);
|
||||
--secondary-foreground: oklch(0.251 0.006 264.1);
|
||||
|
||||
--border: oklch(0.908 0.004 264.1);
|
||||
--input: oklch(0.908 0.004 264.1);
|
||||
--ring: oklch(0.251 0.006 264.1);
|
||||
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
.dark {
|
||||
/* 为暗模式重新定义变量 (OKLCH 格式) */
|
||||
--background: oklch(0.159 0.01 264.1);
|
||||
--foreground: oklch(0.981 0 0);
|
||||
|
||||
--card: oklch(0.159 0.01 264.1);
|
||||
--card-foreground: oklch(0.981 0 0);
|
||||
|
||||
--popover: oklch(0.159 0.01 264.1);
|
||||
--popover-foreground: oklch(0.981 0 0);
|
||||
|
||||
--primary: oklch(0.746 0.131 185.308);
|
||||
--primary-foreground: oklch(0.251 0.006 264.1);
|
||||
|
||||
--secondary: oklch(0.308 0.004 264.1);
|
||||
--secondary-foreground: oklch(0.981 0 0);
|
||||
|
||||
--border: oklch(0.308 0.004 264.1);
|
||||
--input: oklch(0.308 0.004 264.1);
|
||||
--ring: oklch(0.85 0.003 264.1);
|
||||
}
|
||||
}
|
||||
|
||||
@theme static {
|
||||
--color-primary: oklch(var(--primary));
|
||||
--color-primary-foreground: oklch(var(--primary-foreground));
|
||||
--color-secondary: oklch(var(--secondary));
|
||||
--color-secondary-foreground: oklch(var(--secondary-foreground));
|
||||
--color-background: oklch(var(--background));
|
||||
--color-foreground: oklch(var(--foreground));
|
||||
--color-border: oklch(var(--border));
|
||||
--color-input: oklch(var(--input));
|
||||
--color-ring: oklch(var(--ring));
|
||||
--color-card: oklch(var(--card));
|
||||
}
|
||||
|
||||
:root {
|
||||
background: var(--background);
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Space Grotesk';
|
||||
src: url('/grotesk.woff2') format('woff2');
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
/* 或者创建特定类 */
|
||||
.space-grotesk-google {
|
||||
font-family: 'Space Grotesk', sans-serif;
|
||||
font-optical-sizing: auto;
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user