diff --git a/docs/changelog.html b/docs/changelog.html new file mode 100644 index 0000000..53fc0cf --- /dev/null +++ b/docs/changelog.html @@ -0,0 +1,75 @@ + + +
+ + +正在加载版本信息...
+优雅的文本片段记录工具
+专为开发者打造,随时随地记录、整理和管理各种文本片段。
+多语言代码块支持,为30+种编程语言提供语法高亮
+内置Prettier支持,一键美化代码
+深色/浅色主题,支持完全自定义
+同时编辑多个文档
+将内容分割为独立的代码块,每个块可设置不同语言
+彩虹括号、VSCode风格搜索、颜色选择器、翻译工具等多种扩展
++function createDocument() { + const doc = new Document(); + + doc.addCodeBlock('javascript', ` + function greeting(name) { + return `Hello, ${name}!`; + } + + console.log(greeting('World')); + `); + + return doc; +}+
+// VoidRaft - An elegant text snippet recording tool +// Multi-language support | Code formatting | Custom themes +// A modern text editor designed for developers+
$1
');
+
+ // Inline code - `code`
+ markdown = markdown.replace(/`([^`]+)`/g, '$1
');
+
+ // Lists - * item
+ markdown = markdown.replace(/^\* (.*$)/gm, '');
+
+ // Line breaks - two spaces at end of line
+ markdown = markdown.replace(/ \n/g, '
');
+
+ return `
${markdown}
`; + } + + // Update translations when language changes + window.addEventListener('languageChanged', updateUI); + + // Initial UI update based on current language + updateUI(); + + /** + * Update UI elements with current language + */ + function updateUI() { + const lang = getCurrentLang(); + + // Update all i18n elements + document.querySelectorAll('[data-en][data-zh]').forEach(el => { + if (el.hasAttribute(`data-${lang}`)) { + el.textContent = el.getAttribute(`data-${lang}`); + } + }); + } +}); \ No newline at end of file diff --git a/docs/js/script.js b/docs/js/script.js new file mode 100644 index 0000000..a33994f --- /dev/null +++ b/docs/js/script.js @@ -0,0 +1,138 @@ +/** + * VoidRaft - Website Script + */ +document.addEventListener('DOMContentLoaded', () => { + // Initialize components + initThemeToggle(); + initLanguageToggle(); + initCardEffects(); + + // Console branding + console.log('%c VoidRaft', 'color: #ff006e; font-size: 20px; font-family: "Space Mono", monospace;'); + console.log('%c An elegant text snippet recording tool designed for developers.', 'color: #073B4C; font-family: "Space Mono", monospace;'); +}); + +/** + * Initialize theme toggle functionality + */ +function initThemeToggle() { + const themeToggle = document.getElementById('theme-toggle'); + if (!themeToggle) return; + + // Get initial theme from local storage or system preference + const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)'); + const savedTheme = localStorage.getItem('theme'); + const theme = savedTheme || (prefersDarkScheme.matches ? 'dark' : 'light'); + + // Apply initial theme + setTheme(theme); + + // Add click handler + themeToggle.addEventListener('click', () => { + document.body.classList.add('theme-transition'); + + const currentTheme = document.body.classList.contains('theme-dark') ? 'dark' : 'light'; + const newTheme = currentTheme === 'dark' ? 'light' : 'dark'; + + setTheme(newTheme); + localStorage.setItem('theme', newTheme); + + // Remove transition class after animation completes + setTimeout(() => document.body.classList.remove('theme-transition'), 300); + }); +} + +/** + * Set theme to dark or light + * @param {string} theme - 'dark' or 'light' + */ +function setTheme(theme) { + const isDark = theme === 'dark'; + + // Update body class + document.body.classList.toggle('theme-dark', isDark); + document.body.classList.toggle('theme-light', !isDark); + + // Update toggle icon + const themeToggle = document.getElementById('theme-toggle'); + if (themeToggle) { + const icon = themeToggle.querySelector('i'); + if (icon) { + icon.className = isDark ? 'fas fa-sun' : 'fas fa-moon'; + } + } +} + +/** + * Initialize language toggle functionality + */ +function initLanguageToggle() { + const langToggle = document.getElementById('lang-toggle'); + if (!langToggle) return; + + // Get initial language from local storage or browser preference + const savedLang = localStorage.getItem('lang'); + const userLang = navigator.language || navigator.userLanguage; + const defaultLang = userLang.includes('zh') ? 'zh' : 'en'; + const lang = savedLang || defaultLang; + + // Set current language and apply it + window.currentLang = lang; + setLanguage(lang); + + // Add click handler + langToggle.addEventListener('click', () => { + document.body.classList.add('lang-transition'); + + const newLang = window.currentLang === 'zh' ? 'en' : 'zh'; + setLanguage(newLang); + window.currentLang = newLang; + localStorage.setItem('lang', newLang); + + // Notify other components about language change + window.dispatchEvent(new CustomEvent('languageChanged', { detail: { lang: newLang } })); + + // Remove transition class after animation completes + setTimeout(() => document.body.classList.remove('lang-transition'), 300); + }); +} + +/** + * Set page language + * @param {string} lang - 'zh' or 'en' + */ +function setLanguage(lang) { + // Update all elements with data-zh and data-en attributes + document.querySelectorAll('[data-zh][data-en]').forEach(el => { + el.textContent = el.getAttribute(`data-${lang}`); + }); + + // Update HTML language attribute + document.documentElement.lang = lang === 'zh' ? 'zh-CN' : 'en'; + + // Update toggle button text + const langToggle = document.getElementById('lang-toggle'); + if (langToggle) { + const text = lang === 'zh' ? 'EN/中' : '中/EN'; + langToggle.innerHTML = ` ${text}`; + } +} + +/** + * Initialize card hover effects + */ +function initCardEffects() { + const cards = document.querySelectorAll('.feature-card'); + + cards.forEach(card => { + card.addEventListener('mouseenter', () => { + card.style.transform = 'translateY(-8px)'; + card.style.boxShadow = '7px 7px 0 var(--shadow-color)'; + }); + + card.addEventListener('mouseleave', () => { + card.style.transform = 'translateY(0)'; + card.style.boxShadow = '5px 5px 0 var(--shadow-color)'; + }); + }); +} \ No newline at end of file diff --git a/frontend/src/components/toolbar/DocumentSelector.vue b/frontend/src/components/toolbar/DocumentSelector.vue index 2381891..813affe 100644 --- a/frontend/src/components/toolbar/DocumentSelector.vue +++ b/frontend/src/components/toolbar/DocumentSelector.vue @@ -213,8 +213,29 @@ const handleDelete = async (doc: Document, event: Event) => { event.stopPropagation(); if (deleteConfirmId.value === doc.id) { - // 确认删除 + // 确认删除前检查文档是否在其他窗口打开 try { + const hasOpen = await windowStore.isDocumentWindowOpen(doc.id); + if (hasOpen) { + // 设置错误状态并启动定时器 + alreadyOpenDocId.value = doc.id; + + // 清除之前的定时器(如果存在) + if (errorMessageTimer.value) { + clearTimeout(errorMessageTimer.value); + } + + // 设置新的定时器,3秒后清除错误信息 + errorMessageTimer.value = window.setTimeout(() => { + alreadyOpenDocId.value = null; + errorMessageTimer.value = null; + }, 3000); + + // 取消删除确认状态 + deleteConfirmId.value = null; + return; + } + await documentStore.deleteDocument(doc.id); await documentStore.updateDocuments();