fix: Update entrypointsDir and manifest version in wxt.config.ts
feat: Update routing imports in options and sidepanel App components fix: Remove unused SquarePen icon import in Header component
This commit is contained in:
parent
93879fe5ab
commit
e4357677a7
@ -6,7 +6,6 @@ import {
|
|||||||
ComputerIcon,
|
ComputerIcon,
|
||||||
GithubIcon,
|
GithubIcon,
|
||||||
PanelLeftIcon,
|
PanelLeftIcon,
|
||||||
SquarePen,
|
|
||||||
ZapIcon
|
ZapIcon
|
||||||
} from "lucide-react"
|
} from "lucide-react"
|
||||||
import { useTranslation } from "react-i18next"
|
import { useTranslation } from "react-i18next"
|
||||||
|
267
src/entries-firefox/background.ts
Normal file
267
src/entries-firefox/background.ts
Normal file
@ -0,0 +1,267 @@
|
|||||||
|
import { getOllamaURL, isOllamaRunning } from "../services/ollama"
|
||||||
|
import { browser } from "wxt/browser"
|
||||||
|
import { clearBadge, streamDownload } from "@/utils/pull-ollama"
|
||||||
|
|
||||||
|
export default defineBackground({
|
||||||
|
main() {
|
||||||
|
let isCopilotRunning: boolean = false
|
||||||
|
browser.runtime.onMessage.addListener(async (message) => {
|
||||||
|
if (message.type === "sidepanel") {
|
||||||
|
await browser.sidebarAction.open()
|
||||||
|
} else if (message.type === "pull_model") {
|
||||||
|
const ollamaURL = await getOllamaURL()
|
||||||
|
|
||||||
|
const isRunning = await isOllamaRunning()
|
||||||
|
|
||||||
|
if (!isRunning) {
|
||||||
|
setBadgeText({ text: "E" })
|
||||||
|
setBadgeBackgroundColor({ color: "#FF0000" })
|
||||||
|
setTitle({ title: "Ollama is not running" })
|
||||||
|
setTimeout(() => {
|
||||||
|
clearBadge()
|
||||||
|
}, 5000)
|
||||||
|
}
|
||||||
|
|
||||||
|
await streamDownload(ollamaURL, message.modelName)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
browser.runtime.onConnect.addListener((port) => {
|
||||||
|
if (port.name === "pgCopilot") {
|
||||||
|
isCopilotRunning = true
|
||||||
|
port.onDisconnect.addListener(() => {
|
||||||
|
isCopilotRunning = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (import.meta.env.BROWSER === "chrome") {
|
||||||
|
chrome.action.onClicked.addListener((tab) => {
|
||||||
|
chrome.tabs.create({ url: chrome.runtime.getURL("/options.html") })
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
browser.browserAction.onClicked.addListener((tab) => {
|
||||||
|
console.log("browser.browserAction.onClicked.addListener")
|
||||||
|
browser.tabs.create({ url: browser.runtime.getURL("/options.html") })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const contextMenuTitle = {
|
||||||
|
webUi: browser.i18n.getMessage("openOptionToChat"),
|
||||||
|
sidePanel: browser.i18n.getMessage("openSidePanelToChat")
|
||||||
|
}
|
||||||
|
|
||||||
|
const contextMenuId = {
|
||||||
|
webUi: "open-web-ui-pa",
|
||||||
|
sidePanel: "open-side-panel-pa"
|
||||||
|
}
|
||||||
|
|
||||||
|
browser.contextMenus.create({
|
||||||
|
id: contextMenuId["sidePanel"],
|
||||||
|
title: contextMenuTitle["sidePanel"],
|
||||||
|
contexts: ["page", "selection"]
|
||||||
|
})
|
||||||
|
|
||||||
|
browser.contextMenus.create({
|
||||||
|
id: "summarize-pa",
|
||||||
|
title: browser.i18n.getMessage("contextSummarize"),
|
||||||
|
contexts: ["selection"]
|
||||||
|
})
|
||||||
|
|
||||||
|
browser.contextMenus.create({
|
||||||
|
id: "explain-pa",
|
||||||
|
title: browser.i18n.getMessage("contextExplain"),
|
||||||
|
contexts: ["selection"]
|
||||||
|
})
|
||||||
|
|
||||||
|
browser.contextMenus.create({
|
||||||
|
id: "rephrase-pa",
|
||||||
|
title: browser.i18n.getMessage("contextRephrase"),
|
||||||
|
contexts: ["selection"]
|
||||||
|
})
|
||||||
|
|
||||||
|
browser.contextMenus.create({
|
||||||
|
id: "translate-pg",
|
||||||
|
title: browser.i18n.getMessage("contextTranslate"),
|
||||||
|
contexts: ["selection"]
|
||||||
|
})
|
||||||
|
|
||||||
|
browser.contextMenus.create({
|
||||||
|
id: "custom-pg",
|
||||||
|
title: browser.i18n.getMessage("contextCustom"),
|
||||||
|
contexts: ["selection"]
|
||||||
|
})
|
||||||
|
|
||||||
|
if (import.meta.env.BROWSER === "chrome") {
|
||||||
|
browser.contextMenus.onClicked.addListener(async (info, tab) => {
|
||||||
|
if (info.menuItemId === "open-side-panel-pa") {
|
||||||
|
chrome.sidePanel.open({
|
||||||
|
tabId: tab.id!
|
||||||
|
})
|
||||||
|
} else if (info.menuItemId === "open-web-ui-pa") {
|
||||||
|
browser.tabs.create({
|
||||||
|
url: browser.runtime.getURL("/options.html")
|
||||||
|
})
|
||||||
|
} else if (info.menuItemId === "summarize-pa") {
|
||||||
|
chrome.sidePanel.open({
|
||||||
|
tabId: tab.id!
|
||||||
|
})
|
||||||
|
// this is a bad method hope somone can fix it :)
|
||||||
|
setTimeout(async () => {
|
||||||
|
await browser.runtime.sendMessage({
|
||||||
|
from: "background",
|
||||||
|
type: "summary",
|
||||||
|
text: info.selectionText
|
||||||
|
})
|
||||||
|
}, isCopilotRunning ? 0 : 5000)
|
||||||
|
|
||||||
|
} else if (info.menuItemId === "rephrase-pa") {
|
||||||
|
chrome.sidePanel.open({
|
||||||
|
tabId: tab.id!
|
||||||
|
})
|
||||||
|
setTimeout(async () => {
|
||||||
|
|
||||||
|
await browser.runtime.sendMessage({
|
||||||
|
type: "rephrase",
|
||||||
|
from: "background",
|
||||||
|
text: info.selectionText
|
||||||
|
})
|
||||||
|
}, isCopilotRunning ? 0 : 5000)
|
||||||
|
|
||||||
|
} else if (info.menuItemId === "translate-pg") {
|
||||||
|
chrome.sidePanel.open({
|
||||||
|
tabId: tab.id!
|
||||||
|
})
|
||||||
|
|
||||||
|
setTimeout(async () => {
|
||||||
|
await browser.runtime.sendMessage({
|
||||||
|
type: "translate",
|
||||||
|
from: "background",
|
||||||
|
text: info.selectionText
|
||||||
|
})
|
||||||
|
}, isCopilotRunning ? 0 : 5000)
|
||||||
|
} else if (info.menuItemId === "explain-pa") {
|
||||||
|
chrome.sidePanel.open({
|
||||||
|
tabId: tab.id!
|
||||||
|
})
|
||||||
|
|
||||||
|
setTimeout(async () => {
|
||||||
|
await browser.runtime.sendMessage({
|
||||||
|
type: "explain",
|
||||||
|
from: "background",
|
||||||
|
text: info.selectionText
|
||||||
|
})
|
||||||
|
}, isCopilotRunning ? 0 : 5000)
|
||||||
|
} else if (info.menuItemId === "custom-pg") {
|
||||||
|
chrome.sidePanel.open({
|
||||||
|
tabId: tab.id!
|
||||||
|
})
|
||||||
|
|
||||||
|
setTimeout(async () => {
|
||||||
|
await browser.runtime.sendMessage({
|
||||||
|
type: "custom",
|
||||||
|
from: "background",
|
||||||
|
text: info.selectionText
|
||||||
|
})
|
||||||
|
}, isCopilotRunning ? 0 : 5000)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
browser.commands.onCommand.addListener((command) => {
|
||||||
|
switch (command) {
|
||||||
|
case "execute_side_panel":
|
||||||
|
chrome.tabs.query(
|
||||||
|
{ active: true, currentWindow: true },
|
||||||
|
async (tabs) => {
|
||||||
|
const tab = tabs[0]
|
||||||
|
chrome.sidePanel.open({
|
||||||
|
tabId: tab.id!
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (import.meta.env.BROWSER === "firefox") {
|
||||||
|
browser.contextMenus.onClicked.addListener((info, tab) => {
|
||||||
|
if (info.menuItemId === "open-side-panel-pa") {
|
||||||
|
browser.sidebarAction.toggle()
|
||||||
|
} else if (info.menuItemId === "open-web-ui-pa") {
|
||||||
|
browser.tabs.create({
|
||||||
|
url: browser.runtime.getURL("/options.html")
|
||||||
|
})
|
||||||
|
} else if (info.menuItemId === "summarize-pa") {
|
||||||
|
if (!isCopilotRunning) {
|
||||||
|
browser.sidebarAction.toggle()
|
||||||
|
}
|
||||||
|
setTimeout(async () => {
|
||||||
|
await browser.runtime.sendMessage({
|
||||||
|
from: "background",
|
||||||
|
type: "summary",
|
||||||
|
text: info.selectionText
|
||||||
|
})
|
||||||
|
}, isCopilotRunning ? 0 : 5000)
|
||||||
|
} else if (info.menuItemId === "rephrase-pa") {
|
||||||
|
if (!isCopilotRunning) {
|
||||||
|
browser.sidebarAction.toggle()
|
||||||
|
}
|
||||||
|
setTimeout(async () => {
|
||||||
|
await browser.runtime.sendMessage({
|
||||||
|
type: "rephrase",
|
||||||
|
from: "background",
|
||||||
|
text: info.selectionText
|
||||||
|
})
|
||||||
|
}, isCopilotRunning ? 0 : 5000)
|
||||||
|
} else if (info.menuItemId === "translate-pg") {
|
||||||
|
if (!isCopilotRunning) {
|
||||||
|
browser.sidebarAction.toggle()
|
||||||
|
}
|
||||||
|
setTimeout(async () => {
|
||||||
|
await browser.runtime.sendMessage({
|
||||||
|
type: "translate",
|
||||||
|
from: "background",
|
||||||
|
text: info.selectionText
|
||||||
|
})
|
||||||
|
}, isCopilotRunning ? 0 : 5000)
|
||||||
|
} else if (info.menuItemId === "explain-pa") {
|
||||||
|
if (!isCopilotRunning) {
|
||||||
|
browser.sidebarAction.toggle()
|
||||||
|
}
|
||||||
|
setTimeout(async () => {
|
||||||
|
await browser.runtime.sendMessage({
|
||||||
|
type: "explain",
|
||||||
|
from: "background",
|
||||||
|
text: info.selectionText
|
||||||
|
})
|
||||||
|
}, isCopilotRunning ? 0 : 5000)
|
||||||
|
} else if (info.menuItemId === "custom-pg") {
|
||||||
|
if (!isCopilotRunning) {
|
||||||
|
browser.sidebarAction.toggle()
|
||||||
|
}
|
||||||
|
setTimeout(async () => {
|
||||||
|
await browser.runtime.sendMessage({
|
||||||
|
type: "custom",
|
||||||
|
from: "background",
|
||||||
|
text: info.selectionText
|
||||||
|
})
|
||||||
|
}, isCopilotRunning ? 0 : 5000)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
browser.commands.onCommand.addListener((command) => {
|
||||||
|
switch (command) {
|
||||||
|
case "execute_side_panel":
|
||||||
|
browser.sidebarAction.toggle()
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
persistent: true
|
||||||
|
})
|
95
src/entries-firefox/hf-pull.content.ts
Normal file
95
src/entries-firefox/hf-pull.content.ts
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
export default defineContentScript({
|
||||||
|
main(ctx) {
|
||||||
|
const downloadModel = async (modelName: string) => {
|
||||||
|
const ok = confirm(
|
||||||
|
`[Page Assist Extension] Do you want to pull the ${modelName} model? This has nothing to do with the huggingface.co website. The model will be pulled locally once you confirm. Make sure Ollama is running.`
|
||||||
|
)
|
||||||
|
if (ok) {
|
||||||
|
alert(
|
||||||
|
`[Page Assist Extension] Pulling ${modelName} model. For more details, check the extension icon.`
|
||||||
|
)
|
||||||
|
|
||||||
|
await browser.runtime.sendMessage({
|
||||||
|
type: "pull_model",
|
||||||
|
modelName
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const downloadSVG = `
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24" width="16" height="16">
|
||||||
|
<path d="M12 16l-6-6h4V4h4v6h4l-6 6z"/>
|
||||||
|
<path d="M4 20h16v-2H4v2z"/>
|
||||||
|
</svg>
|
||||||
|
`
|
||||||
|
|
||||||
|
const injectDownloadButton = (modal: HTMLElement) => {
|
||||||
|
const copyButton = modal.querySelector(
|
||||||
|
'button[title="Copy snippet to clipboard"]'
|
||||||
|
)
|
||||||
|
if (copyButton && !modal.querySelector(".pageassist-download-button")) {
|
||||||
|
const downloadButton = copyButton.cloneNode(true) as HTMLElement
|
||||||
|
downloadButton.classList.add("pageassist-download-button")
|
||||||
|
downloadButton.querySelector("svg")!.outerHTML = downloadSVG
|
||||||
|
downloadButton.querySelector("span")!.textContent =
|
||||||
|
"Pull from Page Assist"
|
||||||
|
downloadButton.addEventListener("click", async () => {
|
||||||
|
const preElement = modal.querySelector("pre")
|
||||||
|
if (preElement) {
|
||||||
|
let modelCommand = ""
|
||||||
|
preElement.childNodes.forEach((node) => {
|
||||||
|
if (node.nodeType === Node.TEXT_NODE) {
|
||||||
|
modelCommand += node.textContent
|
||||||
|
} else if (node instanceof HTMLSelectElement) {
|
||||||
|
modelCommand += node.value
|
||||||
|
} else if (node instanceof HTMLElement) {
|
||||||
|
const selectElement = node.querySelector(
|
||||||
|
"select"
|
||||||
|
) as HTMLSelectElement
|
||||||
|
if (selectElement) {
|
||||||
|
modelCommand += selectElement.value
|
||||||
|
} else {
|
||||||
|
modelCommand += node.textContent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
modelCommand = modelCommand.trim()
|
||||||
|
|
||||||
|
await downloadModel(
|
||||||
|
modelCommand
|
||||||
|
?.replaceAll("ollama run", "")
|
||||||
|
?.replaceAll("ollama pull", "")
|
||||||
|
?.trim()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const buttonContainer = document.createElement('div')
|
||||||
|
buttonContainer.classList.add("mb-3")
|
||||||
|
buttonContainer.style.display = 'flex'
|
||||||
|
buttonContainer.style.justifyContent = 'flex-end'
|
||||||
|
buttonContainer.appendChild(downloadButton)
|
||||||
|
modal.querySelector("pre")!.insertAdjacentElement("afterend", buttonContainer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const observer = new MutationObserver((mutations) => {
|
||||||
|
for (const mutation of mutations) {
|
||||||
|
mutation.addedNodes.forEach((node) => {
|
||||||
|
if (node instanceof HTMLElement) {
|
||||||
|
const modal = node.querySelector(".shadow-alternate") as HTMLElement
|
||||||
|
if (modal) {
|
||||||
|
injectDownloadButton(modal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
observer.observe(document.body, { childList: true, subtree: true })
|
||||||
|
},
|
||||||
|
allFrames: true,
|
||||||
|
matches: ["*://huggingface.co/*"]
|
||||||
|
})
|
57
src/entries-firefox/ollama-pull.content.ts
Normal file
57
src/entries-firefox/ollama-pull.content.ts
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
export default defineContentScript({
|
||||||
|
main(ctx) {
|
||||||
|
const downloadModel = async (modelName: string) => {
|
||||||
|
const ok = confirm(
|
||||||
|
`[Page Assist Extension] Do you want to pull ${modelName} model? This has nothing to do with Ollama.com website. The model will be pulled locally once you confirm.`
|
||||||
|
)
|
||||||
|
if (ok) {
|
||||||
|
alert(
|
||||||
|
`[Page Assist Extension] Pulling ${modelName} model. For more details, check the extension icon.`
|
||||||
|
)
|
||||||
|
|
||||||
|
await browser.runtime.sendMessage({
|
||||||
|
type: "pull_model",
|
||||||
|
modelName
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const downloadSVG = `<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="h-5 w-5 pageasssist-icon">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3" />
|
||||||
|
</svg>
|
||||||
|
`
|
||||||
|
const codeDiv = document.querySelectorAll("div.language-none")
|
||||||
|
|
||||||
|
for (let i = 0; i < codeDiv.length; i++) {
|
||||||
|
const button = codeDiv[i].querySelector("button")
|
||||||
|
const command = codeDiv[i].querySelector("input")
|
||||||
|
if (button && command) {
|
||||||
|
const newButton = document.createElement("button")
|
||||||
|
newButton.innerHTML = downloadSVG
|
||||||
|
newButton.className = `border-l ${button.className}`
|
||||||
|
newButton.id = `download-${i}-pageassist`
|
||||||
|
const modelName = command?.value
|
||||||
|
.replace("ollama run", "")
|
||||||
|
.replace("ollama pull", "")
|
||||||
|
.trim()
|
||||||
|
newButton.addEventListener("click", () => {
|
||||||
|
downloadModel(modelName)
|
||||||
|
})
|
||||||
|
|
||||||
|
const span = document.createElement("span")
|
||||||
|
span.title = "Download model via Page Assist"
|
||||||
|
span.appendChild(newButton)
|
||||||
|
|
||||||
|
if (button.parentNode) {
|
||||||
|
button.parentNode.appendChild(span)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
allFrames: true,
|
||||||
|
matches: ["*://ollama.com/*"],
|
||||||
|
|
||||||
|
})
|
57
src/entries-firefox/options/App.tsx
Normal file
57
src/entries-firefox/options/App.tsx
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
|
||||||
|
import { MemoryRouter } from "react-router-dom"
|
||||||
|
import { useEffect, useState } from "react"
|
||||||
|
const queryClient = new QueryClient()
|
||||||
|
import { ConfigProvider, Empty, theme } from "antd"
|
||||||
|
import { StyleProvider } from "@ant-design/cssinjs"
|
||||||
|
import { useDarkMode } from "~/hooks/useDarkmode"
|
||||||
|
import { OptionRouting } from "@/routes/firefox-route"
|
||||||
|
import "~/i18n"
|
||||||
|
import { useTranslation } from "react-i18next"
|
||||||
|
import { PageAssistProvider } from "@/components/Common/PageAssistProvider"
|
||||||
|
|
||||||
|
function IndexOption() {
|
||||||
|
const { mode } = useDarkMode()
|
||||||
|
const { t, i18n } = useTranslation()
|
||||||
|
const [direction, setDirection] = useState<"ltr" | "rtl">("ltr")
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (i18n.resolvedLanguage) {
|
||||||
|
document.documentElement.lang = i18n.resolvedLanguage
|
||||||
|
document.documentElement.dir = i18n.dir(i18n.resolvedLanguage)
|
||||||
|
setDirection(i18n.dir(i18n.resolvedLanguage))
|
||||||
|
}
|
||||||
|
}, [i18n, i18n.resolvedLanguage])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MemoryRouter>
|
||||||
|
<ConfigProvider
|
||||||
|
theme={{
|
||||||
|
algorithm:
|
||||||
|
mode === "dark" ? theme.darkAlgorithm : theme.defaultAlgorithm,
|
||||||
|
token: {
|
||||||
|
fontFamily: "Arimo"
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
renderEmpty={() => (
|
||||||
|
<Empty
|
||||||
|
imageStyle={{
|
||||||
|
height: 60
|
||||||
|
}}
|
||||||
|
description={t("common:noData")}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
direction={direction}>
|
||||||
|
<StyleProvider hashPriority="high">
|
||||||
|
<QueryClientProvider client={queryClient}>
|
||||||
|
<PageAssistProvider>
|
||||||
|
<OptionRouting />
|
||||||
|
</PageAssistProvider>
|
||||||
|
</QueryClientProvider>
|
||||||
|
</StyleProvider>
|
||||||
|
</ConfigProvider>
|
||||||
|
</MemoryRouter>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default IndexOption
|
15
src/entries-firefox/options/index.html
Normal file
15
src/entries-firefox/options/index.html
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Page Assist - A Web UI for Local AI Models</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="manifest.type" content="browser_action" />
|
||||||
|
<meta name="manifest.browser_style" content="false" />
|
||||||
|
<link href="~/assets/tailwind.css" rel="stylesheet" />
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
</head>
|
||||||
|
<body class="bg-white dark:bg-[#171717]">
|
||||||
|
<div id="root"></div>
|
||||||
|
<script type="module" src="./main.tsx"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
10
src/entries-firefox/options/main.tsx
Normal file
10
src/entries-firefox/options/main.tsx
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom/client';
|
||||||
|
import IndexOption from './App';
|
||||||
|
|
||||||
|
|
||||||
|
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||||
|
<React.StrictMode>
|
||||||
|
<IndexOption />
|
||||||
|
</React.StrictMode>,
|
||||||
|
);
|
54
src/entries-firefox/sidepanel/App.tsx
Normal file
54
src/entries-firefox/sidepanel/App.tsx
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
|
||||||
|
import { MemoryRouter } from "react-router-dom"
|
||||||
|
import { useEffect } from "react"
|
||||||
|
import { SidepanelRouting } from "@/routes/firefox-route"
|
||||||
|
const queryClient = new QueryClient()
|
||||||
|
import { ConfigProvider, Empty, theme } from "antd"
|
||||||
|
import { StyleProvider } from "@ant-design/cssinjs"
|
||||||
|
import { useDarkMode } from "~/hooks/useDarkmode"
|
||||||
|
import "~/i18n"
|
||||||
|
import { useTranslation } from "react-i18next"
|
||||||
|
import { PageAssistProvider } from "@/components/Common/PageAssistProvider"
|
||||||
|
|
||||||
|
function IndexSidepanel() {
|
||||||
|
const { mode } = useDarkMode()
|
||||||
|
const { t, i18n } = useTranslation()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (i18n.resolvedLanguage) {
|
||||||
|
document.documentElement.lang = i18n.resolvedLanguage;
|
||||||
|
document.documentElement.dir = i18n.dir(i18n.resolvedLanguage);
|
||||||
|
}
|
||||||
|
}, [i18n, i18n.resolvedLanguage]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MemoryRouter>
|
||||||
|
<ConfigProvider
|
||||||
|
theme={{
|
||||||
|
algorithm:
|
||||||
|
mode === "dark" ? theme.darkAlgorithm : theme.defaultAlgorithm,
|
||||||
|
token: {
|
||||||
|
fontFamily: "Arimo"
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
renderEmpty={() => (
|
||||||
|
<Empty
|
||||||
|
imageStyle={{
|
||||||
|
height: 60
|
||||||
|
}}
|
||||||
|
description={t("common:noData")}
|
||||||
|
/>
|
||||||
|
)}>
|
||||||
|
<StyleProvider hashPriority="high">
|
||||||
|
<QueryClientProvider client={queryClient}>
|
||||||
|
<PageAssistProvider>
|
||||||
|
<SidepanelRouting />
|
||||||
|
</PageAssistProvider>
|
||||||
|
</QueryClientProvider>
|
||||||
|
</StyleProvider>
|
||||||
|
</ConfigProvider>
|
||||||
|
</MemoryRouter>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default IndexSidepanel
|
16
src/entries-firefox/sidepanel/index.html
Normal file
16
src/entries-firefox/sidepanel/index.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Page Assist - A Web UI for Local AI Models</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="manifest.type" content="browser_action" />
|
||||||
|
<meta name="manifest.open_at_install" content="false" />
|
||||||
|
<meta name="manifest.browser_style" content="false" />
|
||||||
|
<link href="~/assets/tailwind.css" rel="stylesheet" />
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
</head>
|
||||||
|
<body class="bg-white dark:bg-[#171717]">
|
||||||
|
<div id="root"></div>
|
||||||
|
<script type="module" src="./main.tsx"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
9
src/entries-firefox/sidepanel/main.tsx
Normal file
9
src/entries-firefox/sidepanel/main.tsx
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import React from "react"
|
||||||
|
import ReactDOM from "react-dom/client"
|
||||||
|
import IndexSidepanel from "./App"
|
||||||
|
|
||||||
|
ReactDOM.createRoot(document.getElementById("root")!).render(
|
||||||
|
<React.StrictMode>
|
||||||
|
<IndexSidepanel />
|
||||||
|
</React.StrictMode>
|
||||||
|
)
|
@ -5,7 +5,7 @@ const queryClient = new QueryClient()
|
|||||||
import { ConfigProvider, Empty, theme } from "antd"
|
import { ConfigProvider, Empty, theme } from "antd"
|
||||||
import { StyleProvider } from "@ant-design/cssinjs"
|
import { StyleProvider } from "@ant-design/cssinjs"
|
||||||
import { useDarkMode } from "~/hooks/useDarkmode"
|
import { useDarkMode } from "~/hooks/useDarkmode"
|
||||||
import { OptionRouting } from "~/routes"
|
import { OptionRouting } from "@/routes/chrome-route"
|
||||||
import "~/i18n"
|
import "~/i18n"
|
||||||
import { useTranslation } from "react-i18next"
|
import { useTranslation } from "react-i18next"
|
||||||
import { PageAssistProvider } from "@/components/Common/PageAssistProvider"
|
import { PageAssistProvider } from "@/components/Common/PageAssistProvider"
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
|
||||||
import { MemoryRouter } from "react-router-dom"
|
import { MemoryRouter } from "react-router-dom"
|
||||||
import { useEffect } from "react"
|
import { useEffect } from "react"
|
||||||
import { SidepanelRouting } from "~/routes"
|
import { SidepanelRouting } from "@/routes/chrome-route"
|
||||||
const queryClient = new QueryClient()
|
const queryClient = new QueryClient()
|
||||||
import { ConfigProvider, Empty, theme } from "antd"
|
import { ConfigProvider, Empty, theme } from "antd"
|
||||||
import { StyleProvider } from "@ant-design/cssinjs"
|
import { StyleProvider } from "@ant-design/cssinjs"
|
||||||
|
28
src/routes/chrome-route.tsx
Normal file
28
src/routes/chrome-route.tsx
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { Suspense } from "react"
|
||||||
|
import { useDarkMode } from "~/hooks/useDarkmode"
|
||||||
|
import { OptionRoutingChrome, SidepanelRoutingChrome } from "./chrome"
|
||||||
|
import { PageAssistLoader } from "@/components/Common/PageAssistLoader"
|
||||||
|
|
||||||
|
export const OptionRouting = () => {
|
||||||
|
const { mode } = useDarkMode()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={`${mode === "dark" ? "dark" : "light"} arimo`}>
|
||||||
|
<Suspense fallback={<PageAssistLoader />}>
|
||||||
|
<OptionRoutingChrome />
|
||||||
|
</Suspense>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SidepanelRouting = () => {
|
||||||
|
const { mode } = useDarkMode()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={`${mode === "dark" ? "dark" : "light"} arimo`}>
|
||||||
|
<Suspense fallback={<PageAssistLoader />}>
|
||||||
|
<SidepanelRoutingChrome />
|
||||||
|
</Suspense>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -1,22 +1,16 @@
|
|||||||
import { Suspense } from "react"
|
import { Suspense } from "react"
|
||||||
import { useTranslation } from "react-i18next"
|
|
||||||
import { useDarkMode } from "~/hooks/useDarkmode"
|
import { useDarkMode } from "~/hooks/useDarkmode"
|
||||||
import { OptionRoutingChrome, SidepanelRoutingChrome } from "./chrome"
|
|
||||||
import { OptionRoutingFirefox, SidepanelRoutingFirefox } from "./firefox"
|
import { OptionRoutingFirefox, SidepanelRoutingFirefox } from "./firefox"
|
||||||
import { PageAssistLoader } from "@/components/Common/PageAssistLoader"
|
import { PageAssistLoader } from "@/components/Common/PageAssistLoader"
|
||||||
|
|
||||||
export const OptionRouting = () => {
|
export const OptionRouting = () => {
|
||||||
const { mode } = useDarkMode()
|
const { mode } = useDarkMode()
|
||||||
const { i18n } = useTranslation()
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`${mode === "dark" ? "dark" : "light"} arimo`}>
|
<div className={`${mode === "dark" ? "dark" : "light"} arimo`}>
|
||||||
<Suspense fallback={<PageAssistLoader />}>
|
<Suspense fallback={<PageAssistLoader />}>
|
||||||
{import.meta.env.BROWSER === "chrome" ? (
|
|
||||||
<OptionRoutingChrome />
|
|
||||||
) : (
|
|
||||||
<OptionRoutingFirefox />
|
<OptionRoutingFirefox />
|
||||||
)}
|
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@ -24,16 +18,12 @@ export const OptionRouting = () => {
|
|||||||
|
|
||||||
export const SidepanelRouting = () => {
|
export const SidepanelRouting = () => {
|
||||||
const { mode } = useDarkMode()
|
const { mode } = useDarkMode()
|
||||||
const { i18n } = useTranslation()
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`${mode === "dark" ? "dark" : "light"} arimo`}>
|
<div className={`${mode === "dark" ? "dark" : "light"} arimo`}>
|
||||||
<Suspense fallback={<PageAssistLoader />}>
|
<Suspense fallback={<PageAssistLoader />}>
|
||||||
{import.meta.env.BROWSER === "chrome" ? (
|
|
||||||
<SidepanelRoutingChrome />
|
|
||||||
) : (
|
|
||||||
<SidepanelRoutingFirefox />
|
<SidepanelRoutingFirefox />
|
||||||
)}
|
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
@ -45,12 +45,15 @@ export default defineConfig({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
entrypointsDir: "entries",
|
entrypointsDir:
|
||||||
|
process.env.TARGET === "firefox" ?
|
||||||
|
"entries-firefox" :
|
||||||
|
"entries",
|
||||||
srcDir: "src",
|
srcDir: "src",
|
||||||
outDir: "build",
|
outDir: "build",
|
||||||
|
|
||||||
manifest: {
|
manifest: {
|
||||||
version: "1.3.9",
|
version: "1.3.10",
|
||||||
name:
|
name:
|
||||||
process.env.TARGET === "firefox"
|
process.env.TARGET === "firefox"
|
||||||
? "Page Assist - A Web UI for Local AI Models"
|
? "Page Assist - A Web UI for Local AI Models"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user