enhancement: scrollbar setting options (#4726)

* enhancement: scrollbar setting options

* chore: fix linter
This commit is contained in:
Faisal Amir 2025-02-25 09:37:04 +07:00 committed by GitHub
parent 81fea5665b
commit 2ea8083ad7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 191 additions and 56 deletions

View File

@ -684,61 +684,61 @@ __metadata:
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fassistant-extension%40workspace%3Aassistant-extension":
version: 0.1.10
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=ff5479&locator=%40janhq%2Fassistant-extension%40workspace%3Aassistant-extension"
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=b51c7a&locator=%40janhq%2Fassistant-extension%40workspace%3Aassistant-extension"
dependencies:
rxjs: "npm:^7.8.1"
ulidx: "npm:^2.3.0"
checksum: 10c0/a9f5cc6b3e90eecef539a2036385dcdcb5988304a4c78d1bff4fe9e7e9910b319aa1efd92c395a0dabee98821a9bc274f45958a345441204f3dafbeec76ba658
checksum: 10c0/14c61c6f50f09da8202fec64a46e3b5b81927872ee25695da209a2cc1cf7638049c9cd981a0be0cd51034479dfd3d921b851b0fa2809a4823095977b41954e6e
languageName: node
linkType: hard
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fconversational-extension%40workspace%3Aconversational-extension":
version: 0.1.10
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=ff5479&locator=%40janhq%2Fconversational-extension%40workspace%3Aconversational-extension"
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=b51c7a&locator=%40janhq%2Fconversational-extension%40workspace%3Aconversational-extension"
dependencies:
rxjs: "npm:^7.8.1"
ulidx: "npm:^2.3.0"
checksum: 10c0/a9f5cc6b3e90eecef539a2036385dcdcb5988304a4c78d1bff4fe9e7e9910b319aa1efd92c395a0dabee98821a9bc274f45958a345441204f3dafbeec76ba658
checksum: 10c0/14c61c6f50f09da8202fec64a46e3b5b81927872ee25695da209a2cc1cf7638049c9cd981a0be0cd51034479dfd3d921b851b0fa2809a4823095977b41954e6e
languageName: node
linkType: hard
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fengine-management-extension%40workspace%3Aengine-management-extension":
version: 0.1.10
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=ff5479&locator=%40janhq%2Fengine-management-extension%40workspace%3Aengine-management-extension"
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=b51c7a&locator=%40janhq%2Fengine-management-extension%40workspace%3Aengine-management-extension"
dependencies:
rxjs: "npm:^7.8.1"
ulidx: "npm:^2.3.0"
checksum: 10c0/a9f5cc6b3e90eecef539a2036385dcdcb5988304a4c78d1bff4fe9e7e9910b319aa1efd92c395a0dabee98821a9bc274f45958a345441204f3dafbeec76ba658
checksum: 10c0/14c61c6f50f09da8202fec64a46e3b5b81927872ee25695da209a2cc1cf7638049c9cd981a0be0cd51034479dfd3d921b851b0fa2809a4823095977b41954e6e
languageName: node
linkType: hard
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fhardware-management-extension%40workspace%3Ahardware-management-extension":
version: 0.1.10
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=ff5479&locator=%40janhq%2Fhardware-management-extension%40workspace%3Ahardware-management-extension"
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=b51c7a&locator=%40janhq%2Fhardware-management-extension%40workspace%3Ahardware-management-extension"
dependencies:
rxjs: "npm:^7.8.1"
ulidx: "npm:^2.3.0"
checksum: 10c0/a9f5cc6b3e90eecef539a2036385dcdcb5988304a4c78d1bff4fe9e7e9910b319aa1efd92c395a0dabee98821a9bc274f45958a345441204f3dafbeec76ba658
checksum: 10c0/14c61c6f50f09da8202fec64a46e3b5b81927872ee25695da209a2cc1cf7638049c9cd981a0be0cd51034479dfd3d921b851b0fa2809a4823095977b41954e6e
languageName: node
linkType: hard
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Finference-cortex-extension%40workspace%3Ainference-cortex-extension":
version: 0.1.10
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=ff5479&locator=%40janhq%2Finference-cortex-extension%40workspace%3Ainference-cortex-extension"
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=b51c7a&locator=%40janhq%2Finference-cortex-extension%40workspace%3Ainference-cortex-extension"
dependencies:
rxjs: "npm:^7.8.1"
ulidx: "npm:^2.3.0"
checksum: 10c0/a9f5cc6b3e90eecef539a2036385dcdcb5988304a4c78d1bff4fe9e7e9910b319aa1efd92c395a0dabee98821a9bc274f45958a345441204f3dafbeec76ba658
checksum: 10c0/14c61c6f50f09da8202fec64a46e3b5b81927872ee25695da209a2cc1cf7638049c9cd981a0be0cd51034479dfd3d921b851b0fa2809a4823095977b41954e6e
languageName: node
linkType: hard
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fmodel-extension%40workspace%3Amodel-extension":
version: 0.1.10
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=ff5479&locator=%40janhq%2Fmodel-extension%40workspace%3Amodel-extension"
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=b51c7a&locator=%40janhq%2Fmodel-extension%40workspace%3Amodel-extension"
dependencies:
rxjs: "npm:^7.8.1"
ulidx: "npm:^2.3.0"
checksum: 10c0/a9f5cc6b3e90eecef539a2036385dcdcb5988304a4c78d1bff4fe9e7e9910b319aa1efd92c395a0dabee98821a9bc274f45958a345441204f3dafbeec76ba658
checksum: 10c0/14c61c6f50f09da8202fec64a46e3b5b81927872ee25695da209a2cc1cf7638049c9cd981a0be0cd51034479dfd3d921b851b0fa2809a4823095977b41954e6e
languageName: node
linkType: hard
@ -755,6 +755,7 @@ __metadata:
run-script-os: "npm:^1.1.6"
ts-loader: "npm:^9.5.0"
typescript: "npm:^5.3.3"
vitest: "npm:^3.0.6"
languageName: unknown
linkType: soft

View File

@ -51,20 +51,3 @@
flex-direction: column;
height: 8px;
}
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track,
::-webkit-scrollbar-thumb {
background-clip: content-box;
border-radius: inherit;
}
::-webkit-scrollbar-track {
background: hsla(var(--scrollbar-tracker));
}
::-webkit-scrollbar-thumb {
background: hsla(var(--scrollbar-thumb));
border-radius: 20px;
}

View File

@ -42,6 +42,7 @@ import {
productAnalyticAtom,
productAnalyticPromptAtom,
reduceTransparentAtom,
showScrollBarAtom,
} from '@/helpers/atoms/Setting.atom'
const BaseLayout = () => {
@ -52,6 +53,7 @@ const BaseLayout = () => {
const [productAnalyticPrompt, setProductAnalyticPrompt] = useAtom(
productAnalyticPromptAtom
)
const showScrollBar = useAtomValue(showScrollBarAtom)
const [showProductAnalyticPrompt, setShowProductAnalyticPrompt] =
useState(false)
@ -150,7 +152,12 @@ const BaseLayout = () => {
)}
>
<TopPanel />
<div className="relative top-9 flex h-[calc(100vh-(36px+36px))] w-screen">
<div
className={twMerge(
'relative top-9 flex h-[calc(100vh-(36px+36px))] w-screen',
showScrollBar && 'show-scroll-bar'
)}
>
<RibbonPanel />
<MainViewContainer />
<LoadingModal />

View File

@ -12,7 +12,10 @@ import { atom, useAtom, useAtomValue } from 'jotai'
import { twMerge } from 'tailwind-merge'
import { showLeftPanelAtom } from '@/helpers/atoms/App.atom'
import { reduceTransparentAtom } from '@/helpers/atoms/Setting.atom'
import {
reduceTransparentAtom,
showScrollBarAtom,
} from '@/helpers/atoms/Setting.atom'
type Props = PropsWithChildren
@ -27,6 +30,7 @@ const LeftPanelContainer = ({ children }: Props) => {
const [showLeftPanel, setShowLeftPanel] = useAtom(showLeftPanelAtom)
const matches = useMediaQuery('(max-width: 880px)')
const reduceTransparent = useAtomValue(reduceTransparentAtom)
const showScrollBar = useAtomValue(showScrollBarAtom)
useClickOutside(
() => matches && showLeftPanel && setShowLeftPanel(false),
@ -101,7 +105,10 @@ const LeftPanelContainer = ({ children }: Props) => {
style={{ width: showLeftPanel ? leftPanelWidth : 0 }}
onMouseDown={(e) => isResizing && e.stopPropagation()}
>
<ScrollArea className="h-full w-full">
<ScrollArea
type={showScrollBar ? 'always' : 'scroll'}
className="h-full w-full"
>
{children}
{showLeftPanel && !matches && (
<Fragment>

View File

@ -4,6 +4,7 @@ import { ScrollArea } from '@janhq/joi'
import { useAtomValue } from 'jotai'
import { showScrollBarAtom } from '@/helpers/atoms/Setting.atom'
import { activeThreadAtom } from '@/helpers/atoms/Thread.atom'
const ListContainer = ({ children }: PropsWithChildren) => {
@ -12,6 +13,7 @@ const ListContainer = ({ children }: PropsWithChildren) => {
const isUserManuallyScrollingUp = useRef(false)
const activeThread = useAtomValue(activeThreadAtom)
const prevActiveThread = useRef(activeThread)
const showScrollBar = useAtomValue(showScrollBarAtom)
// Handle active thread changes
useEffect(() => {
@ -59,6 +61,7 @@ const ListContainer = ({ children }: PropsWithChildren) => {
return (
<ScrollArea
type={showScrollBar ? 'always' : 'scroll'}
className="flex h-full w-full flex-col overflow-x-hidden"
ref={listRef}
onScroll={handleScroll}

View File

@ -55,6 +55,7 @@ import {
showEngineListModelAtom,
} from '@/helpers/atoms/Model.atom'
import { showScrollBarAtom } from '@/helpers/atoms/Setting.atom'
import {
activeThreadAtom,
setThreadModelParamsAtom,
@ -77,6 +78,7 @@ const ModelDropdown = ({
const [modelDropdownState, setModelDropdownState] = useAtom(
modelDropdownStateAtom
)
const showScrollBar = useAtomValue(showScrollBarAtom)
const [searchFilter, setSearchFilter] = useState('local')
const [searchText, setSearchText] = useState('')
@ -385,7 +387,10 @@ const ModelDropdown = ({
}
/>
</div>
<ScrollArea className="h-[calc(100%-90px)] w-full">
<ScrollArea
type={showScrollBar ? 'always' : 'scroll'}
className="h-[calc(100%-90px)] w-full"
>
{engineList
.filter((e) => e.type === searchFilter)
.filter(

View File

@ -12,7 +12,10 @@ import { atom, useAtom, useAtomValue } from 'jotai'
import { twMerge } from 'tailwind-merge'
import { showRightPanelAtom } from '@/helpers/atoms/App.atom'
import { reduceTransparentAtom } from '@/helpers/atoms/Setting.atom'
import {
reduceTransparentAtom,
showScrollBarAtom,
} from '@/helpers/atoms/Setting.atom'
type Props = PropsWithChildren
@ -28,6 +31,7 @@ const RightPanelContainer = ({ children }: Props) => {
null
)
const reduceTransparent = useAtomValue(reduceTransparentAtom)
const showScrollBar = useAtomValue(showScrollBarAtom)
const [showRightPanel, setShowRightPanel] = useAtom(showRightPanelAtom)
const matches = useMediaQuery('(max-width: 880px)')
@ -105,7 +109,10 @@ const RightPanelContainer = ({ children }: Props) => {
style={{ width: showRightPanel ? rightPanelWidth : 0 }}
onMouseDown={(e) => isResizing && e.preventDefault()}
>
<ScrollArea className="h-full w-full">
<ScrollArea
type={showScrollBar ? 'always' : 'scroll'}
className="h-full w-full"
>
{children}
{showRightPanel && !matches && (
<Fragment>

View File

@ -14,6 +14,7 @@ import { useLogs } from '@/hooks/useLogs'
import { usePath } from '@/hooks/usePath'
import { serverEnabledAtom } from '@/helpers/atoms/LocalServer.atom'
import { showScrollBarAtom } from '@/helpers/atoms/Setting.atom'
type ServerLogsProps = { limit?: number; withCopy?: boolean }
@ -25,6 +26,7 @@ const ServerLogs = (props: ServerLogsProps) => {
const listRef = useRef<HTMLDivElement>(null)
const prevScrollTop = useRef(0)
const isUserManuallyScrollingUp = useRef(false)
const showScrollBar = useAtomValue(showScrollBarAtom)
const updateLogs = useCallback(
() =>
@ -136,6 +138,7 @@ const ServerLogs = (props: ServerLogsProps) => {
)}
</div>
<ScrollArea
type={showScrollBar ? 'always' : 'scroll'}
ref={listRef}
className={twMerge(
'h-[calc(100%-49px)] w-full p-4 py-0',

View File

@ -11,6 +11,7 @@ export const janSettingScreenAtom = atom<SettingScreen[]>([])
export const THEME = 'themeAppearance'
export const REDUCE_TRANSPARENT = 'reduceTransparent'
export const SPELL_CHECKING = 'spellChecking'
export const SCROLL_BAR = 'scrollBar'
export const PRODUCT_ANALYTIC = 'productAnalytic'
export const PRODUCT_ANALYTIC_PROMPT = 'productAnalyticPrompt'
export const THEME_DATA = 'themeData'
@ -45,6 +46,12 @@ export const spellCheckAtom = atomWithStorage<boolean>(
undefined,
{ getOnInit: true }
)
export const showScrollBarAtom = atomWithStorage<boolean>(
SCROLL_BAR,
false,
undefined,
{ getOnInit: true }
)
export const productAnalyticAtom = atomWithStorage<boolean>(
PRODUCT_ANALYTIC,
false,

View File

@ -2,7 +2,7 @@ import Image from 'next/image'
import { ModelSource } from '@janhq/core'
import { Badge, Button, ScrollArea } from '@janhq/joi'
import { useSetAtom } from 'jotai'
import { useAtomValue, useSetAtom } from 'jotai'
import {
ArrowLeftIcon,
DownloadIcon,
@ -24,7 +24,10 @@ import { toGigabytes } from '@/utils/converter'
import { extractModelName } from '@/utils/modelSource'
import { mainViewStateAtom } from '@/helpers/atoms/App.atom'
import { selectedSettingAtom } from '@/helpers/atoms/Setting.atom'
import {
selectedSettingAtom,
showScrollBarAtom,
} from '@/helpers/atoms/Setting.atom'
type Props = {
model: ModelSource
@ -35,9 +38,14 @@ const ModelPage = ({ model, onGoBack }: Props) => {
const setSelectedSetting = useSetAtom(selectedSettingAtom)
const setMainViewState = useSetAtom(mainViewStateAtom)
const { refreshingModels, refreshModels } = useRefreshModelList(model.id)
const showScrollBar = useAtomValue(showScrollBarAtom)
return (
<ScrollArea data-testid="hub-container-test-id" className="h-full w-full">
<ScrollArea
type={showScrollBar ? 'always' : 'scroll'}
data-testid="hub-container-test-id"
className="h-full w-full"
>
<div className="flex h-full w-full justify-center">
<div className="flex w-full max-w-[800px] flex-col ">
<div className="sticky top-0 flex h-12 items-center bg-[hsla(var(--app-bg))] px-4">

View File

@ -51,6 +51,7 @@ import {
} from '@/helpers/atoms/App.atom'
import { modelDetailAtom } from '@/helpers/atoms/Model.atom'
import { showScrollBarAtom } from '@/helpers/atoms/Setting.atom'
import { totalRamAtom } from '@/helpers/atoms/SystemBar.atom'
const sortMenus = [
@ -94,6 +95,7 @@ const HubScreen = () => {
const [selectedModel, setSelectedModel] = useState<ModelSource | undefined>(
undefined
)
const showScrollBar = useAtomValue(showScrollBarAtom)
const [modelDetail, setModelDetail] = useAtom(modelDetailAtom)
const setImportModelStage = useSetAtom(setImportModelStageAtom)
const dropdownRef = useRef<HTMLDivElement>(null)
@ -260,6 +262,7 @@ const HubScreen = () => {
>
{!selectedModel && (
<ScrollArea
type={showScrollBar ? 'always' : 'scroll'}
data-testid="hub-container-test-id"
className="h-full w-full"
>
@ -311,7 +314,10 @@ const HubScreen = () => {
/>
</div>
{hubBannerOption === 'gallery' && (
<ScrollArea className="h-[350px] w-full">
<ScrollArea
type={showScrollBar ? 'always' : 'scroll'}
className="h-[350px] w-full"
>
{Array.from({ length: 30 }, (_, i) => i + 1).map(
(e) => {
return (

View File

@ -1,7 +1,7 @@
import { useCallback, useState } from 'react'
import { Input, ScrollArea, Switch } from '@janhq/joi'
import { useAtom } from 'jotai'
import { useAtom, useAtomValue } from 'jotai'
import { EyeIcon, EyeOffIcon, XIcon, ArrowLeftIcon } from 'lucide-react'
import { useDebouncedCallback } from 'use-debounce'
@ -18,6 +18,7 @@ import {
proxyUsernameAtom,
proxyPasswordAtom,
} from '@/helpers/atoms/AppConfig.atom'
import { showScrollBarAtom } from '@/helpers/atoms/Setting.atom'
const ProxySettings = ({ onBack }: { onBack: () => void }) => {
const [proxy, setProxy] = useAtom(proxyAtom)
@ -38,6 +39,7 @@ const ProxySettings = ({ onBack }: { onBack: () => void }) => {
const [verifyPeerSSL, setVerifyPeerSSL] = useAtom(verifyPeerSslAtom)
const [verifyHostSSL, setVerifyHostSSL] = useAtom(verifyHostSslAtom)
const [showPassword, setShowPassword] = useState(false)
const showScrollBar = useAtomValue(showScrollBarAtom)
const updatePullOptions = useDebouncedCallback(
() => configurePullOptions(),
@ -102,7 +104,10 @@ const ProxySettings = ({ onBack }: { onBack: () => void }) => {
)
return (
<ScrollArea className="h-full w-full">
<ScrollArea
type={showScrollBar ? 'always' : 'scroll'}
className="h-full w-full"
>
{/* Header */}
<div className="sticky top-0 z-10 flex h-12 items-center border-b border-[hsla(var(--app-border))] bg-[hsla(var(--app-bg))] px-4">
<div className="flex items-center gap-2">

View File

@ -26,6 +26,7 @@ import {
quickAskEnabledAtom,
} from '@/helpers/atoms/AppConfig.atom'
import { showScrollBarAtom } from '@/helpers/atoms/Setting.atom'
import { ThreadModalAction } from '@/helpers/atoms/Thread.atom'
import { modalActionThreadAtom } from '@/helpers/atoms/Thread.atom'
@ -38,6 +39,7 @@ const Advanced = ({ setSubdir }: { setSubdir: (subdir: string) => void }) => {
const [experimentalEnabled, setExperimentalEnabled] = useAtom(
experimentalFeatureEnabledAtom
)
const showScrollBar = useAtomValue(showScrollBarAtom)
const [proxyEnabled, setProxyEnabled] = useAtom(proxyEnabledAtom)
const quickAskEnabled = useAtomValue(quickAskEnabledAtom)
@ -94,7 +96,10 @@ const Advanced = ({ setSubdir }: { setSubdir: (subdir: string) => void }) => {
}
return (
<ScrollArea className="h-full w-full px-4">
<ScrollArea
type={showScrollBar ? 'always' : 'scroll'}
className="h-full w-full px-4"
>
<div className="block w-full py-4">
{/* Experimental */}
<div className="flex w-full flex-row items-start justify-between gap-4 border-b border-[hsla(var(--app-border))] py-4 first:pt-0 last:border-none">

View File

@ -14,6 +14,7 @@ import {
chatWidthAtom,
reduceTransparentAtom,
selectedThemeIdAtom,
showScrollBarAtom,
spellCheckAtom,
themeDataAtom,
themesOptionsAtom,
@ -29,6 +30,7 @@ export default function AppearanceOptions() {
reduceTransparentAtom
)
const [spellCheck, setSpellCheck] = useAtom(spellCheckAtom)
const [showScrollBar, setShowScrollBar] = useAtom(showScrollBarAtom)
const [chatWidth, setChatWidth] = useAtom(chatWidthAtom)
const chatWidthOption = [
@ -194,6 +196,22 @@ export default function AppearanceOptions() {
/>
</div>
</div>
<div className="flex w-full flex-col items-start justify-between gap-4 border-b border-[hsla(var(--app-border))] py-4 first:pt-0 last:border-none sm:flex-row">
<div className="w-full space-y-1 lg:w-3/4">
<div className="flex gap-x-2">
<h6 className="font-semibold capitalize">Scrolling Bar</h6>
</div>
<p className=" font-medium leading-relaxed text-[hsla(var(--text-secondary))]">
Turn on to make scrolling bar visible across windows.
</p>
</div>
<div className="flex-shrink-0">
<Switch
checked={showScrollBar}
onChange={(e) => setShowScrollBar(e.target.checked)}
/>
</div>
</div>
</div>
)
}

View File

@ -3,6 +3,7 @@ import React, { useState, useEffect, useRef } from 'react'
import { Button, ScrollArea, Badge, Input } from '@janhq/joi'
import { useAtomValue } from 'jotai'
import { SearchIcon } from 'lucide-react'
import { Marked, Renderer } from 'marked'
@ -12,12 +13,13 @@ import { formatExtensionsName } from '@/utils/converter'
import { extensionManager } from '@/extension'
import Extension from '@/extension/Extension'
import { showScrollBarAtom } from '@/helpers/atoms/Setting.atom'
const ExtensionCatalog = () => {
const [coreActiveExtensions, setCoreActiveExtensions] = useState<Extension[]>(
[]
)
const showScrollBar = useAtomValue(showScrollBarAtom)
const [searchText, setSearchText] = useState('')
const [showLoading, setShowLoading] = useState(false)
const fileInputRef = useRef<HTMLInputElement | null>(null)
@ -103,7 +105,10 @@ const ExtensionCatalog = () => {
return (
<>
<ScrollArea className="h-full w-full">
<ScrollArea
type={showScrollBar ? 'always' : 'scroll'}
className="h-full w-full"
>
<div className="flex w-full flex-col items-start justify-between gap-y-2 p-4 sm:flex-row">
<div className="w-full sm:w-[300px]">
<Input

View File

@ -9,7 +9,7 @@ import {
} from '@janhq/core'
import { Button, ScrollArea, Badge, Select, Progress } from '@janhq/joi'
import { useAtom } from 'jotai'
import { useAtom, useAtomValue } from 'jotai'
import { twMerge } from 'tailwind-merge'
import { useActiveModel } from '@/hooks/useActiveModel'
@ -30,6 +30,7 @@ import ExtensionSetting from '../ExtensionSetting'
import DeleteEngineVariant from './DeleteEngineVariant'
import { LocalEngineDefaultVariantAtom } from '@/helpers/atoms/App.atom'
import { showScrollBarAtom } from '@/helpers/atoms/Setting.atom'
const os = () => {
switch (PLATFORM) {
case 'win32':
@ -53,6 +54,7 @@ const LocalEngineSettings = ({ engine }: { engine: InferenceEngine }) => {
defaultEngineVariant?.version as string,
os()
)
const showScrollBar = useAtomValue(showScrollBarAtom)
const [installingEngines, setInstallingEngines] = useState<
Map<string, number>
>(new Map())
@ -169,7 +171,10 @@ const LocalEngineSettings = ({ engine }: { engine: InferenceEngine }) => {
}
return (
<ScrollArea className="h-full w-full">
<ScrollArea
type={showScrollBar ? 'always' : 'scroll'}
className="h-full w-full"
>
<div className="block w-full px-4">
<div className="mb-3 mt-4 border-b border-[hsla(var(--app-border))] pb-4">
<div className="flex w-full flex-col items-start justify-between sm:flex-row">

View File

@ -48,6 +48,7 @@ import {
downloadedModelsAtom,
selectedModelAtom,
} from '@/helpers/atoms/Model.atom'
import { showScrollBarAtom } from '@/helpers/atoms/Setting.atom'
import { threadsAtom } from '@/helpers/atoms/Thread.atom'
const RemoteEngineSettings = ({
@ -64,6 +65,7 @@ const RemoteEngineSettings = ({
const customEngineLogo = getLogoEngine(name)
const threads = useAtomValue(threadsAtom)
const { refreshingModels, refreshModels } = useRefreshModelList(name)
const showScrollBar = useAtomValue(showScrollBarAtom)
const engine =
engines &&
@ -150,7 +152,10 @@ const RemoteEngineSettings = ({
if (!engine) return null
return (
<ScrollArea className="h-full w-full">
<ScrollArea
type={showScrollBar ? 'always' : 'scroll'}
className="h-full w-full"
>
<div className="block w-full px-4">
<div className="mb-3 mt-4 border-b border-[hsla(var(--app-border))] pb-4">
<div className="flex w-full flex-col items-start justify-between sm:flex-row">

View File

@ -3,6 +3,8 @@ import React from 'react'
import { InferenceEngine } from '@janhq/core'
import { ScrollArea } from '@janhq/joi'
import { useAtomValue } from 'jotai'
import { useGetEngines } from '@/hooks/useEngineManagement'
import { isLocalEngine } from '@/utils/modelEngine'
@ -11,11 +13,17 @@ import LocalEngineItems from './LocalEngineItem'
import ModalAddRemoteEngine from './ModalAddRemoteEngine'
import RemoteEngineItems from './RemoteEngineItem'
import { showScrollBarAtom } from '@/helpers/atoms/Setting.atom'
const Engines = () => {
const { engines } = useGetEngines()
const showScrollBar = useAtomValue(showScrollBarAtom)
return (
<ScrollArea className="h-full w-full">
<ScrollArea
type={showScrollBar ? 'always' : 'scroll'}
className="h-full w-full"
>
<div className="block w-full px-4">
<div className="mb-3 mt-4 pb-4">
<h6 className="text-xs text-[hsla(var(--text-secondary))]">

View File

@ -22,6 +22,7 @@ import { toGigabytes } from '@/utils/converter'
import { utilizedMemory } from '@/utils/memory'
import { showScrollBarAtom } from '@/helpers/atoms/Setting.atom'
import {
cpuUsageAtom,
ramUtilitizedAtom,
@ -44,7 +45,7 @@ const Hardware = () => {
const totalRam = useAtomValue(totalRamAtom)
const usedRam = useAtomValue(usedRamAtom)
const ramUtilitized = useAtomValue(ramUtilitizedAtom)
const showScrollBar = useAtomValue(showScrollBarAtom)
const [gpus, setGpus] = useAtom(gpusAtom)
const [orderGpus, setOrderGpus] = useAtom(orderGpusAtom)
@ -133,7 +134,10 @@ const Hardware = () => {
}, [hardware?.gpus, setGpus])
return (
<ScrollArea className="h-full w-full px-4">
<ScrollArea
type={showScrollBar ? 'always' : 'scroll'}
className="h-full w-full px-4"
>
<div className="block w-full py-4">
{/* CPU */}
<div className="flex w-full flex-col items-start justify-between gap-4 border-b border-[hsla(var(--app-border))] py-4 first:pt-0 last:border-none sm:flex-row">

View File

@ -1,4 +1,7 @@
import { ScrollArea, Badge } from '@janhq/joi'
import { useAtomValue } from 'jotai'
import { showScrollBarAtom } from '@/helpers/atoms/Setting.atom'
const availableHotkeys = [
{
@ -42,8 +45,12 @@ const availableHotkeys = [
]
const Hotkeys = () => {
const showScrollBar = useAtomValue(showScrollBarAtom)
return (
<ScrollArea className="h-full w-full p-4">
<ScrollArea
type={showScrollBar ? 'always' : 'scroll'}
className="h-full w-full p-4"
>
<div className="mb-2 flex flex-col items-center justify-center gap-2">
<div className="hidden w-full gap-x-4 border-b border-[hsla(var(--app-border))] pb-2 sm:flex">
<div className="w-1/2 pb-2">

View File

@ -40,6 +40,7 @@ import {
downloadedModelsAtom,
showEngineListModelAtom,
} from '@/helpers/atoms/Model.atom'
import { showScrollBarAtom } from '@/helpers/atoms/Setting.atom'
const MyModels = () => {
const downloadedModels = useAtomValue(downloadedModelsAtom)
@ -49,6 +50,7 @@ const MyModels = () => {
const [showEngineListModel, setShowEngineListModel] = useAtom(
showEngineListModelAtom
)
const showScrollBar = useAtomValue(showScrollBarAtom)
const { engines } = useGetEngines()
@ -124,7 +126,10 @@ const MyModels = () => {
return (
<div {...getRootProps()} className="h-full w-full">
<ScrollArea className="h-full w-full">
<ScrollArea
type={showScrollBar ? 'always' : 'scroll'}
className="h-full w-full"
>
{isDragActive && (
<div className="absolute z-50 mx-auto h-full w-full bg-[hsla(var(--app-bg))]/50 p-8 backdrop-blur-lg">
<div

View File

@ -10,7 +10,10 @@ import { toaster } from '@/containers/Toast'
import { usePath } from '@/hooks/usePath'
import { janDataFolderPathAtom } from '@/helpers/atoms/AppConfig.atom'
import { productAnalyticAtom } from '@/helpers/atoms/Setting.atom'
import {
productAnalyticAtom,
showScrollBarAtom,
} from '@/helpers/atoms/Setting.atom'
const Privacy = () => {
/**
@ -30,13 +33,16 @@ const Privacy = () => {
type: 'success',
})
}
const showScrollBar = useAtomValue(showScrollBarAtom)
const janDataFolderPath = useAtomValue(janDataFolderPathAtom)
const { onRevealInFinder } = usePath()
const [productAnalytic, setProductAnalytic] = useAtom(productAnalyticAtom)
return (
<ScrollArea className="h-full w-full px-4">
<ScrollArea
type={showScrollBar ? 'always' : 'scroll'}
className="h-full w-full px-4"
>
<div className="mb-4 mt-8 rounded-xl bg-[hsla(var(--tertiary-bg))] px-4 py-2 text-[hsla(var(--text-secondary))]">
<p>
We prioritize your control over your data. Learn more about our&nbsp;

View File

@ -43,7 +43,10 @@ import {
configuredModelsAtom,
getDownloadingModelAtom,
} from '@/helpers/atoms/Model.atom'
import { selectedSettingAtom } from '@/helpers/atoms/Setting.atom'
import {
selectedSettingAtom,
showScrollBarAtom,
} from '@/helpers/atoms/Setting.atom'
type Props = {
isShowStarterScreen?: boolean
@ -57,6 +60,7 @@ const OnDeviceStarterScreen = ({ isShowStarterScreen }: Props) => {
const downloadStates = useAtomValue(modelDownloadStateAtom)
const setSelectedSetting = useSetAtom(selectedSettingAtom)
const { engines } = useGetEngines()
const showScrollBar = useAtomValue(showScrollBarAtom)
const configuredModels = useAtomValue(configuredModelsAtom)
const { sources } = useGetModelSources()
@ -98,6 +102,7 @@ const OnDeviceStarterScreen = ({ isShowStarterScreen }: Props) => {
return (
<CenterPanelContainer isShowStarterScreen={isShowStarterScreen}>
<ScrollArea
type={showScrollBar ? 'always' : 'scroll'}
className="flex h-full w-full items-center"
data-testid="onboard-screen"
>

View File

@ -33,6 +33,7 @@
}
input[type='number'] {
appearance: textfield;
-moz-appearance: textfield;
}
@ -42,3 +43,22 @@
margin: 0;
}
}
.show-scroll-bar {
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track,
::-webkit-scrollbar-thumb {
background-clip: content-box;
border-radius: inherit;
}
::-webkit-scrollbar-track {
background: hsla(var(--scrollbar-tracker));
}
::-webkit-scrollbar-thumb {
background: hsla(var(--scrollbar-thumb));
border-radius: 20px;
}
}