diff --git a/docs/README.md b/docs/README.md index ddb7208..1a1bcc7 100644 --- a/docs/README.md +++ b/docs/README.md @@ -25,7 +25,7 @@ Your web application, titled **"Unity Chat U1 6.6"**, provides an interactive ch - **Speech Recognition:** Users can dictate messages through voice input, which captures speech and translates it into textual inputs in real-time. - **Message Handling:** - - **Markdown Support:** AI-generated responses utilize Markdown, enhanced with syntax highlighting (via PrismJS) for clarity in code snippets. + - **Markdown Support:** AI-generated responses utilize Markdown, enhanced with syntax highlighting (via highlight.js) for clarity in code snippets. - **Image Embedding:** Automatically embeds images generated by Pollinations based on AI conversation content. - **Editing and Regeneration:** Users can edit their messages or regenerate AI responses conveniently from within the chat interface. @@ -88,7 +88,7 @@ Your web application, titled **"Unity Chat U1 6.6"**, provides an interactive ch --- ## **Technical Stack & Dependencies** -- **Frontend:** HTML, CSS, JavaScript, Bootstrap 5, Font Awesome, PrismJS, Marked.js +- **Frontend:** HTML, CSS, JavaScript, Bootstrap 5, Font Awesome, highlight.js, Marked.js - **Backend:** Node.js (Express), cors, fs for file operations - **Speech & Multimedia:** Web Speech API for speech synthesis and recognition - **Persistent Storage:** Local Storage and server-side JSON file storage (`userData.json`) diff --git a/index.html b/index.html index 98ae4c8..b33a062 100644 --- a/index.html +++ b/index.html @@ -6,7 +6,7 @@ - + @@ -466,14 +466,8 @@ }); } - - - - - - - - + + diff --git a/js/chat/chat-init.js b/js/chat/chat-init.js index 57b89a5..d82bcfb 100644 --- a/js/chat/chat-init.js +++ b/js/chat/chat-init.js @@ -13,10 +13,10 @@ document.addEventListener("DOMContentLoaded", () => { if (newTitle && newTitle !== currentSession.name) Storage.renameSession(currentSession.id, newTitle); } }; - const highlightAllCodeBlocks = () => { - if (!window.Prism) return; - chatBox.querySelectorAll("pre code").forEach(block => Prism.highlightElement(block)); - }; + const highlightAllCodeBlocks = () => { + if (!window.hljs) return; + chatBox.querySelectorAll("pre code").forEach(block => hljs.highlightElement(block)); + }; const appendMessage = ({ role, content, index, imageUrls = [], audioUrls = [] }) => { const container = document.createElement("div"); container.classList.add("message"); diff --git a/js/chat/chat-storage.js b/js/chat/chat-storage.js index 30c9d80..d72f5ec 100644 --- a/js/chat/chat-storage.js +++ b/js/chat/chat-storage.js @@ -25,15 +25,15 @@ document.addEventListener("DOMContentLoaded", () => { } } } - function highlightAllCodeBlocks() { - if (!window.Prism) { - return; - } - const codeBlocks = chatBox.querySelectorAll("pre code"); - codeBlocks.forEach((block) => { - Prism.highlightElement(block); - }); - } + function highlightAllCodeBlocks() { + if (!window.hljs) { + return; + } + const codeBlocks = chatBox.querySelectorAll("pre code"); + codeBlocks.forEach((block) => { + hljs.highlightElement(block); + }); + } function appendMessage({ role, content, index, imageUrls = [], audioUrls = [] }) { const container = document.createElement("div"); container.classList.add("message"); diff --git a/js/ui/ui.js b/js/ui/ui.js index aef62c3..846d68c 100644 --- a/js/ui/ui.js +++ b/js/ui/ui.js @@ -31,20 +31,27 @@ document.addEventListener("DOMContentLoaded", () => { const clearUserDataBtn = document.getElementById("clear-user-data-btn"); const toggleSimpleModeBtn = document.getElementById("toggle-simple-mode"); - let themeLinkElement = document.getElementById("theme-link"); - if (!themeLinkElement) { - themeLinkElement = document.createElement("link"); - themeLinkElement.id = "theme-link"; - themeLinkElement.rel = "stylesheet"; - document.head.appendChild(themeLinkElement); - } + let themeLinkElement = document.getElementById("theme-link"); + if (!themeLinkElement) { + themeLinkElement = document.createElement("link"); + themeLinkElement.id = "theme-link"; + themeLinkElement.rel = "stylesheet"; + document.head.appendChild(themeLinkElement); + } + let hljsThemeLink = document.getElementById("hljs-theme-link"); + if (!hljsThemeLink) { + hljsThemeLink = document.createElement("link"); + hljsThemeLink.id = "hljs-theme-link"; + hljsThemeLink.rel = "stylesheet"; + document.head.appendChild(hljsThemeLink); + } - const allThemes = [ - { value: "light", label: "Light", file: "themes/light.css" }, - { value: "dark", label: "Dark", file: "themes/dark.css" }, - { value: "hacker", label: "Hacker", file: "themes/hacker.css" }, - { value: "oled", label: "OLED Dark", file: "themes/oled.css" }, - { value: "subtle-light", label: "Subtle Light", file: "themes/subtle_light.css" }, + const allThemes = [ + { value: "light", label: "Light", file: "themes/light.css" }, + { value: "dark", label: "Dark", file: "themes/dark.css" }, + { value: "hacker", label: "Hacker", file: "themes/hacker.css" }, + { value: "oled", label: "OLED Dark", file: "themes/oled.css" }, + { value: "subtle-light", label: "Subtle Light", file: "themes/subtle_light.css" }, { value: "burple", label: "Burple", file: "themes/burple.css" }, { value: "pretty-pink", label: "Pretty Pink", file: "themes/pretty_pink.css" }, { value: "nord", label: "Nord", file: "themes/nord.css" }, @@ -61,9 +68,42 @@ document.addEventListener("DOMContentLoaded", () => { { value: "ocean-breeze", label: "Ocean Breeze", file: "themes/ocean_breeze.css" }, { value: "vintage-paper", label: "Vintage Paper", file: "themes/vintage_paper.css" }, { value: "honeycomb", label: "Honeycomb", file: "themes/honeycomb.css" }, - { value: "rainbow-throwup", label: "Rainbow Throwup", file: "themes/rainbow_throwup.css" }, - { value: "serenity", label: "Serenity", file: "themes/serenity.css" } - ]; + { value: "rainbow-throwup", label: "Rainbow Throwup", file: "themes/rainbow_throwup.css" }, + { value: "serenity", label: "Serenity", file: "themes/serenity.css" } + ]; + + const hljsThemeMap = { + light: "github", + dark: "github-dark", + hacker: "a11y-dark", + oled: "atom-one-dark", + "subtle-light": "atom-one-light", + burple: "atom-one-dark", + "pretty-pink": "github", + nord: "nord", + "solarized-light": "solarized-light", + "solarized-dark": "solarized-dark", + "gruvbox-light": "gruvbox-light", + "gruvbox-dark": "gruvbox-dark", + cyberpunk: "atom-one-dark", + dracula: "dracula", + monokai: "monokai", + "material-dark": "atom-one-dark", + "material-light": "atom-one-light", + "pastel-dream": "github", + "ocean-breeze": "github", + "vintage-paper": "github", + honeycomb: "github", + "rainbow-throwup": "github", + serenity: "atom-one-light" + }; + + const HLJS_BASE = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/"; + + function updateHighlightTheme(themeValue) { + const hlTheme = hljsThemeMap[themeValue] || "github-dark"; + hljsThemeLink.href = `${HLJS_BASE}${hlTheme}.min.css`; + } function populateThemeDropdowns() { themeSelect.innerHTML = ""; @@ -88,8 +128,9 @@ document.addEventListener("DOMContentLoaded", () => { const savedTheme = localStorage.getItem("selectedTheme") || "dark"; themeSelect.value = savedTheme; themeSelectSettings.value = savedTheme; - const found = allThemes.find(t => t.value === savedTheme); - themeLinkElement.href = found ? found.file : "themes/dark.css"; + const found = allThemes.find(t => t.value === savedTheme); + themeLinkElement.href = found ? found.file : "themes/dark.css"; + updateHighlightTheme(savedTheme); } loadUserTheme(); @@ -97,8 +138,9 @@ document.addEventListener("DOMContentLoaded", () => { localStorage.setItem("selectedTheme", newThemeValue); themeSelect.value = newThemeValue; themeSelectSettings.value = newThemeValue; - const found = allThemes.find(t => t.value === newThemeValue); - themeLinkElement.href = found ? found.file : ""; + const found = allThemes.find(t => t.value === newThemeValue); + themeLinkElement.href = found ? found.file : ""; + updateHighlightTheme(newThemeValue); } themeSelect.addEventListener("change", () => { diff --git a/package-lock.json b/package-lock.json index 1bf7421..c4a3179 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,9 +6,20 @@ "": { "name": "unity-chat", "devDependencies": { + "highlight.js": "^11.11.1", "marked": "^11.2.0" } }, + "node_modules/highlight.js": { + "version": "11.11.1", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz", + "integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/marked": { "version": "11.2.0", "resolved": "https://registry.npmjs.org/marked/-/marked-11.2.0.tgz", diff --git a/package.json b/package.json index 0b0fdb4..fc72598 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "test": "node tests/run-all.mjs" }, "devDependencies": { + "highlight.js": "^11.11.1", "marked": "^11.2.0" } } -