feat(layout): 添加侧边栏并优化布局结构
- 在 +layout.svelte 中引入 Sidebar 组件并调整整体布局 - 使用 Flexbox 实现侧边栏与主内容区域的响应式布局 - 更新 Header 样式,使用 fixed 定位并添加阴影效果- 新增全局 CSS 变量以统一背景色调 - 添加 @tauri-apps/plugin-store依赖用于本地存储功能 - 创建 Sidebar 组件,包含导航图标及交互逻辑- 移除页面中旧的临时导航列表,替换为新布局结构 - 调整样式细节,增强视觉一致性和用户体验
This commit is contained in:
21
package-lock.json
generated
21
package-lock.json
generated
@@ -8,7 +8,8 @@
|
|||||||
"name": "it-tools",
|
"name": "it-tools",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "^2.9.0"
|
"@tauri-apps/api": "^2.9.0",
|
||||||
|
"@tauri-apps/plugin-store": "^2.4.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sveltejs/adapter-static": "^3.0.10",
|
"@sveltejs/adapter-static": "^3.0.10",
|
||||||
@@ -866,7 +867,6 @@
|
|||||||
"integrity": "sha512-TGFX1pZUt9qqY20Cv5NyYvy0iLWHf2jXi8s+eCGsig7jQMdwZWKUFMR6TbvFNhfDSUpc1sH/Y5EHv20g3HHA3g==",
|
"integrity": "sha512-TGFX1pZUt9qqY20Cv5NyYvy0iLWHf2jXi8s+eCGsig7jQMdwZWKUFMR6TbvFNhfDSUpc1sH/Y5EHv20g3HHA3g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@standard-schema/spec": "^1.0.0",
|
"@standard-schema/spec": "^1.0.0",
|
||||||
"@sveltejs/acorn-typescript": "^1.0.5",
|
"@sveltejs/acorn-typescript": "^1.0.5",
|
||||||
@@ -906,7 +906,6 @@
|
|||||||
"integrity": "sha512-YZs/OSKOQAQCnJvM/P+F1URotNnYNeU3P2s4oIpzm1uFaqUEqRxUB0g5ejMjEb5Gjb9/PiBI5Ktrq4rUUF8UVQ==",
|
"integrity": "sha512-YZs/OSKOQAQCnJvM/P+F1URotNnYNeU3P2s4oIpzm1uFaqUEqRxUB0g5ejMjEb5Gjb9/PiBI5Ktrq4rUUF8UVQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sveltejs/vite-plugin-svelte-inspector": "^5.0.0",
|
"@sveltejs/vite-plugin-svelte-inspector": "^5.0.0",
|
||||||
"debug": "^4.4.1",
|
"debug": "^4.4.1",
|
||||||
@@ -1439,6 +1438,15 @@
|
|||||||
"node": ">= 10"
|
"node": ">= 10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@tauri-apps/plugin-store": {
|
||||||
|
"version": "2.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-store/-/plugin-store-2.4.1.tgz",
|
||||||
|
"integrity": "sha512-ckGSEzZ5Ii4Hf2D5x25Oqnm2Zf9MfDWAzR+volY0z/OOBz6aucPKEY0F649JvQ0Vupku6UJo7ugpGRDOFOunkA==",
|
||||||
|
"license": "MIT OR Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@tauri-apps/api": "^2.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/cookie": {
|
"node_modules/@types/cookie": {
|
||||||
"version": "0.6.0",
|
"version": "0.6.0",
|
||||||
"resolved": "https://registry.npmmirror.com/@types/cookie/-/cookie-0.6.0.tgz",
|
"resolved": "https://registry.npmmirror.com/@types/cookie/-/cookie-0.6.0.tgz",
|
||||||
@@ -1459,7 +1467,6 @@
|
|||||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
},
|
},
|
||||||
@@ -2048,7 +2055,6 @@
|
|||||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
@@ -2091,7 +2097,6 @@
|
|||||||
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
|
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"prettier": "bin/prettier.cjs"
|
"prettier": "bin/prettier.cjs"
|
||||||
},
|
},
|
||||||
@@ -2108,7 +2113,6 @@
|
|||||||
"integrity": "sha512-pn1ra/0mPObzqoIQn/vUTR3ZZI6UuZ0sHqMK5x2jMLGrs53h0sXhkVuDcrlssHwIMk7FYrMjHBPoUSyyEEDlBQ==",
|
"integrity": "sha512-pn1ra/0mPObzqoIQn/vUTR3ZZI6UuZ0sHqMK5x2jMLGrs53h0sXhkVuDcrlssHwIMk7FYrMjHBPoUSyyEEDlBQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"prettier": "^3.0.0",
|
"prettier": "^3.0.0",
|
||||||
"svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0"
|
"svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0"
|
||||||
@@ -2300,7 +2304,6 @@
|
|||||||
"integrity": "sha512-kjkAjCk41mJfvJZG56XcJNOdJSke94JxtcX8zFzzz2vrt47E0LnoBzU6azIZ1aBxJgUep8qegAkguSf1GjxLXQ==",
|
"integrity": "sha512-kjkAjCk41mJfvJZG56XcJNOdJSke94JxtcX8zFzzz2vrt47E0LnoBzU6azIZ1aBxJgUep8qegAkguSf1GjxLXQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/remapping": "^2.3.4",
|
"@jridgewell/remapping": "^2.3.4",
|
||||||
"@jridgewell/sourcemap-codec": "^1.5.0",
|
"@jridgewell/sourcemap-codec": "^1.5.0",
|
||||||
@@ -2399,7 +2402,6 @@
|
|||||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
@@ -2414,7 +2416,6 @@
|
|||||||
"integrity": "sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==",
|
"integrity": "sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.25.0",
|
"esbuild": "^0.25.0",
|
||||||
"fdir": "^6.5.0",
|
"fdir": "^6.5.0",
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
"vite": "^7.1.10"
|
"vite": "^7.1.10"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "^2.9.0"
|
"@tauri-apps/api": "^2.9.0",
|
||||||
|
"@tauri-apps/plugin-store": "^2.4.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
@import 'tailwindcss';
|
@import 'tailwindcss';
|
||||||
|
|
||||||
|
:root{
|
||||||
|
--main-bg-color: #1f1f1f;
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background-color: #1f1f1f; /* 示例:一个深灰色 */
|
background-color: #1f1f1f; /* 示例:一个深灰色 */
|
||||||
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,9 +41,11 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
position: sticky;
|
position: fixed;
|
||||||
|
width: 100%;
|
||||||
top: 0;
|
top: 0;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
|
box-shadow: 1px 0 3px rgba(255, 255, 255, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.window-controls {
|
.window-controls {
|
||||||
|
|||||||
127
src/lib/components/layout/Sidebar.svelte
Normal file
127
src/lib/components/layout/Sidebar.svelte
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
// 您可以在此处导入 SvelteKit 的导航链接模块
|
||||||
|
// import { goto } from '$app/navigation';
|
||||||
|
|
||||||
|
// 模拟导航项数据
|
||||||
|
// 确保对象字面量语法正确无误
|
||||||
|
const navItems = [
|
||||||
|
{ icon: '🏠', label: '主页', path: '/' },
|
||||||
|
{ icon: '⭐', label: '收藏', path: '/favorites' },
|
||||||
|
{ icon: '💬', label: '聊天', path: '/chat' },
|
||||||
|
{ icon: '⚙️', label: '设置', path: '/settings' },
|
||||||
|
];
|
||||||
|
|
||||||
|
let activePath: string = '/'; // 明确声明类型
|
||||||
|
|
||||||
|
function navigate(path: string) {
|
||||||
|
activePath = path;
|
||||||
|
// goto(path); // 实际应用中使用 SvelteKit 的导航
|
||||||
|
console.log(`导航到: ${path}`);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<nav class="sidebar">
|
||||||
|
<!-- 顶部图标/Logo -->
|
||||||
|
<div class="sidebar-logo">
|
||||||
|
<span role="img" aria-label="App Logo">⚛️</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 中间导航图标 -->
|
||||||
|
<div class="nav-list">
|
||||||
|
{#each navItems as item}
|
||||||
|
<button
|
||||||
|
class="nav-item"
|
||||||
|
class:active={activePath === item.path}
|
||||||
|
on:click={() => navigate(item.path)}
|
||||||
|
title={item.label}
|
||||||
|
>
|
||||||
|
{item.icon}
|
||||||
|
</button>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 底部设置/用户图标 -->
|
||||||
|
<div class="bottom-icons">
|
||||||
|
<button class="nav-item" title="用户资料">👤</button>
|
||||||
|
<button class="nav-item" title="退出">↩️</button>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* 侧边栏的基础样式 */
|
||||||
|
.sidebar {
|
||||||
|
/* 根据图片,侧边栏宽度较窄,可能在 60px 左右 */
|
||||||
|
width: 25px;
|
||||||
|
min-width: 35px; /* 确保它不会收缩 */
|
||||||
|
height: 100%;
|
||||||
|
background-color: var(--main-bg-color); /* 比主背景稍亮 */
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column; /* 垂直排列内容 */
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px 0;
|
||||||
|
box-shadow: 1px 0 3px rgba(255, 255, 255, 0.1);
|
||||||
|
user-select: none; /* 阻止文本选择 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Logo/顶部区域 */
|
||||||
|
.sidebar-logo {
|
||||||
|
font-size: 1rem;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 导航列表区域 */
|
||||||
|
.nav-list {
|
||||||
|
flex: 1; /* 占据中间所有剩余垂直空间,将底部图标推到底部 */
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 15px; /* 增加图标间的间隔 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 底部图标区域 */
|
||||||
|
.bottom-icons {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 导航按钮样式 */
|
||||||
|
.nav-item {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: #b0b0b0; /* 默认图标颜色 */
|
||||||
|
font-size: 1rem;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.2s, color 0.2s;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 鼠标悬停效果 */
|
||||||
|
.nav-item:hover {
|
||||||
|
background-color: #3e3e3e;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 激活状态效果(关键:模拟选中高亮) */
|
||||||
|
.nav-item.active {
|
||||||
|
/* 侧边栏上常见的条状高亮 */
|
||||||
|
color: #ffffff;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.nav-item.active::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
width: 4px; /* 高亮的条形宽度 */
|
||||||
|
height: 80%;
|
||||||
|
background-color: #4CAF50; /* 绿色高亮条 */
|
||||||
|
border-radius: 0 4px 4px 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
import '../app.css';
|
import '../app.css';
|
||||||
import favicon from '$lib/assets/favicon.svg';
|
import favicon from '$lib/assets/favicon.svg';
|
||||||
import Header from '$lib/components/layout/Header.svelte';
|
import Header from '$lib/components/layout/Header.svelte';
|
||||||
|
import Sidebar from '$lib/components/layout/Sidebar.svelte';
|
||||||
|
|
||||||
let { children } = $props();
|
let { children } = $props();
|
||||||
</script>
|
</script>
|
||||||
@@ -10,5 +11,36 @@
|
|||||||
<link rel="icon" href={favicon} />
|
<link rel="icon" href={favicon} />
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
<Header/>
|
<Header/>
|
||||||
|
<div class="app-container">
|
||||||
|
|
||||||
{@render children()}
|
<!-- 1. 侧边栏: 固定宽度,全高 -->
|
||||||
|
<Sidebar />
|
||||||
|
<!-- 2. 主内容区域: 占据剩余所有空间 (flex-1) -->
|
||||||
|
<main class="main-content">
|
||||||
|
<!-- 渲染子路由的内容 (+page.svelte 或下级 +layout.svelte)
|
||||||
|
使用标准的 <slot /> 替换了 {@render children()} -->
|
||||||
|
|
||||||
|
{@render children()}
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* 确保整个应用容器占满整个视口 */
|
||||||
|
.app-container {
|
||||||
|
display: flex;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
overflow: hidden; /* 防止滚动条出现在侧边栏和主内容之间 */
|
||||||
|
background-color: #1e1e1e; /* 模拟深色背景 */
|
||||||
|
color: #f1f1f1;
|
||||||
|
padding-top: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 主内容区域占据剩余空间 */
|
||||||
|
.main-content {
|
||||||
|
flex: 1; /* 占据 Flex 容器的剩余空间 */
|
||||||
|
/* 允许主内容区域内部滚动 */
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
<div class="app-container">
|
<div class="app-container">
|
||||||
|
<div class="app-content">
|
||||||
<ul>
|
123
|
||||||
|
</div>
|
||||||
<li on:click={() => goto('/about')}>关于</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@@ -12,5 +10,5 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import { goto } from '$app/navigation';
|
|
||||||
</script>
|
</script>
|
||||||
Reference in New Issue
Block a user