commit 935ecfc5aeca6bbe4223a85828c13a3a52a7aaa4
Author: root <root@hub.scroll.pub>
Date: 2024-12-30 14:44:31 +0000
Subject: Initial commit
diff --git a/body.html b/body.html
new file mode 100644
index 0000000..1728ea5
--- /dev/null
+++ b/body.html
@@ -0,0 +1,53 @@
+<header>
+ <h1>Daily Work Log</h1>
+ <nav>
+ <button id="newLogBtn" aria-label="Create new log entry">+ New Entry</button>
+ <div class="search-container">
+ <input type="search" id="searchInput" placeholder="Search logs..." aria-label="Search logs">
+ <select id="filterCategory" aria-label="Filter by category">
+ <option value="">All Categories</option>
+ </select>
+ </div>
+ </nav>
+</header>
+
+<main>
+ <section id="logForm" class="hidden">
+ <h2>Create Log Entry</h2>
+ <form id="workLogForm">
+ <div class="form-group">
+ <label for="logDate">Date:</label>
+ <input type="datetime-local" id="logDate" required>
+ </div>
+ <div class="form-group">
+ <label for="logCategory">Category:</label>
+ <input type="text" id="logCategory" list="categories" placeholder="Enter or select category">
+ <datalist id="categories"></datalist>
+ </div>
+ <div class="form-group">
+ <label for="logTags">Tags (comma-separated):</label>
+ <input type="text" id="logTags" placeholder="e.g., urgent, meeting, follow-up">
+ </div>
+ <div class="form-group">
+ <label for="logContent">Log Content:</label>
+ <textarea id="logContent" rows="6" required></textarea>
+ </div>
+ <div class="form-actions">
+ <button type="submit">Save Log</button>
+ <button type="button" id="cancelBtn">Cancel</button>
+ </div>
+ </form>
+ </section>
+
+ <section id="logList">
+ <div class="log-controls">
+ <button id="sortDateBtn">Sort by Date</button>
+ <button id="exportBtn">Export Logs</button>
+ </div>
+ <div id="logEntries"></div>
+ </section>
+</main>
+
+<footer>
+ <p>Work Log Manager - A simple tool to track your daily work activities</p>
+</footer>
diff --git a/index.scroll b/index.scroll
new file mode 100644
index 0000000..f7f9ec7
--- /dev/null
+++ b/index.scroll
@@ -0,0 +1,8 @@
+buildHtml
+baseUrl https://worklog.scroll.pub
+metaTags
+editButton /edit.html
+title Daily Work Log Manager
+style.css
+body.html
+script.js
diff --git a/prompt.json b/prompt.json
new file mode 100644
index 0000000..bd27b87
--- /dev/null
+++ b/prompt.json
@@ -0,0 +1,20 @@
+{
+ "id": "msg_01VqE2sepDJzcjtA7fs96faK",
+ "type": "message",
+ "role": "assistant",
+ "model": "claude-3-5-sonnet-20241022",
+ "content": [
+ {
+ "type": "text",
+ "text": "---domain---\nworklog.scroll.pub\n\n---index.scroll---\nbuildHtml\nbaseUrl https://worklog.scroll.pub\nmetaTags\neditButton /edit.html\ntitle Daily Work Log Manager\nstyle.css\nbody.html\nscript.js\n\n---body.html---\n<header>\n <h1>Daily Work Log</h1>\n <nav>\n <button id=\"newLogBtn\" aria-label=\"Create new log entry\">+ New Entry</button>\n <div class=\"search-container\">\n <input type=\"search\" id=\"searchInput\" placeholder=\"Search logs...\" aria-label=\"Search logs\">\n <select id=\"filterCategory\" aria-label=\"Filter by category\">\n <option value=\"\">All Categories</option>\n </select>\n </div>\n </nav>\n</header>\n\n<main>\n <section id=\"logForm\" class=\"hidden\">\n <h2>Create Log Entry</h2>\n <form id=\"workLogForm\">\n <div class=\"form-group\">\n <label for=\"logDate\">Date:</label>\n <input type=\"datetime-local\" id=\"logDate\" required>\n </div>\n <div class=\"form-group\">\n <label for=\"logCategory\">Category:</label>\n <input type=\"text\" id=\"logCategory\" list=\"categories\" placeholder=\"Enter or select category\">\n <datalist id=\"categories\"></datalist>\n </div>\n <div class=\"form-group\">\n <label for=\"logTags\">Tags (comma-separated):</label>\n <input type=\"text\" id=\"logTags\" placeholder=\"e.g., urgent, meeting, follow-up\">\n </div>\n <div class=\"form-group\">\n <label for=\"logContent\">Log Content:</label>\n <textarea id=\"logContent\" rows=\"6\" required></textarea>\n </div>\n <div class=\"form-actions\">\n <button type=\"submit\">Save Log</button>\n <button type=\"button\" id=\"cancelBtn\">Cancel</button>\n </div>\n </form>\n </section>\n\n <section id=\"logList\">\n <div class=\"log-controls\">\n <button id=\"sortDateBtn\">Sort by Date</button>\n <button id=\"exportBtn\">Export Logs</button>\n </div>\n <div id=\"logEntries\"></div>\n </section>\n</main>\n\n<footer>\n <p>Work Log Manager - A simple tool to track your daily work activities</p>\n</footer>\n\n---style.css---\n:root {\n --primary-color: #2c3e50;\n --secondary-color: #3498db;\n --accent-color: #e74c3c;\n --background-color: #f5f6fa;\n --text-color: #2c3e50;\n --border-radius: 8px;\n --shadow: 0 2px 4px rgba(0,0,0,0.1);\n}\n\n* {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\nbody {\n font-family: 'Segoe UI', system-ui, sans-serif;\n line-height: 1.6;\n color: var(--text-color);\n background: var(--background-color);\n}\n\nheader {\n background: var(--primary-color);\n color: white;\n padding: 1rem;\n box-shadow: var(--shadow);\n}\n\nh1 {\n font-size: 1.8rem;\n margin-bottom: 1rem;\n}\n\nnav {\n display: flex;\n gap: 1rem;\n flex-wrap: wrap;\n}\n\n.search-container {\n display: flex;\n gap: 0.5rem;\n flex-grow: 1;\n}\n\ninput, select, textarea {\n padding: 0.5rem;\n border: 2px solid #ddd;\n border-radius: var(--border-radius);\n font-size: 1rem;\n}\n\nbutton {\n background: var(--secondary-color);\n color: white;\n border: none;\n padding: 0.5rem 1rem;\n border-radius: var(--border-radius);\n cursor: pointer;\n transition: transform 0.2s, background-color 0.2s;\n}\n\nbutton:hover {\n background: #2980b9;\n transform: translateY(-2px);\n}\n\nmain {\n max-width: 1200px;\n margin: 2rem auto;\n padding: 0 1rem;\n}\n\n.form-group {\n margin-bottom: 1rem;\n}\n\n.form-group label {\n display: block;\n margin-bottom: 0.5rem;\n font-weight: 500;\n}\n\n.form-group input,\n.form-group textarea {\n width: 100%;\n}\n\n.log-entry {\n background: white;\n padding: 1rem;\n margin-bottom: 1rem;\n border-radius: var(--border-radius);\n box-shadow: var(--shadow);\n transition: transform 0.2s;\n}\n\n.log-entry:hover {\n transform: translateY(-2px);\n}\n\n.log-header {\n display: flex;\n justify-content: space-between;\n margin-bottom: 0.5rem;\n}\n\n.log-tags {\n display: flex;\n gap: 0.5rem;\n flex-wrap: wrap;\n margin: 0.5rem 0;\n}\n\n.tag {\n background: #e1e8ed;\n padding: 0.2rem 0.5rem;\n border-radius: 12px;\n font-size: 0.9rem;\n}\n\n.hidden {\n display: none;\n}\n\n.form-actions {\n display: flex;\n gap: 1rem;\n justify-content: flex-end;\n}\n\nfooter {\n text-align: center;\n padding: 2rem;\n background: var(--primary-color);\n color: white;\n margin-top: 2rem;\n}\n\n@media (max-width: 768px) {\n nav {\n flex-direction: column;\n }\n \n .search-container {\n flex-direction: column;\n }\n \n .log-header {\n flex-direction: column;\n gap: 0.5rem;\n }\n}\n\n---script.js---\nclass WorkLogManager {\n constructor() {\n this.logs = JSON.parse(localStorage.getItem('workLogs')) || [];\n this.categories = new Set(this.logs.map(log => log.category));\n this.setupEventListeners();\n this.updateCategoryList();\n this.renderLogs();\n }\n\n setupEventListeners() {\n document.getElementById('newLogBtn').addEventListener('click', () => {\n document.getElementById('logForm').classList.remove('hidden');\n document.getElementById('logDate').value = new Date().toISOString().slice(0, 16);\n });\n\n document.getElementById('workLogForm').addEventListener('submit', (e) => {\n e.preventDefault();\n this.saveLog();\n });\n\n document.getElementById('cancelBtn').addEventListener('click', () => {\n document.getElementById('logForm').classList.add('hidden');\n });\n\n document.getElementById('searchInput').addEventListener('input', () => this.filterLogs());\n document.getElementById('filterCategory').addEventListener('change', () => this.filterLogs());\n document.getElementById('sortDateBtn').addEventListener('click', () => this.toggleSort());\n document.getElementById('exportBtn').addEventListener('click', () => this.exportLogs());\n }\n\n saveLog() {\n const logData = {\n id: Date.now(),\n date: document.getElementById('logDate').value,\n category: document.getElementById('logCategory').value,\n tags: document.getElementById('logTags').value.split(',').map(tag => tag.trim()).filter(tag => tag),\n content: document.getElementById('logContent').value\n };\n\n this.logs.unshift(logData);\n this.updateLocalStorage();\n this.categories.add(logData.category);\n this.updateCategoryList();\n this.renderLogs();\n document.getElementById('workLogForm').reset();\n document.getElementById('logForm').classList.add('hidden');\n }\n\n updateLocalStorage() {\n localStorage.setItem('workLogs', JSON.stringify(this.logs));\n }\n\n updateCategoryList() {\n const categorySelect = document.getElementById('filterCategory');\n const categoryDatalist = document.getElementById('categories');\n \n categorySelect.innerHTML = '<option value=\"\">All Categories</option>';\n categoryDatalist.innerHTML = '';\n \n this.categories.forEach(category => {\n if (category) {\n categorySelect.innerHTML += `<option value=\"${category}\">${category}</option>`;\n categoryDatalist.innerHTML += `<option value=\"${category}\">`;\n }\n });\n }\n\n renderLogs() {\n const logEntries = document.getElementById('logEntries');\n logEntries.innerHTML = '';\n\n this.logs.forEach(log => {\n const logElement = document.createElement('div');\n logElement.className = 'log-entry';\n logElement.innerHTML = `\n <div class=\"log-header\">\n <div>\n <strong>${new Date(log.date).toLocaleString()}</strong>\n ${log.category ? `<span class=\"tag\">${log.category}</span>` : ''}\n </div>\n <div>\n <button onclick=\"workLogManager.editLog(${log.id})\">Edit</button>\n <button onclick=\"workLogManager.deleteLog(${log.id})\">Delete</button>\n </div>\n </div>\n <div class=\"log-tags\">\n ${log.tags.map(tag => `<span class=\"tag\">${tag}</span>`).join('')}\n </div>\n <div class=\"log-content\">${log.content.replace(/\\n/g, '<br>')}</div>\n `;\n logEntries.appendChild(logElement);\n });\n }\n\n editLog(id) {\n const log = this.logs.find(log => log.id === id);\n if (log) {\n document.getElementById('logDate').value = log.date;\n document.getElementById('logCategory').value = log.category;\n document.getElementById('logTags').value = log.tags.join(', ');\n document.getElementById('logContent').value = log.content;\n document.getElementById('logForm').classList.remove('hidden');\n this.deleteLog(id);\n }\n }\n\n deleteLog(id) {\n if (confirm('Are you sure you want to delete this log?')) {\n this.logs = this.logs.filter(log => log.id !== id);\n this.updateLocalStorage();\n this.renderLogs();\n }\n }\n\n filterLogs() {\n const searchTerm = document.getElementById('searchInput').value.toLowerCase();\n const categoryFilter = document.getElementById('filterCategory').value;\n \n const filtered = this.logs.filter(log => {\n const matchesSearch = log.content.toLowerCase().includes(searchTerm) ||\n log.tags.some(tag => tag.toLowerCase().includes(searchTerm));\n const matchesCategory = !categoryFilter || log.category === categoryFilter;\n return matchesSearch && matchesCategory;\n });\n\n this.renderFilteredLogs(filtered);\n }\n\n renderFilteredLogs(filtered) {\n const logEntries = document.getElementById('logEntries');\n logEntries.innerHTML = '';\n filtered.forEach(log => {\n // Reuse the same rendering logic as in renderLogs()\n const logElement = document.createElement('div');\n logElement.className = 'log-entry';\n // ... (same innerHTML content as in renderLogs)\n logEntries.appendChild(logElement);\n });\n }\n\n toggleSort() {\n this.logs.reverse();\n this.renderLogs();\n }\n\n exportLogs() {\n const exportData = JSON.stringify(this.logs, null, 2);\n const blob = new Blob([exportData], { type: 'application/json' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = `work-logs-${new Date().toISOString().slice(0,10)}.json`;\n document.body.appendChild(a);\n a.click();\n document.body.removeChild(a);\n URL.revokeObjectURL(url);\n }\n}\n\nconst workLogManager = new WorkLogManager();\n\n---end---"
+ }
+ ],
+ "stop_reason": "end_turn",
+ "stop_sequence": null,
+ "usage": {
+ "input_tokens": 1193,
+ "cache_creation_input_tokens": 0,
+ "cache_read_input_tokens": 0,
+ "output_tokens": 3200
+ }
+}
\ No newline at end of file
diff --git a/readme.scroll b/readme.scroll
new file mode 100644
index 0000000..b1de630
--- /dev/null
+++ b/readme.scroll
@@ -0,0 +1,2 @@
+# worklog4.scroll.pub
+Website generated by Claude from prompt: 记录工作日志: 用户可以随时记录自己的工作内容。 输入框允许用户写入详细的工作日志,支持多行文本编辑。 日志的内容包括工作事项、任务进度、问题记录等。 日志分类: 用户可以为每条日志指定一个分类,帮助整理和区分日志的内容(例如:项目进度、问题记录、日常事务等)。 支持自定义分类,方便用户根据个人需求分类日志。 日志标签: 用户可以为日志添加标签,帮助更高效地进行检索和归类。 标签可按需要自定义,用于标注关键字或重要事项。 记录日期: 每条日志自动记录当前日期和时间,用户也可以手动修改日期,以便清晰了解每条日志的时间。 查看日志列表: 显示所有已记录的日志,并按日期或分类排序。 用户可以在列表中查看简短的日志摘要。 日志搜索: 提供搜索功能,允许用户通过关键词查找特定日志。 支持按日期或分类过滤日志,帮助快速定位所需内容。 编辑日志: 用户可以在任何时候编辑已经记录的日志内容。 编辑时,用户可以修改文本、日期、分类和标签。 删除日志: 用户可以删除日志条目,删除前会弹出确认提示,以避免误操作。 删除操作会立即更新本地存储,确保数据同步。 日志排序: 提供按日期排序的选项,可以选择查看最新的日志或最旧的日志。 日志按日期和分类的排序功能帮助用户更有序地查看日志内容。 本地存储: 所有日志数据保存在本地浏览器的 localStorage 中,数据不会丢失,页面刷新或浏览器关闭后仍能恢复。 通过 localStorage 实现日志数据的持久化存储,确保用户的数据安全可靠。 简单的用户交互: 所有操作(如记录、编辑、删除、搜索)都通过简单的按钮和输入框完成。 用户界面简洁、易用,无需注册或登录,任何人都可以随时记录和管理日志。 日志导出(可选功能): 提供导出日志为文本文件或CSV格式的功能,便于用户备份或分享日志。 提醒功能(可选功能): 可实现一个简单的提醒功能,提醒用户记录日志或查看某些重要的工作事项。 这个工作日志工具集成了记录、分类、编辑、删除、搜索等多种功能,旨在帮助用户高效地管理和查看自己的工作日志,积累经验与知识。并且所有功能均通过原生HTML、CSS、JavaScript实现,确保其简单、轻量,并适用于单机使用。
\ No newline at end of file
diff --git a/script.js b/script.js
new file mode 100644
index 0000000..d5879c9
--- /dev/null
+++ b/script.js
@@ -0,0 +1,160 @@
+class WorkLogManager {
+ constructor() {
+ this.logs = JSON.parse(localStorage.getItem('workLogs')) || [];
+ this.categories = new Set(this.logs.map(log => log.category));
+ this.setupEventListeners();
+ this.updateCategoryList();
+ this.renderLogs();
+ }
+
+ setupEventListeners() {
+ document.getElementById('newLogBtn').addEventListener('click', () => {
+ document.getElementById('logForm').classList.remove('hidden');
+ document.getElementById('logDate').value = new Date().toISOString().slice(0, 16);
+ });
+
+ document.getElementById('workLogForm').addEventListener('submit', (e) => {
+ e.preventDefault();
+ this.saveLog();
+ });
+
+ document.getElementById('cancelBtn').addEventListener('click', () => {
+ document.getElementById('logForm').classList.add('hidden');
+ });
+
+ document.getElementById('searchInput').addEventListener('input', () => this.filterLogs());
+ document.getElementById('filterCategory').addEventListener('change', () => this.filterLogs());
+ document.getElementById('sortDateBtn').addEventListener('click', () => this.toggleSort());
+ document.getElementById('exportBtn').addEventListener('click', () => this.exportLogs());
+ }
+
+ saveLog() {
+ const logData = {
+ id: Date.now(),
+ date: document.getElementById('logDate').value,
+ category: document.getElementById('logCategory').value,
+ tags: document.getElementById('logTags').value.split(',').map(tag => tag.trim()).filter(tag => tag),
+ content: document.getElementById('logContent').value
+ };
+
+ this.logs.unshift(logData);
+ this.updateLocalStorage();
+ this.categories.add(logData.category);
+ this.updateCategoryList();
+ this.renderLogs();
+ document.getElementById('workLogForm').reset();
+ document.getElementById('logForm').classList.add('hidden');
+ }
+
+ updateLocalStorage() {
+ localStorage.setItem('workLogs', JSON.stringify(this.logs));
+ }
+
+ updateCategoryList() {
+ const categorySelect = document.getElementById('filterCategory');
+ const categoryDatalist = document.getElementById('categories');
+
+ categorySelect.innerHTML = '<option value="">All Categories</option>';
+ categoryDatalist.innerHTML = '';
+
+ this.categories.forEach(category => {
+ if (category) {
+ categorySelect.innerHTML += `<option value="${category}">${category}</option>`;
+ categoryDatalist.innerHTML += `<option value="${category}">`;
+ }
+ });
+ }
+
+ renderLogs() {
+ const logEntries = document.getElementById('logEntries');
+ logEntries.innerHTML = '';
+
+ this.logs.forEach(log => {
+ const logElement = document.createElement('div');
+ logElement.className = 'log-entry';
+ logElement.innerHTML = `
+ <div class="log-header">
+ <div>
+ <strong>${new Date(log.date).toLocaleString()}</strong>
+ ${log.category ? `<span class="tag">${log.category}</span>` : ''}
+ </div>
+ <div>
+ <button onclick="workLogManager.editLog(${log.id})">Edit</button>
+ <button onclick="workLogManager.deleteLog(${log.id})">Delete</button>
+ </div>
+ </div>
+ <div class="log-tags">
+ ${log.tags.map(tag => `<span class="tag">${tag}</span>`).join('')}
+ </div>
+ <div class="log-content">${log.content.replace(/\n/g, '<br>')}</div>
+ `;
+ logEntries.appendChild(logElement);
+ });
+ }
+
+ editLog(id) {
+ const log = this.logs.find(log => log.id === id);
+ if (log) {
+ document.getElementById('logDate').value = log.date;
+ document.getElementById('logCategory').value = log.category;
+ document.getElementById('logTags').value = log.tags.join(', ');
+ document.getElementById('logContent').value = log.content;
+ document.getElementById('logForm').classList.remove('hidden');
+ this.deleteLog(id);
+ }
+ }
+
+ deleteLog(id) {
+ if (confirm('Are you sure you want to delete this log?')) {
+ this.logs = this.logs.filter(log => log.id !== id);
+ this.updateLocalStorage();
+ this.renderLogs();
+ }
+ }
+
+ filterLogs() {
+ const searchTerm = document.getElementById('searchInput').value.toLowerCase();
+ const categoryFilter = document.getElementById('filterCategory').value;
+
+ const filtered = this.logs.filter(log => {
+ const matchesSearch = log.content.toLowerCase().includes(searchTerm) ||
+ log.tags.some(tag => tag.toLowerCase().includes(searchTerm));
+ const matchesCategory = !categoryFilter || log.category === categoryFilter;
+ return matchesSearch && matchesCategory;
+ });
+
+ this.renderFilteredLogs(filtered);
+ }
+
+ renderFilteredLogs(filtered) {
+ const logEntries = document.getElementById('logEntries');
+ logEntries.innerHTML = '';
+ filtered.forEach(log => {
+ // Reuse the same rendering logic as in renderLogs()
+ const logElement = document.createElement('div');
+ logElement.className = 'log-entry';
+ // ... (same innerHTML content as in renderLogs)
+ logEntries.appendChild(logElement);
+ });
+ }
+
+ toggleSort() {
+ this.logs.reverse();
+ this.renderLogs();
+ }
+
+ exportLogs() {
+ const exportData = JSON.stringify(this.logs, null, 2);
+ const blob = new Blob([exportData], { type: 'application/json' });
+ const url = URL.createObjectURL(blob);
+ const a = document.createElement('a');
+ a.href = url;
+ a.download = `work-logs-${new Date().toISOString().slice(0,10)}.json`;
+ document.body.appendChild(a);
+ a.click();
+ document.body.removeChild(a);
+ URL.revokeObjectURL(url);
+ }
+}
+
+const workLogManager = new WorkLogManager();
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..07cb3ef
--- /dev/null
+++ b/style.css
@@ -0,0 +1,155 @@
+:root {
+ --primary-color: #2c3e50;
+ --secondary-color: #3498db;
+ --accent-color: #e74c3c;
+ --background-color: #f5f6fa;
+ --text-color: #2c3e50;
+ --border-radius: 8px;
+ --shadow: 0 2px 4px rgba(0,0,0,0.1);
+}
+
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+body {
+ font-family: 'Segoe UI', system-ui, sans-serif;
+ line-height: 1.6;
+ color: var(--text-color);
+ background: var(--background-color);
+}
+
+header {
+ background: var(--primary-color);
+ color: white;
+ padding: 1rem;
+ box-shadow: var(--shadow);
+}
+
+h1 {
+ font-size: 1.8rem;
+ margin-bottom: 1rem;
+}
+
+nav {
+ display: flex;
+ gap: 1rem;
+ flex-wrap: wrap;
+}
+
+.search-container {
+ display: flex;
+ gap: 0.5rem;
+ flex-grow: 1;
+}
+
+input, select, textarea {
+ padding: 0.5rem;
+ border: 2px solid #ddd;
+ border-radius: var(--border-radius);
+ font-size: 1rem;
+}
+
+button {
+ background: var(--secondary-color);
+ color: white;
+ border: none;
+ padding: 0.5rem 1rem;
+ border-radius: var(--border-radius);
+ cursor: pointer;
+ transition: transform 0.2s, background-color 0.2s;
+}
+
+button:hover {
+ background: #2980b9;
+ transform: translateY(-2px);
+}
+
+main {
+ max-width: 1200px;
+ margin: 2rem auto;
+ padding: 0 1rem;
+}
+
+.form-group {
+ margin-bottom: 1rem;
+}
+
+.form-group label {
+ display: block;
+ margin-bottom: 0.5rem;
+ font-weight: 500;
+}
+
+.form-group input,
+.form-group textarea {
+ width: 100%;
+}
+
+.log-entry {
+ background: white;
+ padding: 1rem;
+ margin-bottom: 1rem;
+ border-radius: var(--border-radius);
+ box-shadow: var(--shadow);
+ transition: transform 0.2s;
+}
+
+.log-entry:hover {
+ transform: translateY(-2px);
+}
+
+.log-header {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 0.5rem;
+}
+
+.log-tags {
+ display: flex;
+ gap: 0.5rem;
+ flex-wrap: wrap;
+ margin: 0.5rem 0;
+}
+
+.tag {
+ background: #e1e8ed;
+ padding: 0.2rem 0.5rem;
+ border-radius: 12px;
+ font-size: 0.9rem;
+}
+
+.hidden {
+ display: none;
+}
+
+.form-actions {
+ display: flex;
+ gap: 1rem;
+ justify-content: flex-end;
+}
+
+footer {
+ text-align: center;
+ padding: 2rem;
+ background: var(--primary-color);
+ color: white;
+ margin-top: 2rem;
+}
+
+@media (max-width: 768px) {
+ nav {
+ flex-direction: column;
+ }
+
+ .search-container {
+ flex-direction: column;
+ }
+
+ .log-header {
+ flex-direction: column;
+ gap: 0.5rem;
+ }
+}