1057 lines
38 KiB
HTML
1057 lines
38 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>个性化导航</title>
|
||
<style>
|
||
:root {
|
||
--primary-color: #0F3460;
|
||
--secondary-color: #1A73E8;
|
||
--text-color: #ffffff;
|
||
--card-bg: rgba(255, 255, 255, 0.1);
|
||
--card-hover: rgba(255, 255, 255, 0.2);
|
||
--shadow-color: rgba(0, 0, 0, 0.3);
|
||
}
|
||
|
||
.theme-dark {
|
||
--primary-color: #0F3460;
|
||
--secondary-color: #1A73E8;
|
||
--text-color: #ffffff;
|
||
--card-bg: rgba(255, 255, 255, 0.1);
|
||
--card-hover: rgba(255, 255, 255, 0.2);
|
||
--shadow-color: rgba(0, 0, 0, 0.3);
|
||
}
|
||
|
||
.theme-light {
|
||
--primary-color: #E3F2FD;
|
||
--secondary-color: #90CAF9;
|
||
--text-color: #333333;
|
||
--card-bg: rgba(255, 255, 255, 0.7);
|
||
--card-hover: rgba(255, 255, 255, 0.9);
|
||
--shadow-color: rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
.theme-warm {
|
||
--primary-color: #FF7043;
|
||
--secondary-color: #FFA000;
|
||
--text-color: #333333;
|
||
--card-bg: rgba(255, 255, 255, 0.7);
|
||
--card-hover: rgba(255, 255, 255, 0.9);
|
||
--shadow-color: rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
.theme-cool {
|
||
--primary-color: #4DB6AC;
|
||
--secondary-color: #80DEEA;
|
||
--text-color: #333333;
|
||
--card-bg: rgba(255, 255, 255, 0.7);
|
||
--card-hover: rgba(255, 255, 255, 0.9);
|
||
--shadow-color: rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
transition: background-color 0.5s ease, color 0.3s ease, transform 0.2s ease, box-shadow 0.3s ease;
|
||
}
|
||
|
||
body {
|
||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||
min-height: 100vh;
|
||
background: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%);
|
||
color: var(--text-color);
|
||
padding: 20px;
|
||
overflow-x: hidden;
|
||
background-attachment: fixed;
|
||
background-size: 200% 200%;
|
||
animation: gradientBG 15s ease infinite;
|
||
}
|
||
|
||
@keyframes gradientBG {
|
||
0% {
|
||
background-position: 0% 50%;
|
||
}
|
||
50% {
|
||
background-position: 100% 50%;
|
||
}
|
||
100% {
|
||
background-position: 0% 50%;
|
||
}
|
||
}
|
||
|
||
.container {
|
||
max-width: 1200px;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 30px;
|
||
animation: fadeInDown 0.8s ease;
|
||
}
|
||
|
||
@keyframes fadeInDown {
|
||
from {
|
||
opacity: 0;
|
||
transform: translateY(-20px);
|
||
}
|
||
to {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
}
|
||
}
|
||
|
||
.logo {
|
||
font-size: 24px;
|
||
font-weight: bold;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.logo i {
|
||
margin-right: 10px;
|
||
font-size: 28px;
|
||
}
|
||
|
||
.settings {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 15px;
|
||
}
|
||
|
||
.settings-btn {
|
||
background: var(--card-bg);
|
||
border: none;
|
||
color: var(--text-color);
|
||
width: 40px;
|
||
height: 40px;
|
||
border-radius: 50%;
|
||
cursor: pointer;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
box-shadow: 0 4px 6px var(--shadow-color);
|
||
}
|
||
|
||
.settings-btn:hover {
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 6px 8px var(--shadow-color);
|
||
}
|
||
|
||
.search-container {
|
||
display: flex;
|
||
justify-content: center;
|
||
margin-bottom: 40px;
|
||
position: relative;
|
||
animation: fadeIn 1s ease;
|
||
}
|
||
|
||
@keyframes fadeIn {
|
||
from {
|
||
opacity: 0;
|
||
}
|
||
to {
|
||
opacity: 1;
|
||
}
|
||
}
|
||
|
||
.search-box {
|
||
width: 600px;
|
||
max-width: 100%;
|
||
position: relative;
|
||
}
|
||
|
||
.search-input {
|
||
width: 100%;
|
||
padding: 15px 20px;
|
||
border-radius: 50px;
|
||
border: none;
|
||
background: var(--card-bg);
|
||
color: var(--text-color);
|
||
font-size: 16px;
|
||
box-shadow: 0 4px 15px var(--shadow-color);
|
||
backdrop-filter: blur(5px);
|
||
outline: none;
|
||
}
|
||
|
||
.search-input::placeholder {
|
||
color: rgba(var(--text-color), 0.7);
|
||
}
|
||
|
||
.search-engine-selector {
|
||
position: absolute;
|
||
right: 10px;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
background: var(--card-bg);
|
||
border: none;
|
||
color: var(--text-color);
|
||
padding: 5px 10px;
|
||
border-radius: 20px;
|
||
cursor: pointer;
|
||
backdrop-filter: blur(5px);
|
||
}
|
||
|
||
.nav-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
|
||
gap: 20px;
|
||
margin-bottom: 30px;
|
||
}
|
||
|
||
.nav-card {
|
||
background: var(--card-bg);
|
||
border-radius: 10px;
|
||
padding: 15px;
|
||
text-align: center;
|
||
cursor: pointer;
|
||
box-shadow: 0 4px 6px var(--shadow-color);
|
||
backdrop-filter: blur(5px);
|
||
position: relative;
|
||
animation: fadeInUp 0.5s ease;
|
||
user-select: none;
|
||
}
|
||
|
||
@keyframes fadeInUp {
|
||
from {
|
||
opacity: 0;
|
||
transform: translateY(20px);
|
||
}
|
||
to {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
}
|
||
}
|
||
|
||
.nav-card:hover {
|
||
transform: translateY(-5px);
|
||
box-shadow: 0 8px 15px var(--shadow-color);
|
||
background: var(--card-hover);
|
||
}
|
||
|
||
.nav-card i {
|
||
font-size: 30px;
|
||
margin-bottom: 10px;
|
||
display: block;
|
||
}
|
||
|
||
.nav-card .title {
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.nav-card .delete-btn {
|
||
position: absolute;
|
||
top: -8px;
|
||
right: -8px;
|
||
background: #ff4444;
|
||
color: white;
|
||
width: 20px;
|
||
height: 20px;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 12px;
|
||
opacity: 0;
|
||
transition: opacity 0.3s ease;
|
||
}
|
||
|
||
.nav-card:hover .delete-btn {
|
||
opacity: 1;
|
||
}
|
||
|
||
.add-card {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
cursor: pointer;
|
||
background: var(--card-bg);
|
||
border: 2px dashed rgba(var(--text-color), 0.3);
|
||
border-radius: 10px;
|
||
height: 100%;
|
||
min-height: 100px;
|
||
animation: pulse 2s infinite;
|
||
}
|
||
|
||
@keyframes pulse {
|
||
0% {
|
||
opacity: 0.7;
|
||
}
|
||
50% {
|
||
opacity: 1;
|
||
}
|
||
100% {
|
||
opacity: 0.7;
|
||
}
|
||
}
|
||
|
||
.add-card:hover {
|
||
background: var(--card-hover);
|
||
border-color: rgba(var(--text-color), 0.5);
|
||
}
|
||
|
||
.add-card i {
|
||
font-size: 24px;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.modal {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background: rgba(0, 0, 0, 0.7);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 1000;
|
||
opacity: 0;
|
||
pointer-events: none;
|
||
transition: opacity 0.3s ease;
|
||
backdrop-filter: blur(5px);
|
||
}
|
||
|
||
.modal.active {
|
||
opacity: 1;
|
||
pointer-events: all;
|
||
}
|
||
|
||
.modal-content {
|
||
background: var(--card-bg);
|
||
padding: 30px;
|
||
border-radius: 15px;
|
||
width: 90%;
|
||
max-width: 500px;
|
||
max-height: 90vh;
|
||
overflow-y: auto;
|
||
transform: translateY(-20px);
|
||
transition: transform 0.3s ease;
|
||
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
|
||
backdrop-filter: blur(10px);
|
||
}
|
||
|
||
.modal.active .modal-content {
|
||
transform: translateY(0);
|
||
}
|
||
|
||
.modal-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.modal-title {
|
||
font-size: 20px;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.close-btn {
|
||
background: none;
|
||
border: none;
|
||
font-size: 24px;
|
||
cursor: pointer;
|
||
color: var(--text-color);
|
||
}
|
||
|
||
.form-group {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.form-group label {
|
||
display: block;
|
||
margin-bottom: 8px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.form-control {
|
||
width: 100%;
|
||
padding: 10px 15px;
|
||
border-radius: 8px;
|
||
border: 1px solid rgba(var(--text-color), 0.2);
|
||
background: rgba(255, 255, 255, 0.1);
|
||
color: var(--text-color);
|
||
outline: none;
|
||
}
|
||
|
||
.form-control:focus {
|
||
border-color: var(--secondary-color);
|
||
}
|
||
|
||
.btn {
|
||
padding: 10px 20px;
|
||
border-radius: 8px;
|
||
border: none;
|
||
cursor: pointer;
|
||
font-weight: 500;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.btn-primary {
|
||
background: var(--secondary-color);
|
||
color: white;
|
||
}
|
||
|
||
.btn-primary:hover {
|
||
background: var(--primary-color);
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 4px 8px var(--shadow-color);
|
||
}
|
||
|
||
.btn-secondary {
|
||
background: rgba(var(--text-color), 0.1);
|
||
color: var(--text-color);
|
||
}
|
||
|
||
.btn-secondary:hover {
|
||
background: rgba(var(--text-color), 0.2);
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 4px 8px var(--shadow-color);
|
||
}
|
||
|
||
.theme-options {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, 1fr);
|
||
gap: 15px;
|
||
margin-top: 15px;
|
||
}
|
||
|
||
.theme-option {
|
||
padding: 15px;
|
||
border-radius: 10px;
|
||
cursor: pointer;
|
||
text-align: center;
|
||
border: 2px solid transparent;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.theme-option:hover {
|
||
transform: scale(1.05);
|
||
}
|
||
|
||
.theme-option.active {
|
||
border-color: var(--text-color);
|
||
box-shadow: 0 0 0 2px var(--secondary-color);
|
||
}
|
||
|
||
.theme-dark-preview {
|
||
background: linear-gradient(135deg, #0F3460 0%, #1A73E8 100%);
|
||
}
|
||
|
||
.theme-light-preview {
|
||
background: linear-gradient(135deg, #E3F2FD 0%, #90CAF9 100%);
|
||
}
|
||
|
||
.theme-warm-preview {
|
||
background: linear-gradient(135deg, #FF7043 0%, #FFA000 100%);
|
||
}
|
||
|
||
.theme-cool-preview {
|
||
background: linear-gradient(135deg, #4DB6AC 0%, #80DEEA 100%);
|
||
}
|
||
|
||
.resize-handle {
|
||
position: absolute;
|
||
width: 10px;
|
||
height: 10px;
|
||
background: var(--secondary-color);
|
||
border-radius: 50%;
|
||
bottom: -5px;
|
||
right: -5px;
|
||
cursor: nwse-resize;
|
||
opacity: 0;
|
||
transition: opacity 0.3s ease;
|
||
}
|
||
|
||
.nav-card:hover .resize-handle {
|
||
opacity: 1;
|
||
}
|
||
|
||
.draggable {
|
||
touch-action: none;
|
||
user-select: none;
|
||
}
|
||
|
||
.grid-stack {
|
||
position: relative;
|
||
}
|
||
|
||
.grid-stack-item {
|
||
position: absolute;
|
||
}
|
||
|
||
.grid-stack-item-content {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
/* 响应式调整 */
|
||
@media (max-width: 768px) {
|
||
.nav-grid {
|
||
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
|
||
gap: 15px;
|
||
}
|
||
|
||
.search-box {
|
||
width: 100%;
|
||
}
|
||
|
||
.theme-options {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
}
|
||
|
||
/* 字体图标 */
|
||
@font-face {
|
||
font-family: 'Material Icons';
|
||
font-style: normal;
|
||
font-weight: 400;
|
||
src: url(https://fonts.gstatic.com/s/materialicons/v139/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2) format('woff2');
|
||
}
|
||
|
||
.material-icons {
|
||
font-family: 'Material Icons';
|
||
font-weight: normal;
|
||
font-style: normal;
|
||
font-size: 24px;
|
||
line-height: 1;
|
||
letter-spacing: normal;
|
||
text-transform: none;
|
||
display: inline-block;
|
||
white-space: nowrap;
|
||
word-wrap: normal;
|
||
direction: ltr;
|
||
-webkit-font-feature-settings: 'liga';
|
||
-webkit-font-smoothing: antialiased;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body class="theme-dark">
|
||
<div class="container">
|
||
<header>
|
||
<div class="logo">
|
||
<i class="material-icons">navigation</i>
|
||
<span>个性化导航</span>
|
||
</div>
|
||
<div class="settings">
|
||
<button class="settings-btn" id="themeBtn" title="切换主题">
|
||
<i class="material-icons">palette</i>
|
||
</button>
|
||
<button class="settings-btn" id="addBtn" title="添加快捷方式">
|
||
<i class="material-icons">add</i>
|
||
</button>
|
||
<button class="settings-btn" id="editBtn" title="编辑模式">
|
||
<i class="material-icons">edit</i>
|
||
</button>
|
||
</div>
|
||
</header>
|
||
|
||
<div class="search-container">
|
||
<div class="search-box" id="searchBox">
|
||
<input type="text" class="search-input" id="searchInput" placeholder="搜索...">
|
||
<select class="search-engine-selector" id="searchEngine">
|
||
<option value="https://www.google.com/search?q=">Google</option>
|
||
<option value="https://www.bing.com/search?q=">Bing</option>
|
||
<option value="https://www.baidu.com/s?wd=">百度</option>
|
||
<option value="https://search.yahoo.com/search?p=">Yahoo</option>
|
||
<option value="https://duckduckgo.com/?q=">DuckDuckGo</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="nav-grid" id="navGrid">
|
||
<!-- 导航项将通过JS动态添加 -->
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 添加快捷方式模态框 -->
|
||
<div class="modal" id="addModal">
|
||
<div class="modal-content">
|
||
<div class="modal-header">
|
||
<div class="modal-title">添加快捷方式</div>
|
||
<button class="close-btn" id="closeAddModal">×</button>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="siteName">网站名称</label>
|
||
<input type="text" id="siteName" class="form-control" placeholder="例如: 谷歌">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="siteUrl">网站地址</label>
|
||
<input type="text" id="siteUrl" class="form-control" placeholder="https://www.google.com">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="siteIcon">图标</label>
|
||
<select id="siteIcon" class="form-control">
|
||
<option value="language">语言</option>
|
||
<option value="home">主页</option>
|
||
<option value="mail">邮件</option>
|
||
<option value="video_library">视频</option>
|
||
<option value="music_note">音乐</option>
|
||
<option value="shopping_cart">购物</option>
|
||
<option value="work">工作</option>
|
||
<option value="school">学习</option>
|
||
<option value="public">社交</option>
|
||
<option value="settings">设置</option>
|
||
</select>
|
||
</div>
|
||
<button class="btn btn-primary" id="saveSite">保存</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 主题设置模态框 -->
|
||
<div class="modal" id="themeModal">
|
||
<div class="modal-content">
|
||
<div class="modal-header">
|
||
<div class="modal-title">主题设置</div>
|
||
<button class="close-btn" id="closeThemeModal">×</button>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>选择主题</label>
|
||
<div class="theme-options">
|
||
<div class="theme-option theme-dark-preview active" data-theme="dark">
|
||
<div>深色主题</div>
|
||
</div>
|
||
<div class="theme-option theme-light-preview" data-theme="light">
|
||
<div>浅色主题</div>
|
||
</div>
|
||
<div class="theme-option theme-warm-preview" data-theme="warm">
|
||
<div>暖色主题</div>
|
||
</div>
|
||
<div class="theme-option theme-cool-preview" data-theme="cool">
|
||
<div>冷色主题</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="customPrimary">自定义主色</label>
|
||
<input type="color" id="customPrimary" class="form-control">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="customSecondary">自定义次色</label>
|
||
<input type="color" id="customSecondary" class="form-control">
|
||
</div>
|
||
<button class="btn btn-primary" id="applyTheme">应用主题</button>
|
||
<button class="btn btn-secondary" id="resetTheme">重置为默认</button>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
// 初始化变量
|
||
let isEditMode = false;
|
||
let navItems = JSON.parse(localStorage.getItem('navItems')) || [
|
||
{ name: '谷歌', url: 'https://www.google.com', icon: 'language' },
|
||
{ name: 'YouTube', url: 'https://www.youtube.com', icon: 'video_library' },
|
||
{ name: 'GitHub', url: 'https://github.com', icon: 'code' },
|
||
{ name: '微博', url: 'https://weibo.com', icon: 'public' },
|
||
{ name: '知乎', url: 'https://www.zhihu.com', icon: 'forum' },
|
||
{ name: 'B站', url: 'https://www.bilibili.com', icon: 'play_circle_filled' },
|
||
{ name: '淘宝', url: 'https://www.taobao.com', icon: 'shopping_cart' },
|
||
{ name: '网易云', url: 'https://music.163.com', icon: 'music_note' }
|
||
];
|
||
|
||
let searchEngine = localStorage.getItem('searchEngine') || 'https://www.google.com/search?q=';
|
||
let currentTheme = localStorage.getItem('theme') || 'dark';
|
||
let customPrimary = localStorage.getItem('customPrimary') || '';
|
||
let customSecondary = localStorage.getItem('customSecondary') || '';
|
||
|
||
// DOM元素
|
||
const navGrid = document.getElementById('navGrid');
|
||
const searchInput = document.getElementById('searchInput');
|
||
const searchEngineSelect = document.getElementById('searchEngine');
|
||
const addModal = document.getElementById('addModal');
|
||
const themeModal = document.getElementById('themeModal');
|
||
const addBtn = document.getElementById('addBtn');
|
||
const themeBtn = document.getElementById('themeBtn');
|
||
const editBtn = document.getElementById('editBtn');
|
||
const closeAddModal = document.getElementById('closeAddModal');
|
||
const closeThemeModal = document.getElementById('closeThemeModal');
|
||
const saveSiteBtn = document.getElementById('saveSite');
|
||
const applyThemeBtn = document.getElementById('applyTheme');
|
||
const resetThemeBtn = document.getElementById('resetTheme');
|
||
const siteNameInput = document.getElementById('siteName');
|
||
const siteUrlInput = document.getElementById('siteUrl');
|
||
const siteIconSelect = document.getElementById('siteIcon');
|
||
const customPrimaryInput = document.getElementById('customPrimary');
|
||
const customSecondaryInput = document.getElementById('customSecondary');
|
||
const searchBox = document.getElementById('searchBox');
|
||
|
||
// 初始化页面
|
||
initPage();
|
||
|
||
// 初始化页面函数
|
||
function initPage() {
|
||
// 设置主题
|
||
document.body.className = `theme-${currentTheme}`;
|
||
if (customPrimary && customSecondary) {
|
||
applyCustomTheme(customPrimary, customSecondary);
|
||
}
|
||
|
||
// 设置搜索引擎
|
||
searchEngineSelect.value = searchEngine;
|
||
|
||
// 渲染导航项
|
||
renderNavItems();
|
||
|
||
// 初始化搜索框动画
|
||
initSearchBoxAnimation();
|
||
}
|
||
|
||
// 渲染导航项
|
||
function renderNavItems() {
|
||
navGrid.innerHTML = '';
|
||
|
||
navItems.forEach((item, index) => {
|
||
const card = document.createElement('div');
|
||
card.className = 'nav-card draggable';
|
||
card.setAttribute('data-index', index);
|
||
card.style.animationDelay = `${index * 0.1}s`;
|
||
|
||
card.innerHTML = `
|
||
<i class="material-icons">${item.icon}</i>
|
||
<div class="title">${item.name}</div>
|
||
<div class="delete-btn" style="display: ${isEditMode ? 'flex' : 'none'}">×</div>
|
||
<div class="resize-handle" style="display: ${isEditMode ? 'block' : 'none'}"></div>
|
||
`;
|
||
|
||
// 添加点击事件
|
||
card.addEventListener('click', function(e) {
|
||
if (!isEditMode && !e.target.classList.contains('delete-btn')) {
|
||
window.open(item.url, '_blank');
|
||
}
|
||
});
|
||
|
||
// 添加删除按钮事件
|
||
const deleteBtn = card.querySelector('.delete-btn');
|
||
deleteBtn.addEventListener('click', function(e) {
|
||
e.stopPropagation();
|
||
navItems.splice(index, 1);
|
||
saveNavItems();
|
||
renderNavItems();
|
||
});
|
||
|
||
navGrid.appendChild(card);
|
||
});
|
||
|
||
// 添加"添加"卡片
|
||
const addCard = document.createElement('div');
|
||
addCard.className = 'add-card';
|
||
addCard.innerHTML = `
|
||
<i class="material-icons">add</i>
|
||
<div>添加快捷方式</div>
|
||
`;
|
||
addCard.addEventListener('click', function() {
|
||
openAddModal();
|
||
});
|
||
navGrid.appendChild(addCard);
|
||
|
||
// 如果是编辑模式,初始化拖拽和调整大小
|
||
if (isEditMode) {
|
||
initDraggable();
|
||
initResizable();
|
||
}
|
||
}
|
||
|
||
// 初始化拖拽功能
|
||
function initDraggable() {
|
||
const cards = document.querySelectorAll('.nav-card');
|
||
|
||
cards.forEach(card => {
|
||
card.addEventListener('mousedown', function(e) {
|
||
if (e.target.classList.contains('delete-btn') ||
|
||
e.target.classList.contains('resize-handle')) {
|
||
return;
|
||
}
|
||
|
||
const startX = e.clientX;
|
||
const startY = e.clientY;
|
||
const startLeft = card.offsetLeft;
|
||
const startTop = card.offsetTop;
|
||
|
||
function moveCard(e) {
|
||
const dx = e.clientX - startX;
|
||
const dy = e.clientY - startY;
|
||
|
||
card.style.left = `${startLeft + dx}px`;
|
||
card.style.top = `${startTop + dy}px`;
|
||
card.style.position = 'absolute';
|
||
}
|
||
|
||
function stopDrag() {
|
||
document.removeEventListener('mousemove', moveCard);
|
||
document.removeEventListener('mouseup', stopDrag);
|
||
|
||
// 保存位置
|
||
const index = parseInt(card.getAttribute('data-index'));
|
||
navItems[index].position = {
|
||
left: card.offsetLeft,
|
||
top: card.offsetTop
|
||
};
|
||
saveNavItems();
|
||
}
|
||
|
||
document.addEventListener('mousemove', moveCard);
|
||
document.addEventListener('mouseup', stopDrag);
|
||
});
|
||
});
|
||
}
|
||
|
||
// 初始化调整大小功能
|
||
function initResizable() {
|
||
const cards = document.querySelectorAll('.nav-card');
|
||
|
||
cards.forEach(card => {
|
||
const resizeHandle = card.querySelector('.resize-handle');
|
||
|
||
resizeHandle.addEventListener('mousedown', function(e) {
|
||
e.stopPropagation();
|
||
|
||
const startX = e.clientX;
|
||
const startY = e.clientY;
|
||
const startWidth = card.offsetWidth;
|
||
const startHeight = card.offsetHeight;
|
||
|
||
function resizeCard(e) {
|
||
const dx = e.clientX - startX;
|
||
const dy = e.clientY - startY;
|
||
|
||
card.style.width = `${startWidth + dx}px`;
|
||
card.style.height = `${startHeight + dy}px`;
|
||
}
|
||
|
||
function stopResize() {
|
||
document.removeEventListener('mousemove', resizeCard);
|
||
document.removeEventListener('mouseup', stopResize);
|
||
|
||
// 保存大小
|
||
const index = parseInt(card.getAttribute('data-index'));
|
||
navItems[index].size = {
|
||
width: card.offsetWidth,
|
||
height: card.offsetHeight
|
||
};
|
||
saveNavItems();
|
||
}
|
||
|
||
document.addEventListener('mousemove', resizeCard);
|
||
document.addEventListener('mouseup', stopResize);
|
||
});
|
||
});
|
||
}
|
||
|
||
// 初始化搜索框动画
|
||
function initSearchBoxAnimation() {
|
||
searchBox.addEventListener('mousemove', function(e) {
|
||
const boxRect = searchBox.getBoundingClientRect();
|
||
const centerX = boxRect.left + boxRect.width / 2;
|
||
const centerY = boxRect.top + boxRect.height / 2;
|
||
|
||
const mouseX = e.clientX;
|
||
const mouseY = e.clientY;
|
||
|
||
const dx = (mouseX - centerX) / 20;
|
||
const dy = (mouseY - centerY) / 20;
|
||
|
||
// 限制偏移量在10px以内
|
||
const offsetX = Math.max(-10, Math.min(10, dx));
|
||
const offsetY = Math.max(-10, Math.min(10, dy));
|
||
|
||
searchBox.style.transform = `translate(${offsetX}px, ${offsetY}px)`;
|
||
});
|
||
|
||
searchBox.addEventListener('mouseleave', function() {
|
||
searchBox.style.transform = 'translate(0, 0)';
|
||
});
|
||
}
|
||
|
||
// 保存导航项到本地存储
|
||
function saveNavItems() {
|
||
localStorage.setItem('navItems', JSON.stringify(navItems));
|
||
}
|
||
|
||
// 打开添加快捷方式模态框
|
||
function openAddModal() {
|
||
siteNameInput.value = '';
|
||
siteUrlInput.value = '';
|
||
siteIconSelect.value = 'language';
|
||
addModal.classList.add('active');
|
||
}
|
||
|
||
// 打开主题设置模态框
|
||
function openThemeModal() {
|
||
// 设置当前选中的主题
|
||
document.querySelectorAll('.theme-option').forEach(option => {
|
||
option.classList.remove('active');
|
||
if (option.dataset.theme === currentTheme) {
|
||
option.classList.add('active');
|
||
}
|
||
});
|
||
|
||
// 设置自定义颜色
|
||
if (customPrimary) {
|
||
customPrimaryInput.value = customPrimary;
|
||
}
|
||
if (customSecondary) {
|
||
customSecondaryInput.value = customSecondary;
|
||
}
|
||
|
||
themeModal.classList.add('active');
|
||
}
|
||
|
||
// 应用自定义主题
|
||
function applyCustomTheme(primary, secondary) {
|
||
document.documentElement.style.setProperty('--primary-color', primary);
|
||
document.documentElement.style.setProperty('--secondary-color', secondary);
|
||
}
|
||
|
||
// 事件监听
|
||
addBtn.addEventListener('click', openAddModal);
|
||
themeBtn.addEventListener('click', openThemeModal);
|
||
|
||
editBtn.addEventListener('click', function() {
|
||
isEditMode = !isEditMode;
|
||
editBtn.innerHTML = `<i class="material-icons">${isEditMode ? 'done' : 'edit'}</i>`;
|
||
|
||
// 显示/隐藏删除按钮和调整大小手柄
|
||
document.querySelectorAll('.delete-btn').forEach(btn => {
|
||
btn.style.display = isEditMode ? 'flex' : 'none';
|
||
});
|
||
|
||
document.querySelectorAll('.resize-handle').forEach(handle => {
|
||
handle.style.display = isEditMode ? 'block' : 'none';
|
||
});
|
||
|
||
if (isEditMode) {
|
||
initDraggable();
|
||
initResizable();
|
||
}
|
||
});
|
||
|
||
closeAddModal.addEventListener('click', function() {
|
||
addModal.classList.remove('active');
|
||
});
|
||
|
||
closeThemeModal.addEventListener('click', function() {
|
||
themeModal.classList.remove('active');
|
||
});
|
||
|
||
saveSiteBtn.addEventListener('click', function() {
|
||
const name = siteNameInput.value.trim();
|
||
const url = siteUrlInput.value.trim();
|
||
const icon = siteIconSelect.value;
|
||
|
||
if (name && url) {
|
||
// 确保URL以http://或https://开头
|
||
const fullUrl = url.startsWith('http://') || url.startsWith('https://') ? url : `https://${url}`;
|
||
|
||
navItems.push({
|
||
name,
|
||
url: fullUrl,
|
||
icon
|
||
});
|
||
|
||
saveNavItems();
|
||
renderNavItems();
|
||
addModal.classList.remove('active');
|
||
}
|
||
});
|
||
|
||
// 主题选择
|
||
document.querySelectorAll('.theme-option').forEach(option => {
|
||
option.addEventListener('click', function() {
|
||
document.querySelectorAll('.theme-option').forEach(opt => {
|
||
opt.classList.remove('active');
|
||
});
|
||
this.classList.add('active');
|
||
currentTheme = this.dataset.theme;
|
||
});
|
||
});
|
||
|
||
applyThemeBtn.addEventListener('click', function() {
|
||
// 保存主题设置
|
||
localStorage.setItem('theme', currentTheme);
|
||
|
||
// 应用主题
|
||
document.body.className = `theme-${currentTheme}`;
|
||
|
||
// 如果有自定义颜色,应用它们
|
||
const primary = customPrimaryInput.value;
|
||
const secondary = customSecondaryInput.value;
|
||
|
||
if (primary && secondary) {
|
||
applyCustomTheme(primary, secondary);
|
||
localStorage.setItem('customPrimary', primary);
|
||
localStorage.setItem('customSecondary', secondary);
|
||
customPrimary = primary;
|
||
customSecondary = secondary;
|
||
} else {
|
||
// 清除自定义颜色
|
||
localStorage.removeItem('customPrimary');
|
||
localStorage.removeItem('customSecondary');
|
||
customPrimary = '';
|
||
customSecondary = '';
|
||
}
|
||
|
||
themeModal.classList.remove('active');
|
||
});
|
||
|
||
resetThemeBtn.addEventListener('click', function() {
|
||
// 重置为默认主题
|
||
currentTheme = 'dark';
|
||
document.body.className = 'theme-dark';
|
||
|
||
// 清除自定义颜色
|
||
localStorage.removeItem('customPrimary');
|
||
localStorage.removeItem('customSecondary');
|
||
customPrimary = '';
|
||
customSecondary = '';
|
||
|
||
// 更新UI
|
||
document.querySelectorAll('.theme-option').forEach(opt => {
|
||
opt.classList.remove('active');
|
||
if (opt.dataset.theme === 'dark') {
|
||
opt.classList.add('active');
|
||
}
|
||
});
|
||
|
||
customPrimaryInput.value = '';
|
||
customSecondaryInput.value = '';
|
||
|
||
localStorage.setItem('theme', 'dark');
|
||
});
|
||
|
||
// 搜索功能
|
||
searchInput.addEventListener('keypress', function(e) {
|
||
if (e.key === 'Enter') {
|
||
const query = searchInput.value.trim();
|
||
if (query) {
|
||
window.open(searchEngine + encodeURIComponent(query), '_blank');
|
||
}
|
||
}
|
||
});
|
||
|
||
// 搜索引擎选择
|
||
searchEngineSelect.addEventListener('change', function() {
|
||
searchEngine = this.value;
|
||
localStorage.setItem('searchEngine', searchEngine);
|
||
});
|
||
|
||
// 点击模态框外部关闭模态框
|
||
window.addEventListener('click', function(e) {
|
||
if (e.target === addModal) {
|
||
addModal.classList.remove('active');
|
||
}
|
||
if (e.target === themeModal) {
|
||
themeModal.classList.remove('active');
|
||
}
|
||
});
|
||
});
|
||
</script>
|
||
</body>
|
||
</html> |