diff --git a/package-lock.json b/package-lock.json index 73da11b..8e8acb4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,8 +8,11 @@ "name": "melodymuse", "version": "0.2.0", "dependencies": { + "@fortawesome/fontawesome-svg-core": "^7.2.0", + "@fortawesome/free-brands-svg-icons": "^7.2.0", + "@fortawesome/free-solid-svg-icons": "^7.2.0", + "@fortawesome/react-fontawesome": "^3.3.1", "jszip": "^3.10.1", - "lucide-react": "^0.451.0", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^6.26.2" @@ -711,6 +714,64 @@ "node": ">=12" } }, + "node_modules/@fortawesome/fontawesome-common-types": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-7.2.0.tgz", + "integrity": "sha512-IpR0bER9FY25p+e7BmFH25MZKEwFHTfRAfhOyJubgiDnoJNsSvJ7nigLraHtp4VOG/cy8D7uiV0dLkHOne5Fhw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/fontawesome-svg-core": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-7.2.0.tgz", + "integrity": "sha512-6639htZMjEkwskf3J+e6/iar+4cTNM9qhoWuRfj9F3eJD6r7iCzV1SWnQr2Mdv0QT0suuqU8BoJCZUyCtP9R4Q==", + "license": "MIT", + "dependencies": { + "@fortawesome/fontawesome-common-types": "7.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-brands-svg-icons": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-7.2.0.tgz", + "integrity": "sha512-VNG8xqOip1JuJcC3zsVsKRQ60oXG9+oYNDCosjoU/H9pgYmLTEwWw8pE0jhPz/JWdHeUuK6+NQ3qsM4gIbdbYQ==", + "license": "(CC-BY-4.0 AND MIT)", + "dependencies": { + "@fortawesome/fontawesome-common-types": "7.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-solid-svg-icons": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-7.2.0.tgz", + "integrity": "sha512-YTVITFGN0/24PxzXrwqCgnyd7njDuzp5ZvaCx5nq/jg55kUYd94Nj8UTchBdBofi/L0nwRfjGOg0E41d2u9T1w==", + "license": "(CC-BY-4.0 AND MIT)", + "dependencies": { + "@fortawesome/fontawesome-common-types": "7.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/react-fontawesome": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-3.3.1.tgz", + "integrity": "sha512-wGnAPhfzivDwBWYmEG8MSrEXPruoiMMo48NnsRkj1NZkoaawgOijPNAiSHKMYEoCsqTBSgLTzL6EqTTWGaUR4w==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "@fortawesome/fontawesome-svg-core": "~6 || ~7", + "react": "^18.0.0 || ^19.0.0" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", @@ -1966,15 +2027,6 @@ "yallist": "^3.0.2" } }, - "node_modules/lucide-react": { - "version": "0.451.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.451.0.tgz", - "integrity": "sha512-OwQ3uljZLp2cerj8sboy5rnhtGTCl9UCJIhT1J85/yOuGVlEH+xaUPR7tvNdddPvmV5M5VLdr7cQuWE3hzA4jw==", - "license": "ISC", - "peerDependencies": { - "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" - } - }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", diff --git a/package.json b/package.json index 642146c..860383c 100644 --- a/package.json +++ b/package.json @@ -13,8 +13,11 @@ "lint": "tsc -b --noEmit" }, "dependencies": { + "@fortawesome/fontawesome-svg-core": "^7.2.0", + "@fortawesome/free-brands-svg-icons": "^7.2.0", + "@fortawesome/free-solid-svg-icons": "^7.2.0", + "@fortawesome/react-fontawesome": "^3.3.1", "jszip": "^3.10.1", - "lucide-react": "^0.451.0", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^6.26.2" diff --git a/server.mjs b/server.mjs index 351e217..ff2a3ab 100644 --- a/server.mjs +++ b/server.mjs @@ -179,10 +179,14 @@ async function callProvider(messages, opts = {}, signal) { } const data = await resp.json(); - const content = data.choices?.[0]?.message?.content; + let content = data.choices?.[0]?.message?.content; if (typeof content !== 'string' || !content.trim()) { throw new Error('Provider response did not include a message'); } + + // Strip blocks generated by reasoning models (like MiniMax-M3 or DeepSeek-R1) + content = content.replace(/[\s\S]*?<\/think>\s*/gi, '').trim(); + return content; } diff --git a/src/App.tsx b/src/App.tsx index a0179bd..2b015b0 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -2,15 +2,21 @@ import { Route, Routes } from 'react-router-dom'; import { HomePage } from './pages/HomePage'; import { SettingsPage } from './pages/SettingsPage'; import { ToastProvider } from './lib/toast'; +import { I18nProvider } from './lib/i18n'; +import { ThemeProvider } from './lib/theme'; export default function App() { return ( - - - } /> - } /> - } /> - - + + + + + } /> + } /> + } /> + + + + ); } diff --git a/src/components/CopyButton.tsx b/src/components/CopyButton.tsx index c3b9229..c8f7ade 100644 --- a/src/components/CopyButton.tsx +++ b/src/components/CopyButton.tsx @@ -1,5 +1,6 @@ import { useState } from 'react'; -import { Check, Copy } from 'lucide-react'; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faCheck, faCopy } from "@fortawesome/free-solid-svg-icons"; interface CopyButtonProps { value: string; @@ -41,12 +42,12 @@ export function CopyButton({ value, label = 'Copy', className = '' }: CopyButton > {copied ? ( <> - + Copied! ) : ( <> - + {label} )} diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx index f11faac..0d04130 100644 --- a/src/components/Footer.tsx +++ b/src/components/Footer.tsx @@ -1,14 +1,13 @@ +import { useI18n } from "../lib/i18n"; + export function Footer() { + const { t } = useI18n(); return ( -