Removes test and todo pages from app navigation
Cleans up navigation by excluding test and todo-related pages and their associated files. Simplifies the app structure to focus on the timestamp feature and prepares for future refactoring or feature updates.
This commit is contained in:
+2
-6
@@ -1,18 +1,14 @@
|
|||||||
import {HashRouter as Router, Routes, Route, NavLink} from 'react-router-dom';
|
import {HashRouter as Router, Routes, Route, NavLink} from 'react-router-dom';
|
||||||
import {useState, useEffect} from 'react';
|
import {useState, useEffect} from 'react';
|
||||||
import TimestampPage from './pages/TimestampPage';
|
import TimestampPage from './pages/TimestampPage';
|
||||||
import ElectronicWoodenFishPage from "./pages/ElectronicWoodenFishPage";
|
// import ElectronicWoodenFishPage from "./pages/ElectronicWoodenFishPage";
|
||||||
import TodoListPage from "./pages/TodoListPage";
|
|
||||||
import './App.css';
|
import './App.css';
|
||||||
import TestPage from "./pages/TestPage";
|
|
||||||
|
|
||||||
// 导航项配置数组,便于后续添加
|
// 导航项配置数组,便于后续添加
|
||||||
// 为了测试折叠功能,我们添加更多导航项
|
// 为了测试折叠功能,我们添加更多导航项
|
||||||
const navItems = [
|
const navItems = [
|
||||||
{path: '/', label: '时间戳', element: <TimestampPage/>},
|
{path: '/', label: '时间戳', element: <TimestampPage/>},
|
||||||
{path: '/dzmy', label: '电子木鱼', element: <ElectronicWoodenFishPage/>},
|
// {path: '/dzmy', label: '电子木鱼', element: <ElectronicWoodenFishPage/>},
|
||||||
{path: '/todo', label: '待办', element: <TodoListPage/>},
|
|
||||||
{path: '/test', label: '测试', element: <TestPage/>}
|
|
||||||
];
|
];
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
|
|||||||
@@ -1,131 +0,0 @@
|
|||||||
.app-container {
|
|
||||||
/* 关键:限制最小宽度和高度,适配 Chrome Extension Popup */
|
|
||||||
min-width: 350px;
|
|
||||||
min-height: 500px;
|
|
||||||
max-width: 800px; /* 在网页运行时限制最大宽度 */
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 20px;
|
|
||||||
background: white;
|
|
||||||
box-shadow: 0 0 10px rgba(0,0,0,0.05);
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
border-bottom: 2px solid #eee;
|
|
||||||
padding-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 按钮样式 */
|
|
||||||
button {
|
|
||||||
cursor: pointer;
|
|
||||||
border: none;
|
|
||||||
border-radius: 4px;
|
|
||||||
padding: 8px 16px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
.btn-primary { background-color: #007bff; color: white; }
|
|
||||||
.btn-save { background-color: #28a745; color: white; margin-right: 10px; }
|
|
||||||
.btn-cancel { background-color: #dc3545; color: white; }
|
|
||||||
|
|
||||||
/* 输入框 */
|
|
||||||
.input-area {
|
|
||||||
background: #f9f9f9;
|
|
||||||
padding: 15px;
|
|
||||||
border-radius: 8px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown-input {
|
|
||||||
width: 100%;
|
|
||||||
height: 100px;
|
|
||||||
padding: 10px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
border-radius: 4px;
|
|
||||||
resize: vertical;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
font-family: monospace;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 树状结构 */
|
|
||||||
.date-group {
|
|
||||||
margin-bottom: 15px;
|
|
||||||
border: 1px solid #eee;
|
|
||||||
border-radius: 6px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.date-header {
|
|
||||||
background-color: #e9ecef;
|
|
||||||
padding: 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
font-weight: bold;
|
|
||||||
user-select: none;
|
|
||||||
list-style: none; /* 隐藏默认三角,部分浏览器需要 */
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
/* 自定义折叠箭头 */
|
|
||||||
.date-header::before {
|
|
||||||
content: '▶';
|
|
||||||
display: inline-block;
|
|
||||||
margin-right: 8px;
|
|
||||||
font-size: 0.8em;
|
|
||||||
transition: transform 0.2s;
|
|
||||||
}
|
|
||||||
details[open] .date-header::before {
|
|
||||||
transform: rotate(90deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.count-badge {
|
|
||||||
background: #6c757d;
|
|
||||||
color: white;
|
|
||||||
border-radius: 10px;
|
|
||||||
padding: 2px 8px;
|
|
||||||
font-size: 0.8em;
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.todo-list {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.todo-item {
|
|
||||||
padding: 12px 15px;
|
|
||||||
border-top: 1px solid #f0f0f0;
|
|
||||||
cursor: pointer;
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-start;
|
|
||||||
transition: background 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.todo-item:hover {
|
|
||||||
background-color: #f1f8ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.time-tag {
|
|
||||||
font-size: 0.75em;
|
|
||||||
color: #999;
|
|
||||||
margin-right: 12px;
|
|
||||||
white-space: nowrap;
|
|
||||||
margin-top: 4px; /* 对齐 */
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown-content {
|
|
||||||
flex: 1;
|
|
||||||
font-size: 0.95em;
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Markdown 内部样式修正,防止标题太大 */
|
|
||||||
.markdown-content h1, .markdown-content h2, .markdown-content h3 {
|
|
||||||
margin: 5px 0;
|
|
||||||
font-size: 1.1em;
|
|
||||||
}
|
|
||||||
.markdown-content p {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
import React, { useState, useEffect, useMemo } from 'react';
|
|
||||||
import ReactMarkdown from 'react-markdown';
|
|
||||||
import { format } from 'date-fns';
|
|
||||||
import "./TestPage.css";
|
|
||||||
|
|
||||||
const TestPage = () => {
|
|
||||||
// 待办列表数据: { id, content, createdAt }
|
|
||||||
const [todos, setTodos] = useState(() => {
|
|
||||||
// 从 localStorage 初始化,保证刷新不丢失
|
|
||||||
const saved = localStorage.getItem('markdown-todos');
|
|
||||||
return saved ? JSON.parse(saved) : [];
|
|
||||||
});
|
|
||||||
|
|
||||||
// UI 状态
|
|
||||||
const [isInputVisible, setIsInputVisible] = useState(false);
|
|
||||||
const [inputValue, setInputValue] = useState('');
|
|
||||||
const [editingId, setEditingId] = useState(null); // 当前正在编辑的 ID,null 表示新增
|
|
||||||
|
|
||||||
// 持久化存储
|
|
||||||
useEffect(() => {
|
|
||||||
localStorage.setItem('markdown-todos', JSON.stringify(todos));
|
|
||||||
}, [todos]);
|
|
||||||
|
|
||||||
// --- 核心逻辑:数据处理 ---
|
|
||||||
|
|
||||||
// 1. 处理提交
|
|
||||||
const handleSubmit = () => {
|
|
||||||
if (!inputValue.trim()) return;
|
|
||||||
|
|
||||||
if (editingId) {
|
|
||||||
// 编辑模式
|
|
||||||
setTodos(prev => prev.map(item =>
|
|
||||||
item.id === editingId ? { ...item, content: inputValue } : item
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
// 新增模式
|
|
||||||
const newTodo = {
|
|
||||||
id: Date.now(),
|
|
||||||
content: inputValue,
|
|
||||||
createdAt: Date.now(),
|
|
||||||
};
|
|
||||||
setTodos(prev => [...prev, newTodo]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重置并关闭
|
|
||||||
setInputValue('');
|
|
||||||
setEditingId(null);
|
|
||||||
setIsInputVisible(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 2. 处理点击待办(进入编辑)
|
|
||||||
const handleEditClick = (todo) => {
|
|
||||||
setInputValue(todo.content);
|
|
||||||
setEditingId(todo.id);
|
|
||||||
setIsInputVisible(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 3. 处理取消/关闭
|
|
||||||
const handleCancel = () => {
|
|
||||||
setIsInputVisible(false);
|
|
||||||
setInputValue('');
|
|
||||||
setEditingId(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 4. 数据分组与排序 (核心需求 4)
|
|
||||||
const groupedTodos = useMemo(() => {
|
|
||||||
const groups = {};
|
|
||||||
|
|
||||||
todos.forEach(todo => {
|
|
||||||
// 第一层 Key: 日期 (例如 2023-10-27)
|
|
||||||
const dateKey = format(todo.createdAt, 'yyyy-MM-dd');
|
|
||||||
if (!groups[dateKey]) {
|
|
||||||
groups[dateKey] = [];
|
|
||||||
}
|
|
||||||
groups[dateKey].push(todo);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 将对象转为数组以便排序渲染
|
|
||||||
const groupArray = Object.keys(groups).map(date => ({
|
|
||||||
date,
|
|
||||||
items: groups[date]
|
|
||||||
}));
|
|
||||||
|
|
||||||
// 第一层排序:按日期倒序
|
|
||||||
groupArray.sort((a, b) => new Date(b.date) - new Date(a.date));
|
|
||||||
|
|
||||||
// 第二层排序:组内按添加时间倒序
|
|
||||||
groupArray.forEach(group => {
|
|
||||||
group.items.sort((a, b) => b.createdAt - a.createdAt);
|
|
||||||
});
|
|
||||||
|
|
||||||
return groupArray;
|
|
||||||
}, [todos]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="app-container">
|
|
||||||
<header className="app-header">
|
|
||||||
<h2>Markdown Todo Tree</h2>
|
|
||||||
{/* 如果没打开输入框,显示添加按钮 */}
|
|
||||||
{!isInputVisible && (
|
|
||||||
<button className="btn-primary" onClick={() => setIsInputVisible(true)}>
|
|
||||||
+ 新增待办
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</header>
|
|
||||||
|
|
||||||
{/* 输入区域 (Markdown) */}
|
|
||||||
{isInputVisible && (
|
|
||||||
<div className="input-area">
|
|
||||||
<textarea
|
|
||||||
className="markdown-input"
|
|
||||||
value={inputValue}
|
|
||||||
onChange={(e) => setInputValue(e.target.value)}
|
|
||||||
placeholder="支持 Markdown 语法,例如:# 标题 或 - 列表"
|
|
||||||
autoFocus
|
|
||||||
/>
|
|
||||||
<div className="action-buttons">
|
|
||||||
<button className="btn-save" onClick={handleSubmit}>
|
|
||||||
{editingId ? "更新" : "保存"}
|
|
||||||
</button>
|
|
||||||
<button className="btn-cancel" onClick={handleCancel}>
|
|
||||||
取消
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* 树状列表展示区域 */}
|
|
||||||
<div className="todo-tree">
|
|
||||||
{groupedTodos.length === 0 && <p className="empty-tip">暂无待办,点击上方添加</p>}
|
|
||||||
|
|
||||||
{groupedTodos.map((group) => (
|
|
||||||
// 使用 details/summary 原生标签实现折叠/展开
|
|
||||||
<details key={group.date} open className="date-group">
|
|
||||||
<summary className="date-header">
|
|
||||||
{group.date} <span className="count-badge">{group.items.length}</span>
|
|
||||||
</summary>
|
|
||||||
|
|
||||||
<div className="todo-list">
|
|
||||||
{group.items.map((todo) => (
|
|
||||||
<div
|
|
||||||
key={todo.id}
|
|
||||||
className="todo-item"
|
|
||||||
onClick={() => handleEditClick(todo)}
|
|
||||||
title="点击编辑"
|
|
||||||
>
|
|
||||||
<div className="time-tag">{format(todo.createdAt, "HH:mm")}</div>
|
|
||||||
<div className="markdown-content">
|
|
||||||
{/* 预览渲染 */}
|
|
||||||
<ReactMarkdown>{todo.content}</ReactMarkdown>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</details>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default TestPage;
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
import TodoMarkdownEditor from "../components/TodoMarkdownEditor";
|
|
||||||
import TodoList from "../components/TodoList";
|
|
||||||
|
|
||||||
|
|
||||||
function TodoListPage() {
|
|
||||||
return (<div>
|
|
||||||
<TodoMarkdownEditor/>
|
|
||||||
<TodoList todoContentList={['1. 创建待办事项列表', '2. 添加新的待办事项', '3. 删除已完成的待办事项']}/>
|
|
||||||
</div>)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default TodoListPage;
|
|
||||||
Reference in New Issue
Block a user