fix: Jan Quick Ask window capture input issues (#4758)
This commit is contained in:
parent
b4ba76aa71
commit
dda0feb548
@ -31,6 +31,7 @@ import { registerGlobalShortcuts } from './utils/shortcut'
|
|||||||
import { registerLogger } from './utils/logger'
|
import { registerLogger } from './utils/logger'
|
||||||
|
|
||||||
const preloadPath = join(__dirname, 'preload.js')
|
const preloadPath = join(__dirname, 'preload.js')
|
||||||
|
const preloadQuickAskPath = join(__dirname, 'preload.quickask.js')
|
||||||
const rendererPath = join(__dirname, '..', 'renderer')
|
const rendererPath = join(__dirname, '..', 'renderer')
|
||||||
const quickAskPath = join(rendererPath, 'search.html')
|
const quickAskPath = join(rendererPath, 'search.html')
|
||||||
const mainPath = join(rendererPath, 'index.html')
|
const mainPath = join(rendererPath, 'index.html')
|
||||||
@ -133,7 +134,7 @@ function createQuickAskWindow() {
|
|||||||
// Feature Toggle for Quick Ask
|
// Feature Toggle for Quick Ask
|
||||||
if (!getAppConfigurations().quick_ask) return
|
if (!getAppConfigurations().quick_ask) return
|
||||||
const startUrl = app.isPackaged ? `file://${quickAskPath}` : quickAskUrl
|
const startUrl = app.isPackaged ? `file://${quickAskPath}` : quickAskUrl
|
||||||
windowManager.createQuickAskWindow(preloadPath, startUrl)
|
windowManager.createQuickAskWindow(preloadQuickAskPath, startUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -13,10 +13,10 @@ export const quickAskWindowConfig: Electron.BrowserWindowConstructorOptions = {
|
|||||||
fullscreenable: false,
|
fullscreenable: false,
|
||||||
resizable: false,
|
resizable: false,
|
||||||
center: true,
|
center: true,
|
||||||
movable: false,
|
movable: true,
|
||||||
maximizable: false,
|
maximizable: false,
|
||||||
focusable: true,
|
focusable: true,
|
||||||
transparent: true,
|
transparent: false,
|
||||||
frame: false,
|
frame: false,
|
||||||
type: 'panel',
|
type: 'panel',
|
||||||
}
|
}
|
||||||
|
|||||||
@ -141,6 +141,9 @@ class WindowManager {
|
|||||||
return this._quickAskWindow?.isDestroyed() ?? true
|
return this._quickAskWindow?.isDestroyed() ?? true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expand the quick ask window
|
||||||
|
*/
|
||||||
expandQuickAskWindow(heightOffset: number): void {
|
expandQuickAskWindow(heightOffset: number): void {
|
||||||
const width = quickAskWindowConfig.width!
|
const width = quickAskWindowConfig.width!
|
||||||
const height = quickAskWindowConfig.height! + heightOffset
|
const height = quickAskWindowConfig.height! + heightOffset
|
||||||
@ -148,6 +151,9 @@ class WindowManager {
|
|||||||
this._quickAskWindow?.setSize(width, height, true)
|
this._quickAskWindow?.setSize(width, height, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the selected text to the quick ask window.
|
||||||
|
*/
|
||||||
sendQuickAskSelectedText(selectedText: string): void {
|
sendQuickAskSelectedText(selectedText: string): void {
|
||||||
this._quickAskWindow?.webContents.send(
|
this._quickAskWindow?.webContents.send(
|
||||||
AppEvent.onSelectedText,
|
AppEvent.onSelectedText,
|
||||||
@ -180,6 +186,9 @@ class WindowManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean up all windows.
|
||||||
|
*/
|
||||||
cleanUp(): void {
|
cleanUp(): void {
|
||||||
if (!this.mainWindow?.isDestroyed()) {
|
if (!this.mainWindow?.isDestroyed()) {
|
||||||
this.mainWindow?.close()
|
this.mainWindow?.close()
|
||||||
|
|||||||
32
electron/preload.quickask.ts
Normal file
32
electron/preload.quickask.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
* Exposes a set of APIs to the renderer process via the contextBridge object.
|
||||||
|
* @module preload
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { APIEvents, APIRoutes } from '@janhq/core/node'
|
||||||
|
import { contextBridge, ipcRenderer } from 'electron'
|
||||||
|
|
||||||
|
const interfaces: { [key: string]: (...args: any[]) => any } = {}
|
||||||
|
|
||||||
|
// Loop over each route in APIRoutes
|
||||||
|
APIRoutes.forEach((method) => {
|
||||||
|
// For each method, create a function on the interfaces object
|
||||||
|
// This function invokes the method on the ipcRenderer with any provided arguments
|
||||||
|
|
||||||
|
interfaces[method] = (...args: any[]) => ipcRenderer.invoke(method, ...args)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Loop over each method in APIEvents
|
||||||
|
APIEvents.forEach((method) => {
|
||||||
|
// For each method, create a function on the interfaces object
|
||||||
|
// This function sets up an event listener on the ipcRenderer for the method
|
||||||
|
// The handler for the event is provided as an argument to the function
|
||||||
|
interfaces[method] = (handler: any) => ipcRenderer.on(method, handler)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Expose the 'interfaces' object in the main world under the name 'electronAPI'
|
||||||
|
// This allows the renderer process to access these methods directly
|
||||||
|
contextBridge.exposeInMainWorld('electronAPI', {
|
||||||
|
...interfaces,
|
||||||
|
isQuickAsk: () => true,
|
||||||
|
})
|
||||||
@ -3,7 +3,7 @@
|
|||||||
* @module preload
|
* @module preload
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { APIEvents, APIRoutes, AppConfiguration, getAppConfigurations, updateAppConfiguration } from '@janhq/core/node'
|
import { APIEvents, APIRoutes, AppConfiguration } from '@janhq/core/node'
|
||||||
import { contextBridge, ipcRenderer } from 'electron'
|
import { contextBridge, ipcRenderer } from 'electron'
|
||||||
import { readdirSync } from 'fs'
|
import { readdirSync } from 'fs'
|
||||||
|
|
||||||
@ -15,7 +15,6 @@ APIRoutes.forEach((method) => {
|
|||||||
// This function invokes the method on the ipcRenderer with any provided arguments
|
// This function invokes the method on the ipcRenderer with any provided arguments
|
||||||
|
|
||||||
interfaces[method] = (...args: any[]) => ipcRenderer.invoke(method, ...args)
|
interfaces[method] = (...args: any[]) => ipcRenderer.invoke(method, ...args)
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// Loop over each method in APIEvents
|
// Loop over each method in APIEvents
|
||||||
@ -26,20 +25,21 @@ APIEvents.forEach((method) => {
|
|||||||
interfaces[method] = (handler: any) => ipcRenderer.on(method, handler)
|
interfaces[method] = (handler: any) => ipcRenderer.on(method, handler)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
interfaces['changeDataFolder'] = async (path) => {
|
||||||
interfaces['changeDataFolder'] = async path => {
|
const appConfiguration: AppConfiguration = await ipcRenderer.invoke(
|
||||||
const appConfiguration: AppConfiguration = await ipcRenderer.invoke('getAppConfigurations')
|
'getAppConfigurations'
|
||||||
|
)
|
||||||
const currentJanDataFolder = appConfiguration.data_folder
|
const currentJanDataFolder = appConfiguration.data_folder
|
||||||
appConfiguration.data_folder = path
|
appConfiguration.data_folder = path
|
||||||
const reflect = require('@alumna/reflect')
|
const reflect = require('@alumna/reflect')
|
||||||
const { err } = await reflect({
|
const { err } = await reflect({
|
||||||
src: currentJanDataFolder,
|
src: currentJanDataFolder,
|
||||||
dest: path,
|
dest: path,
|
||||||
recursive: true,
|
recursive: true,
|
||||||
delete: false,
|
delete: false,
|
||||||
overwrite: true,
|
overwrite: true,
|
||||||
errorOnExist: false,
|
errorOnExist: false,
|
||||||
})
|
})
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
throw err
|
throw err
|
||||||
@ -47,7 +47,7 @@ interfaces['changeDataFolder'] = async path => {
|
|||||||
await ipcRenderer.invoke('updateAppConfiguration', appConfiguration)
|
await ipcRenderer.invoke('updateAppConfiguration', appConfiguration)
|
||||||
}
|
}
|
||||||
|
|
||||||
interfaces['isDirectoryEmpty'] = async path => {
|
interfaces['isDirectoryEmpty'] = async (path) => {
|
||||||
const dirChildren = await readdirSync(path)
|
const dirChildren = await readdirSync(path)
|
||||||
return dirChildren.filter((x) => x !== '.DS_Store').length === 0
|
return dirChildren.filter((x) => x !== '.DS_Store').length === 0
|
||||||
}
|
}
|
||||||
@ -56,4 +56,5 @@ interfaces['isDirectoryEmpty'] = async path => {
|
|||||||
// This allows the renderer process to access these methods directly
|
// This allows the renderer process to access these methods directly
|
||||||
contextBridge.exposeInMainWorld('electronAPI', {
|
contextBridge.exposeInMainWorld('electronAPI', {
|
||||||
...interfaces,
|
...interfaces,
|
||||||
|
isQuickAsk: () => false,
|
||||||
})
|
})
|
||||||
|
|||||||
@ -13,10 +13,7 @@ export const metadata: Metadata = {
|
|||||||
export default function RootLayout({ children }: PropsWithChildren) {
|
export default function RootLayout({ children }: PropsWithChildren) {
|
||||||
return (
|
return (
|
||||||
<html lang="en" suppressHydrationWarning>
|
<html lang="en" suppressHydrationWarning>
|
||||||
<body className="h-screen font-sans text-sm antialiased">
|
<body className="h-screen font-sans text-sm antialiased">{children}</body>
|
||||||
<div className="dragable-bar" />
|
|
||||||
{children}
|
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -66,7 +66,7 @@ const UserInput = () => {
|
|||||||
<LogoMark width={28} height={28} className="mx-auto" />
|
<LogoMark width={28} height={28} className="mx-auto" />
|
||||||
<input
|
<input
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
className="flex-1 bg-transparent font-bold focus:outline-none"
|
className="flex-1 bg-transparent font-bold text-[hsla(var(--text-primary))] focus:outline-none"
|
||||||
type="text"
|
type="text"
|
||||||
value={inputValue}
|
value={inputValue}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
|
|||||||
@ -8,9 +8,6 @@ import { useSetAtom } from 'jotai'
|
|||||||
|
|
||||||
import ClipboardListener from '@/containers/Providers/ClipboardListener'
|
import ClipboardListener from '@/containers/Providers/ClipboardListener'
|
||||||
|
|
||||||
import JotaiWrapper from '@/containers/Providers/Jotai'
|
|
||||||
import ThemeWrapper from '@/containers/Providers/Theme'
|
|
||||||
|
|
||||||
import { useLoadTheme } from '@/hooks/useLoadTheme'
|
import { useLoadTheme } from '@/hooks/useLoadTheme'
|
||||||
|
|
||||||
import { setupCoreServices } from '@/services/coreService'
|
import { setupCoreServices } from '@/services/coreService'
|
||||||
@ -48,15 +45,9 @@ export default function RootLayout() {
|
|||||||
useLoadTheme()
|
useLoadTheme()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<html lang="en" suppressHydrationWarning>
|
<>
|
||||||
<body className="font-sans antialiased">
|
<ClipboardListener />
|
||||||
<JotaiWrapper>
|
<Search />
|
||||||
<ThemeWrapper>
|
</>
|
||||||
<ClipboardListener />
|
|
||||||
<Search />
|
|
||||||
</ThemeWrapper>
|
|
||||||
</JotaiWrapper>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import UserInput from './UserInput'
|
|||||||
const Search = () => {
|
const Search = () => {
|
||||||
return (
|
return (
|
||||||
<div className="h-screen w-screen overflow-hidden bg-[hsla(var(--app-bg))]">
|
<div className="h-screen w-screen overflow-hidden bg-[hsla(var(--app-bg))]">
|
||||||
|
<div className={'draggable-bar h-[10px]'} />
|
||||||
<UserInput />
|
<UserInput />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -35,10 +35,7 @@ import useDownloadModel from '@/hooks/useDownloadModel'
|
|||||||
import { modelDownloadStateAtom } from '@/hooks/useDownloadState'
|
import { modelDownloadStateAtom } from '@/hooks/useDownloadState'
|
||||||
import { useGetEngines } from '@/hooks/useEngineManagement'
|
import { useGetEngines } from '@/hooks/useEngineManagement'
|
||||||
|
|
||||||
import {
|
import { useGetFeaturedSources } from '@/hooks/useModelSource'
|
||||||
useGetModelSources,
|
|
||||||
useGetFeaturedSources,
|
|
||||||
} from '@/hooks/useModelSource'
|
|
||||||
import useRecommendedModel from '@/hooks/useRecommendedModel'
|
import useRecommendedModel from '@/hooks/useRecommendedModel'
|
||||||
|
|
||||||
import useUpdateModelParameters from '@/hooks/useUpdateModelParameters'
|
import useUpdateModelParameters from '@/hooks/useUpdateModelParameters'
|
||||||
@ -91,7 +88,6 @@ const ModelDropdown = ({
|
|||||||
const [toggle, setToggle] = useState<HTMLDivElement | null>(null)
|
const [toggle, setToggle] = useState<HTMLDivElement | null>(null)
|
||||||
const [selectedModel, setSelectedModel] = useAtom(selectedModelAtom)
|
const [selectedModel, setSelectedModel] = useAtom(selectedModelAtom)
|
||||||
const { recommendedModel, downloadedModels } = useRecommendedModel()
|
const { recommendedModel, downloadedModels } = useRecommendedModel()
|
||||||
const { sources } = useGetModelSources()
|
|
||||||
const [dropdownOptions, setDropdownOptions] = useState<HTMLDivElement | null>(
|
const [dropdownOptions, setDropdownOptions] = useState<HTMLDivElement | null>(
|
||||||
null
|
null
|
||||||
)
|
)
|
||||||
|
|||||||
17
web/containers/Providers/QuickAskConfigurator.tsx
Normal file
17
web/containers/Providers/QuickAskConfigurator.tsx
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { PropsWithChildren, useEffect, useState } from 'react'
|
||||||
|
|
||||||
|
import { setupCoreServices } from '@/services/coreService'
|
||||||
|
|
||||||
|
export const QuickAskConfigurator = ({ children }: PropsWithChildren) => {
|
||||||
|
const [setupCore, setSetupCore] = useState(false)
|
||||||
|
|
||||||
|
// Services Setup
|
||||||
|
useEffect(() => {
|
||||||
|
setupCoreServices()
|
||||||
|
setSetupCore(true)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return <>{setupCore && <>{children}</>}</>
|
||||||
|
}
|
||||||
@ -14,28 +14,39 @@ import DataLoader from './DataLoader'
|
|||||||
|
|
||||||
import DeepLinkListener from './DeepLinkListener'
|
import DeepLinkListener from './DeepLinkListener'
|
||||||
import KeyListener from './KeyListener'
|
import KeyListener from './KeyListener'
|
||||||
|
import { QuickAskConfigurator } from './QuickAskConfigurator'
|
||||||
import Responsive from './Responsive'
|
import Responsive from './Responsive'
|
||||||
|
|
||||||
import SWRConfigProvider from './SWRConfigProvider'
|
import SWRConfigProvider from './SWRConfigProvider'
|
||||||
import SettingsHandler from './SettingsHandler'
|
import SettingsHandler from './SettingsHandler'
|
||||||
|
|
||||||
const Providers = ({ children }: PropsWithChildren) => {
|
const Providers = ({ children }: PropsWithChildren) => {
|
||||||
|
const isQuickAsk =
|
||||||
|
typeof window !== 'undefined' && window.electronAPI?.isQuickAsk()
|
||||||
return (
|
return (
|
||||||
<SWRConfigProvider>
|
<SWRConfigProvider>
|
||||||
<ThemeWrapper>
|
<ThemeWrapper>
|
||||||
<JotaiWrapper>
|
<JotaiWrapper>
|
||||||
<CoreConfigurator>
|
{isQuickAsk && (
|
||||||
<>
|
<>
|
||||||
<Responsive />
|
<QuickAskConfigurator> {children} </QuickAskConfigurator>
|
||||||
<KeyListener />
|
|
||||||
<EventListener />
|
|
||||||
<DataLoader />
|
|
||||||
<SettingsHandler />
|
|
||||||
<DeepLinkListener />
|
|
||||||
<Toaster />
|
|
||||||
{children}
|
|
||||||
</>
|
</>
|
||||||
</CoreConfigurator>
|
)}
|
||||||
|
{!isQuickAsk && (
|
||||||
|
<CoreConfigurator>
|
||||||
|
<>
|
||||||
|
<Responsive />
|
||||||
|
<KeyListener />
|
||||||
|
<EventListener />
|
||||||
|
<DataLoader />
|
||||||
|
<SettingsHandler />
|
||||||
|
<DeepLinkListener />
|
||||||
|
<Toaster />
|
||||||
|
<div className={'draggable-bar h-[32px]'} />
|
||||||
|
{children}
|
||||||
|
</>
|
||||||
|
</CoreConfigurator>
|
||||||
|
)}
|
||||||
</JotaiWrapper>
|
</JotaiWrapper>
|
||||||
</ThemeWrapper>
|
</ThemeWrapper>
|
||||||
</SWRConfigProvider>
|
</SWRConfigProvider>
|
||||||
|
|||||||
10
web/hooks/useApp.ts
Normal file
10
web/hooks/useApp.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { extensionManager } from '@/extension'
|
||||||
|
|
||||||
|
export function useApp() {
|
||||||
|
async function relaunch() {
|
||||||
|
const extensions = extensionManager.getAll()
|
||||||
|
await Promise.all(extensions.map((e) => e.onUnload()))
|
||||||
|
window.core?.api?.relaunch()
|
||||||
|
}
|
||||||
|
return { relaunch }
|
||||||
|
}
|
||||||
@ -43,7 +43,7 @@ export function useGetFeaturedSources() {
|
|||||||
const { sources, error, mutate } = useGetModelSources()
|
const { sources, error, mutate } = useGetModelSources()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
sources: sources?.filter((e) => e.metadata?.tags.includes('featured')),
|
sources: sources?.filter((e) => e.metadata?.tags?.includes('featured')),
|
||||||
error,
|
error,
|
||||||
mutate,
|
mutate,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,8 @@ import Loader from '@/containers/Loader'
|
|||||||
|
|
||||||
export const SUCCESS_SET_NEW_DESTINATION = 'successSetNewDestination'
|
export const SUCCESS_SET_NEW_DESTINATION = 'successSetNewDestination'
|
||||||
|
|
||||||
|
import { useApp } from '@/hooks/useApp'
|
||||||
|
|
||||||
import ModalChangeDirectory, {
|
import ModalChangeDirectory, {
|
||||||
showDirectoryConfirmModalAtom,
|
showDirectoryConfirmModalAtom,
|
||||||
} from './ModalChangeDirectory'
|
} from './ModalChangeDirectory'
|
||||||
@ -32,6 +34,7 @@ const DataFolder = () => {
|
|||||||
|
|
||||||
const [destinationPath, setDestinationPath] = useState(undefined)
|
const [destinationPath, setDestinationPath] = useState(undefined)
|
||||||
const janDataFolderPath = useAtomValue(janDataFolderPathAtom)
|
const janDataFolderPath = useAtomValue(janDataFolderPathAtom)
|
||||||
|
const { relaunch } = useApp()
|
||||||
|
|
||||||
const onChangeFolderClick = useCallback(async () => {
|
const onChangeFolderClick = useCallback(async () => {
|
||||||
const destFolder = await window.core?.api?.selectDirectory()
|
const destFolder = await window.core?.api?.selectDirectory()
|
||||||
@ -78,7 +81,7 @@ const DataFolder = () => {
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setShowLoader(false)
|
setShowLoader(false)
|
||||||
}, 1200)
|
}, 1200)
|
||||||
await window.core?.api?.relaunch()
|
await relaunch()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
setShowLoader(false)
|
setShowLoader(false)
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import { useDebouncedCallback } from 'use-debounce'
|
|||||||
|
|
||||||
import { toaster } from '@/containers/Toast'
|
import { toaster } from '@/containers/Toast'
|
||||||
|
|
||||||
|
import { useApp } from '@/hooks/useApp'
|
||||||
import { useConfigurations } from '@/hooks/useConfigurations'
|
import { useConfigurations } from '@/hooks/useConfigurations'
|
||||||
|
|
||||||
import ModalDeleteAllThreads from '@/screens/Thread/ThreadLeftPanel/ModalDeleteAllThreads'
|
import ModalDeleteAllThreads from '@/screens/Thread/ThreadLeftPanel/ModalDeleteAllThreads'
|
||||||
@ -47,6 +48,7 @@ const Advanced = ({ setSubdir }: { setSubdir: (subdir: string) => void }) => {
|
|||||||
const { configurePullOptions } = useConfigurations()
|
const { configurePullOptions } = useConfigurations()
|
||||||
|
|
||||||
const setModalActionThread = useSetAtom(modalActionThreadAtom)
|
const setModalActionThread = useSetAtom(modalActionThreadAtom)
|
||||||
|
const { relaunch } = useApp()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* There could be a case where the state update is not synced
|
* There could be a case where the state update is not synced
|
||||||
@ -66,13 +68,13 @@ const Advanced = ({ setSubdir }: { setSubdir: (subdir: string) => void }) => {
|
|||||||
*/
|
*/
|
||||||
const updateQuickAskEnabled = async (
|
const updateQuickAskEnabled = async (
|
||||||
e: boolean,
|
e: boolean,
|
||||||
relaunch: boolean = true
|
relaunchApp: boolean = true
|
||||||
) => {
|
) => {
|
||||||
const appConfiguration: AppConfiguration =
|
const appConfiguration: AppConfiguration =
|
||||||
await window.core?.api?.getAppConfigurations()
|
await window.core?.api?.getAppConfigurations()
|
||||||
appConfiguration.quick_ask = e
|
appConfiguration.quick_ask = e
|
||||||
await window.core?.api?.updateAppConfiguration(appConfiguration)
|
await window.core?.api?.updateAppConfiguration(appConfiguration)
|
||||||
if (relaunch) window.core?.api?.relaunch()
|
if (relaunchApp) relaunch()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -92,7 +94,7 @@ const Advanced = ({ setSubdir }: { setSubdir: (subdir: string) => void }) => {
|
|||||||
// It affects other settings, so we need to reset them
|
// It affects other settings, so we need to reset them
|
||||||
const isRelaunch = quickAskEnabled
|
const isRelaunch = quickAskEnabled
|
||||||
if (quickAskEnabled) await updateQuickAskEnabled(false, false)
|
if (quickAskEnabled) await updateQuickAskEnabled(false, false)
|
||||||
if (isRelaunch) window.core?.api?.relaunch()
|
if (isRelaunch) relaunch()
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -9,6 +9,8 @@ import { Marked, Renderer } from 'marked'
|
|||||||
|
|
||||||
import Loader from '@/containers/Loader'
|
import Loader from '@/containers/Loader'
|
||||||
|
|
||||||
|
import { useApp } from '@/hooks/useApp'
|
||||||
|
|
||||||
import { formatExtensionsName } from '@/utils/converter'
|
import { formatExtensionsName } from '@/utils/converter'
|
||||||
|
|
||||||
import { extensionManager } from '@/extension'
|
import { extensionManager } from '@/extension'
|
||||||
@ -23,6 +25,7 @@ const ExtensionCatalog = () => {
|
|||||||
const [searchText, setSearchText] = useState('')
|
const [searchText, setSearchText] = useState('')
|
||||||
const [showLoading, setShowLoading] = useState(false)
|
const [showLoading, setShowLoading] = useState(false)
|
||||||
const fileInputRef = useRef<HTMLInputElement | null>(null)
|
const fileInputRef = useRef<HTMLInputElement | null>(null)
|
||||||
|
const { relaunch } = useApp()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const getAllSettings = async () => {
|
const getAllSettings = async () => {
|
||||||
@ -74,7 +77,7 @@ const ExtensionCatalog = () => {
|
|||||||
// Send the filename of the to be installed extension
|
// Send the filename of the to be installed extension
|
||||||
// to the main process for installation
|
// to the main process for installation
|
||||||
const installed = await extensionManager.install([extensionFile])
|
const installed = await extensionManager.install([extensionFile])
|
||||||
if (installed) window.core?.api?.relaunch()
|
if (installed) relaunch()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -87,7 +90,7 @@ const ExtensionCatalog = () => {
|
|||||||
// Send the filename of the to be uninstalled extension
|
// Send the filename of the to be uninstalled extension
|
||||||
// to the main process for removal
|
// to the main process for removal
|
||||||
const res = await extensionManager.uninstall([name])
|
const res = await extensionManager.uninstall([name])
|
||||||
if (res) window.core?.api?.relaunch()
|
if (res) relaunch()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -7,18 +7,18 @@
|
|||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dragable-bar {
|
.draggable-bar {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0px;
|
left: 0px;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 32px;
|
|
||||||
user-select: none;
|
|
||||||
-webkit-app-region: drag;
|
-webkit-app-region: drag;
|
||||||
}
|
}
|
||||||
|
|
||||||
.unset-drag {
|
.unset-drag {
|
||||||
|
user-select: inherit;
|
||||||
-webkit-app-region: no-drag;
|
-webkit-app-region: no-drag;
|
||||||
|
pointer-events: all; /* Ensure it receives input events */
|
||||||
}
|
}
|
||||||
|
|
||||||
.unselect {
|
.unselect {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user