mirror of
https://github.com/getumbrel/umbrel.git
synced 2026-10-12 02:14:08 +00:00
Use common Prettier configuration for umbreld and ui
Moves Prettier configuration up to the root folder so any subpackage that uses it shares the same ruleset. Ruleset is taken from umbreld. Also adds an UI task to CI to check formatting.
This commit is contained in:
@@ -3,11 +3,7 @@ name: Node.js CI
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
# TODO: Rollout of 24.04 as ubuntu-latest has been put on hold, but we want
|
||||
# 24.04 because integration tests depend on it, e.g. for `pss` support. Pin
|
||||
# what we need for now, but switch back once ubuntu-latest has been updated.
|
||||
# https://github.com/actions/runner-images/issues/10636
|
||||
umbreld:
|
||||
runs-on: ubuntu-24.04
|
||||
defaults:
|
||||
run:
|
||||
@@ -28,3 +24,23 @@ jobs:
|
||||
node-version: 18
|
||||
- run: sudo npm clean-install
|
||||
- run: sudo npm run ${{ matrix.task }}
|
||||
ui:
|
||||
runs-on: ubuntu-24.04
|
||||
defaults:
|
||||
run:
|
||||
working-directory: packages/ui
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
task:
|
||||
- format:check
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 8
|
||||
- run: pnpm install
|
||||
- run: pnpm run ${{ matrix.task }}
|
||||
|
||||
@@ -31,9 +31,14 @@ jobs:
|
||||
with:
|
||||
node-version: '18'
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 8
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
npm ci
|
||||
pnpm install
|
||||
working-directory: packages/ui
|
||||
|
||||
- name: Update translations
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @type {import('prettier').Config}
|
||||
*/
|
||||
export default {
|
||||
"printWidth": 120,
|
||||
"semi": false,
|
||||
"useTabs": true,
|
||||
"trailingComma": "all",
|
||||
"singleQuote": true,
|
||||
"bracketSpacing": false,
|
||||
"jsxSingleQuote": true,
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "./scripts/umbrel-dev",
|
||||
"dev:help": "npm run dev help"
|
||||
|
||||
@@ -30,3 +30,6 @@ dist-ssr
|
||||
/playwright-report/
|
||||
/blob-report/
|
||||
/playwright/.cache/
|
||||
|
||||
# UI uses pnpm instead of npm
|
||||
package-lock.json
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
import baseConfig from '../../.prettierrc.js'
|
||||
|
||||
/**
|
||||
* @type {import('prettier').Config & import("@ianvs/prettier-plugin-sort-imports").PluginConfig}
|
||||
*/
|
||||
export default {
|
||||
printWidth: 120,
|
||||
semi: false,
|
||||
useTabs: true,
|
||||
trailingComma: 'all', // better for git diffs
|
||||
singleQuote: true,
|
||||
bracketSpacing: false,
|
||||
jsxSingleQuote: true,
|
||||
...baseConfig,
|
||||
plugins: [
|
||||
...(baseConfig.plugins || []),
|
||||
'@ianvs/prettier-plugin-sort-imports',
|
||||
'prettier-plugin-css-order',
|
||||
'prettier-plugin-style-order',
|
||||
Generated
-12333
File diff suppressed because it is too large
Load Diff
@@ -17,7 +17,8 @@
|
||||
"lint": "eslint .",
|
||||
"preview": "vite preview",
|
||||
"build-remote": "ssh root@mark-dev './pull.sh'",
|
||||
"format": "prettier . --write",
|
||||
"format": "prettier --write .",
|
||||
"format:check": "prettier --check .",
|
||||
"tsc": "tsc --noEmit",
|
||||
"size": "vite-bundle-visualizer",
|
||||
"playwright": "playwright test",
|
||||
@@ -113,7 +114,7 @@
|
||||
"fast-glob": "^3.3.2",
|
||||
"openai": "^4.51.0",
|
||||
"postcss": "8.4.31",
|
||||
"prettier": "3.0.3",
|
||||
"prettier": "3.3.3",
|
||||
"prettier-plugin-css-order": "2.0.1",
|
||||
"prettier-plugin-style-order": "0.2.2",
|
||||
"prettier-plugin-tailwindcss": "0.5.6",
|
||||
|
||||
Generated
+19
-19
@@ -201,7 +201,7 @@ devDependencies:
|
||||
version: 8.3.1
|
||||
'@ianvs/prettier-plugin-sort-imports':
|
||||
specifier: 4.1.1
|
||||
version: 4.1.1(prettier@3.0.3)
|
||||
version: 4.1.1(prettier@3.3.3)
|
||||
'@playwright/test':
|
||||
specifier: ^1.40.1
|
||||
version: 1.40.1
|
||||
@@ -266,17 +266,17 @@ devDependencies:
|
||||
specifier: 8.4.31
|
||||
version: 8.4.31
|
||||
prettier:
|
||||
specifier: 3.0.3
|
||||
version: 3.0.3
|
||||
specifier: 3.3.3
|
||||
version: 3.3.3
|
||||
prettier-plugin-css-order:
|
||||
specifier: 2.0.1
|
||||
version: 2.0.1([email protected])(prettier@3.0.3)
|
||||
version: 2.0.1([email protected])(prettier@3.3.3)
|
||||
prettier-plugin-style-order:
|
||||
specifier: 0.2.2
|
||||
version: 0.2.2(prettier@3.0.3)
|
||||
version: 0.2.2(prettier@3.3.3)
|
||||
prettier-plugin-tailwindcss:
|
||||
specifier: 0.5.6
|
||||
version: 0.5.6(@ianvs/[email protected])([email protected])([email protected])(prettier@3.0.3)
|
||||
version: 0.5.6(@ianvs/[email protected])([email protected])([email protected])(prettier@3.3.3)
|
||||
serve:
|
||||
specifier: 14.2.1
|
||||
version: 14.2.1
|
||||
@@ -844,7 +844,7 @@ packages:
|
||||
resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==}
|
||||
dev: true
|
||||
|
||||
/@ianvs/[email protected](prettier@3.0.3):
|
||||
/@ianvs/[email protected](prettier@3.3.3):
|
||||
resolution: {integrity: sha512-kJhXq63ngpTQ2dxgf5GasbPJWsJA3LgoOdd7WGhpUSzLgLgI4IsIzYkbJf9kmpOHe7Vdm/o3PcRA3jmizXUuAQ==}
|
||||
peerDependencies:
|
||||
'@vue/compiler-sfc': '>=3.0.0'
|
||||
@@ -858,7 +858,7 @@ packages:
|
||||
'@babel/parser': 7.23.0
|
||||
'@babel/traverse': 7.23.2
|
||||
'@babel/types': 7.23.0
|
||||
prettier: 3.0.3
|
||||
prettier: 3.3.3
|
||||
semver: 7.5.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -5847,7 +5847,7 @@ packages:
|
||||
engines: {node: '>= 0.8.0'}
|
||||
dev: true
|
||||
|
||||
/[email protected]([email protected])(prettier@3.0.3):
|
||||
/[email protected]([email protected])(prettier@3.3.3):
|
||||
resolution: {integrity: sha512-Y+wZ0wI7/qFUritirJksQn13KqbcNC3OZXSxGh1ui/X39hAeMW9md+Mp7fjk8H4ZQQ8c5CTYZxShoBfAal/79A==}
|
||||
engines: {node: '>=16'}
|
||||
peerDependencies:
|
||||
@@ -5856,22 +5856,22 @@ packages:
|
||||
css-declaration-sorter: 7.1.1([email protected])
|
||||
postcss-less: 6.0.0([email protected])
|
||||
postcss-scss: 4.0.9([email protected])
|
||||
prettier: 3.0.3
|
||||
prettier: 3.3.3
|
||||
transitivePeerDependencies:
|
||||
- postcss
|
||||
dev: true
|
||||
|
||||
/[email protected](prettier@3.0.3):
|
||||
/[email protected](prettier@3.3.3):
|
||||
resolution: {integrity: sha512-4rASdHONhHLNX0arKqEvjGOEAbkSZE3+GQPSaS8mf3en/spjeN0le5fV1yKltWwQeM4UPn7CkKzeD97a4Az/6w==}
|
||||
peerDependencies:
|
||||
prettier: '>= 1.13'
|
||||
dependencies:
|
||||
postcss-sorting: 5.0.1
|
||||
prettier: 3.0.3
|
||||
prettier: 3.3.3
|
||||
resolve-cwd: 3.0.0
|
||||
dev: true
|
||||
|
||||
/[email protected](@ianvs/[email protected])([email protected])([email protected])(prettier@3.0.3):
|
||||
/[email protected](@ianvs/[email protected])([email protected])([email protected])(prettier@3.3.3):
|
||||
resolution: {integrity: sha512-2Xgb+GQlkPAUCFi3sV+NOYcSI5XgduvDBL2Zt/hwJudeKXkyvRS65c38SB0yb9UB40+1rL83I6m0RtlOQ8eHdg==}
|
||||
engines: {node: '>=14.21.3'}
|
||||
peerDependencies:
|
||||
@@ -5923,14 +5923,14 @@ packages:
|
||||
prettier-plugin-twig-melody:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@ianvs/prettier-plugin-sort-imports': 4.1.1(prettier@3.0.3)
|
||||
prettier: 3.0.3
|
||||
prettier-plugin-css-order: 2.0.1([email protected])(prettier@3.0.3)
|
||||
prettier-plugin-style-order: 0.2.2(prettier@3.0.3)
|
||||
'@ianvs/prettier-plugin-sort-imports': 4.1.1(prettier@3.3.3)
|
||||
prettier: 3.3.3
|
||||
prettier-plugin-css-order: 2.0.1([email protected])(prettier@3.3.3)
|
||||
prettier-plugin-style-order: 0.2.2(prettier@3.3.3)
|
||||
dev: true
|
||||
|
||||
/prettier@3.0.3:
|
||||
resolution: {integrity: sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==}
|
||||
/prettier@3.3.3:
|
||||
resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==}
|
||||
engines: {node: '>=14'}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
@@ -38,7 +38,7 @@ export function CopyableField({
|
||||
ref={ref}
|
||||
onClick={() => setTimeout(() => ref.current?.select())}
|
||||
className={cn(
|
||||
'block flex-1 appearance-none truncate bg-transparent py-1.5 pl-2.5 font-mono outline-none min-w-0',
|
||||
'block min-w-0 flex-1 appearance-none truncate bg-transparent py-1.5 pl-2.5 font-mono outline-none',
|
||||
narrow && 'py-0.5',
|
||||
)}
|
||||
type={isPassword && !focused ? 'password' : 'text'}
|
||||
|
||||
@@ -124,7 +124,7 @@ export function useAppInstall(id: string) {
|
||||
const restart = async () => restartMut.mutate({appId: id})
|
||||
|
||||
// Ready means the app can be installed
|
||||
const state: AppStateOrLoading = appStateQ.isLoading ? 'loading' : appState ?? 'not-installed'
|
||||
const state: AppStateOrLoading = appStateQ.isLoading ? 'loading' : (appState ?? 'not-installed')
|
||||
|
||||
return {
|
||||
start,
|
||||
|
||||
@@ -60,11 +60,11 @@ export function useDeviceInfo(): DeviceInfoT {
|
||||
? {
|
||||
icon: hostEnvironmentMap[umbrelHostEnvironment].icon,
|
||||
title: device || LOADING_DASH,
|
||||
}
|
||||
}
|
||||
: {
|
||||
icon: undefined,
|
||||
title: UNKNOWN(),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import i18next from 'i18next'
|
||||
import {arrayIncludes} from 'ts-extras'
|
||||
|
||||
import {trpcReact} from '@/trpc/trpc'
|
||||
import {SupportedLanguageCode, supportedLanguageCodes} from '@/utils/language'
|
||||
|
||||
@@ -9,7 +10,7 @@ export function useLanguage(): [code: SupportedLanguageCode, setCode: (code: Sup
|
||||
onSuccess() {
|
||||
ctx.user.get.invalidate()
|
||||
ctx.user.language.invalidate()
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const setCode = (language: SupportedLanguageCode) => {
|
||||
|
||||
@@ -9,7 +9,11 @@ export type ScrollRestorationAction = 'restore' | 'reset' | 'ignore'
|
||||
* Handler function testing if scroll position should be restored, reset to zero
|
||||
* or ignored.
|
||||
*/
|
||||
export type ScrollRestorationHandler = (thisPathname: string, prevPathname: string, navigationType: NavigationType) => ScrollRestorationAction
|
||||
export type ScrollRestorationHandler = (
|
||||
thisPathname: string,
|
||||
prevPathname: string,
|
||||
navigationType: NavigationType,
|
||||
) => ScrollRestorationAction
|
||||
|
||||
/**
|
||||
* Given a ref to a scrolling container element, keep track of its scroll
|
||||
@@ -55,9 +59,9 @@ export function useScrollRestoration(container: React.RefObject<HTMLElement>, ha
|
||||
const y = Math.round(scrollElement?.scrollTop ?? 0)
|
||||
setScrollPosition(cacheKey, y ?? 0)
|
||||
}
|
||||
scrollElement?.addEventListener('scroll'/*end*/, handleScrollEnd)
|
||||
scrollElement?.addEventListener('scroll' /*end*/, handleScrollEnd)
|
||||
return () => {
|
||||
scrollElement?.removeEventListener('scroll'/*end*/, handleScrollEnd)
|
||||
scrollElement?.removeEventListener('scroll' /*end*/, handleScrollEnd)
|
||||
}
|
||||
}, [cacheKey, state, container, thisPathname, prevPathname, navigationType])
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {SupportedLanguageCode} from '@/utils/language'
|
||||
import {useLanguage} from '@/hooks/use-language'
|
||||
import {keyBy} from '@/utils/misc'
|
||||
import {trpcReact} from '@/trpc/trpc'
|
||||
import {SupportedLanguageCode} from '@/utils/language'
|
||||
import {keyBy} from '@/utils/misc'
|
||||
|
||||
const languageCodesWithFahrenheitTemperature: SupportedLanguageCode[] = ['en']
|
||||
|
||||
@@ -14,13 +14,15 @@ export type TemperatureUnit = (typeof temperatureDescriptions)[number]['id']
|
||||
|
||||
export const temperatureDescriptionsKeyed = keyBy(temperatureDescriptions, 'id')
|
||||
|
||||
export function useTemperatureUnit(optionalUnit?: TemperatureUnit): [unit: TemperatureUnit, setTemp: (unit: TemperatureUnit) => void] {
|
||||
export function useTemperatureUnit(
|
||||
optionalUnit?: TemperatureUnit,
|
||||
): [unit: TemperatureUnit, setTemp: (unit: TemperatureUnit) => void] {
|
||||
const ctx = trpcReact.useContext()
|
||||
const userGetQ = trpcReact.user.get.useQuery()
|
||||
const userSetMut = trpcReact.user.set.useMutation({
|
||||
onSuccess() {
|
||||
ctx.user.get.invalidate()
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const setUnit = (temperatureUnit: TemperatureUnit) => {
|
||||
@@ -34,7 +36,9 @@ export function useTemperatureUnit(optionalUnit?: TemperatureUnit): [unit: Tempe
|
||||
|
||||
// Use preferred unit stored on the backend once set
|
||||
const preferredUnit = userGetQ.data?.temperatureUnit
|
||||
const unit = temperatureDescriptions.some((description) => preferredUnit === description.id) ? preferredUnit as TemperatureUnit : defaultUnit
|
||||
const unit = temperatureDescriptions.some((description) => preferredUnit === description.id)
|
||||
? (preferredUnit as TemperatureUnit)
|
||||
: defaultUnit
|
||||
|
||||
return [unit, setUnit]
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ const scrollRestorationHandler = (thisPathname: string, prevPathname: string, na
|
||||
return 'ignore'
|
||||
}
|
||||
// Reset scroll position to zero unless going back in history
|
||||
if (navigationType !== "POP") {
|
||||
if (navigationType !== 'POP') {
|
||||
return 'reset'
|
||||
}
|
||||
// In app store, restore position when navigating back from an app
|
||||
|
||||
@@ -4,8 +4,8 @@ import {init} from '@/init'
|
||||
import {initTokenRenewal} from '@/modules/auth/shared'
|
||||
import {GlobalSystemStateProvider} from '@/providers/global-system-state/index'
|
||||
|
||||
import {RemoteWallpaperInjector, WallpaperProviderConnected} from './providers/wallpaper'
|
||||
import {RemoteLanguageInjector} from './providers/language'
|
||||
import {RemoteWallpaperInjector, WallpaperProviderConnected} from './providers/wallpaper'
|
||||
import {router} from './router'
|
||||
import {TrpcProvider} from './trpc/trpc-provider'
|
||||
|
||||
|
||||
@@ -37,9 +37,7 @@ const Dependency = ({app, installed = false}: {app: RegistryApp; installed: bool
|
||||
{installed ? (
|
||||
<TbCircleCheckFilled className='h-[18px] w-[18px] text-success-light' />
|
||||
) : (
|
||||
<span className='text-15 font-medium text-brand-lighter'>
|
||||
{t('app.view')}
|
||||
</span>
|
||||
<span className='text-15 font-medium text-brand-lighter'>{t('app.view')}</span>
|
||||
)}
|
||||
</Link>
|
||||
)
|
||||
|
||||
@@ -17,7 +17,7 @@ import {RegistryApp} from '@/trpc/trpc'
|
||||
|
||||
export function AppsGridSection({overline, title, apps}: {overline: string; title: ReactNode; apps?: RegistryApp[]}) {
|
||||
const isMobile = useIsMobile()
|
||||
const appsToShow = isMobile ? (apps ?? []).slice(0, 6) : apps ?? []
|
||||
const appsToShow = isMobile ? (apps ?? []).slice(0, 6) : (apps ?? [])
|
||||
return (
|
||||
<div className={cardClass}>
|
||||
<SectionTitle overline={overline} title={title} />
|
||||
|
||||
@@ -97,7 +97,7 @@ export function DockItem({
|
||||
backgroundImage: bg
|
||||
? `url(${bg})`
|
||||
: // TODO: use a better default
|
||||
`linear-gradient(to bottom right, white, black)`,
|
||||
`linear-gradient(to bottom right, white, black)`,
|
||||
scale: transform,
|
||||
...style,
|
||||
}}
|
||||
|
||||
@@ -125,7 +125,7 @@ export function AppDropdown({
|
||||
: {
|
||||
icon: undefined,
|
||||
name: t('app-picker.select-app'),
|
||||
}
|
||||
}
|
||||
|
||||
const appResults = matchSorter(apps.userApps, query, {
|
||||
keys: ['name'],
|
||||
|
||||
@@ -130,9 +130,9 @@ export type WidgetConfig<T extends WidgetType = WidgetType> = Extract<AnyWidgetC
|
||||
|
||||
export type ExampleWidgetConfig<T extends WidgetType = WidgetType> = T extends 'text-with-buttons'
|
||||
? // Omit the `type` (and `link` from buttons) by omitting `buttons` and then adding it without the `link`
|
||||
Omit<TextWithButtonsWidget, 'type' | 'buttons'> & {buttons: Omit<TextWithButtonsWidget['buttons'], 'link'>}
|
||||
Omit<TextWithButtonsWidget, 'type' | 'buttons'> & {buttons: Omit<TextWithButtonsWidget['buttons'], 'link'>}
|
||||
: // Otherwise, just omit the `type`
|
||||
Omit<WidgetConfig<T>, 'type'>
|
||||
Omit<WidgetConfig<T>, 'type'>
|
||||
|
||||
// Adding `= WidgetType` to `T` makes it so that if `T` is not provided, it defaults to `WidgetType`. Prevents us from always having to write `RegistryWidget<WidgetType>` when referring to the type.
|
||||
export type RegistryWidget<T extends WidgetType = WidgetType> = {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import i18next from 'i18next'
|
||||
import {trpcReact} from "@/trpc/trpc";
|
||||
import {supportedLanguageCodes} from '@/utils/language';
|
||||
|
||||
import {trpcReact} from '@/trpc/trpc'
|
||||
import {supportedLanguageCodes} from '@/utils/language'
|
||||
|
||||
export function RemoteLanguageInjector() {
|
||||
const languageQ = trpcReact.user.language.useQuery()
|
||||
|
||||
@@ -14,7 +14,7 @@ import {t} from '@/utils/i18n'
|
||||
|
||||
import {useDiscoverQuery} from './use-discover-query'
|
||||
|
||||
const getAppById = (appId, apps) => apps.find(app => app.id === appId);
|
||||
const getAppById = (appId, apps) => apps.find((app) => app.id === appId)
|
||||
|
||||
export default function Discover() {
|
||||
return (
|
||||
@@ -53,7 +53,7 @@ function DiscoverContent() {
|
||||
key={section.heading + section.subheading}
|
||||
title={section.heading}
|
||||
overline={section.subheading}
|
||||
apps={section.apps.map(appId => getAppById(appId, apps)).filter(app => app !== undefined)}
|
||||
apps={section.apps.map((appId) => getAppById(appId, apps)).filter((app) => app !== undefined)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -64,7 +64,7 @@ function DiscoverContent() {
|
||||
key={section.heading + section.subheading}
|
||||
overline={section.subheading}
|
||||
title={section.heading}
|
||||
apps={section.apps.map(appId => getAppById(appId, apps)).filter(app => app !== undefined)}
|
||||
apps={section.apps.map((appId) => getAppById(appId, apps)).filter((app) => app !== undefined)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -73,7 +73,7 @@ function DiscoverContent() {
|
||||
return (
|
||||
<AppsThreeColumnSection
|
||||
key={section.heading + section.subheading}
|
||||
apps={section.apps.map(appId => getAppById(appId, apps)).filter(app => app !== undefined)}
|
||||
apps={section.apps.map((appId) => getAppById(appId, apps)).filter((app) => app !== undefined)}
|
||||
overline={section.subheading}
|
||||
title={section.heading}
|
||||
textLocation={section.textLocation}
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import {AnimatedNumber} from '@/components/ui/animated-number'
|
||||
import {SegmentedControl} from '@/components/ui/segmented-control'
|
||||
import {useIsMobile} from '@/hooks/use-is-mobile'
|
||||
import {temperatureDescriptions, temperatureDescriptionsKeyed, TemperatureUnit, useTemperatureUnit} from '@/hooks/use-temperature-unit'
|
||||
import {
|
||||
temperatureDescriptions,
|
||||
temperatureDescriptionsKeyed,
|
||||
TemperatureUnit,
|
||||
useTemperatureUnit,
|
||||
} from '@/hooks/use-temperature-unit'
|
||||
import {cn} from '@/shadcn-lib/utils'
|
||||
import {t} from '@/utils/i18n'
|
||||
import {isCpuTooHot} from '@/utils/system'
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import {useState} from 'react'
|
||||
import {TbLanguage} from 'react-icons/tb'
|
||||
|
||||
import {useState} from 'react'
|
||||
import {ChevronDown} from '@/assets/chevron-down'
|
||||
import {IconButton} from '@/components/ui/icon-button'
|
||||
import {languages, SupportedLanguageCode} from '@/utils/language'
|
||||
import {useLanguage} from '@/hooks/use-language'
|
||||
import {
|
||||
DropdownMenu,
|
||||
@@ -11,6 +10,7 @@ import {
|
||||
DropdownMenuContent,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/shadcn-components/ui/dropdown-menu'
|
||||
import {languages, SupportedLanguageCode} from '@/utils/language'
|
||||
|
||||
export function LanguageDropdown() {
|
||||
return (
|
||||
@@ -47,7 +47,12 @@ export function LanguageDropdownContent() {
|
||||
return (
|
||||
<DropdownMenuContent align='end'>
|
||||
{languages.map(({code, name}) => (
|
||||
<DropdownMenuCheckboxItem key={code} checked={temporaryCode === code} onSelect={() => changeLanguage(code)} disabled={temporaryCode !== activeCode}>
|
||||
<DropdownMenuCheckboxItem
|
||||
key={code}
|
||||
checked={temporaryCode === code}
|
||||
onSelect={() => changeLanguage(code)}
|
||||
disabled={temporaryCode !== activeCode}
|
||||
>
|
||||
{name}
|
||||
</DropdownMenuCheckboxItem>
|
||||
))}
|
||||
|
||||
@@ -124,7 +124,10 @@ export function SettingsContentMobile() {
|
||||
</Link>
|
||||
|
||||
<Card>
|
||||
<CpuTemperatureCardContent warning={cpuTemperature.warning} temperatureInCelcius={cpuTemperature.temperature} />
|
||||
<CpuTemperatureCardContent
|
||||
warning={cpuTemperature.warning}
|
||||
temperatureInCelcius={cpuTemperature.temperature}
|
||||
/>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ export function SettingsSummary() {
|
||||
<dt className='opacity-40'>{t('device')}</dt>
|
||||
<dd>{deviceInfo.data?.device || LOADING_DASH}</dd>
|
||||
<dt className='opacity-40'>{t('umbrelos')}</dt>
|
||||
<dd>{osVersionQ.isLoading ? LOADING_DASH : `${osVersionQ.data?.name}` ?? UNKNOWN()}</dd>
|
||||
<dd>{osVersionQ.isLoading ? LOADING_DASH : (`${osVersionQ.data?.name}` ?? UNKNOWN())}</dd>
|
||||
<dt className='opacity-40'>{t('local-ip')}</dt>
|
||||
<dd>
|
||||
{ipAddresses.data?.length
|
||||
@@ -37,7 +37,7 @@ export function SettingsSummary() {
|
||||
</Link>
|
||||
{index < ipAddresses.data.length - 1 && ', '}
|
||||
</Fragment>
|
||||
))
|
||||
))
|
||||
: LOADING_DASH}
|
||||
</dd>
|
||||
<dt className='opacity-40'>{t('uptime')}</dt>
|
||||
|
||||
@@ -30,7 +30,7 @@ const WallpaperItem = forwardRef(
|
||||
'h-6 shrink-0 bg-white/10 bg-cover bg-center outline-none ring-white/50 transition-all duration-200 focus-visible:ring-1',
|
||||
active
|
||||
? // NOTE: `mx-3` or whatever horizontal marging needs to be big enough to not cause the ring to get clipped from scrolling container
|
||||
'mx-3 rounded-5 ring-2 ring-white/50'
|
||||
'mx-3 rounded-5 ring-2 ring-white/50'
|
||||
: 'rounded-3',
|
||||
className,
|
||||
)}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import {useId, useState} from 'react'
|
||||
|
||||
import {listClass, ListRadioItem} from '@/components/ui/list'
|
||||
import {languages, SupportedLanguageCode} from '@/utils/language'
|
||||
import {useLanguage} from '@/hooks/use-language'
|
||||
import {useSettingsDialogProps} from '@/routes/settings/_components/shared'
|
||||
import {
|
||||
@@ -13,6 +12,7 @@ import {
|
||||
DrawerTitle,
|
||||
} from '@/shadcn-components/ui/drawer'
|
||||
import {t} from '@/utils/i18n'
|
||||
import {languages, SupportedLanguageCode} from '@/utils/language'
|
||||
import {sleep} from '@/utils/misc'
|
||||
|
||||
export function LanguageDrawer() {
|
||||
|
||||
Vendored
+16
-4
@@ -3,9 +3,21 @@
|
||||
|
||||
// https://github.com/lokesh/color-thief/issues/188#issuecomment-1166887824
|
||||
declare module 'colorthief' {
|
||||
export type RGBColor = [number, number, number];
|
||||
export type RGBColor = [number, number, number]
|
||||
export default class ColorThief {
|
||||
getColor: (img: HTMLImageElement | null, quality: number=10) => RGBColor | null;
|
||||
getPalette: (img: HTMLImageElement | null, colorCount: number=10, quality: number=10) => RGBColor[] | null;
|
||||
getColor: (
|
||||
/** The HTML image element. */
|
||||
img: HTMLImageElement | null,
|
||||
/** The quality level (default: 10). */
|
||||
quality?: number,
|
||||
) => RGBColor | null
|
||||
getPalette: (
|
||||
/** The HTML image element. */
|
||||
img: HTMLImageElement | null,
|
||||
/** The number of colors in the palette (default: 10). */
|
||||
colorCount?: number,
|
||||
/** The quality level (default: 10). */
|
||||
quality?: number,
|
||||
) => RGBColor[] | null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {formatDistanceStrict, Locale} from 'date-fns'
|
||||
import {de, enUS, es, fr, hu, it, ja, nl, pt, uk, tr} from 'date-fns/locale'
|
||||
import {de, enUS, es, fr, hu, it, ja, nl, pt, tr, uk} from 'date-fns/locale'
|
||||
|
||||
import {UNKNOWN} from '@/constants'
|
||||
import {SupportedLanguageCode} from '@/utils/language'
|
||||
|
||||
Generated
+32
-9
@@ -76,7 +76,7 @@
|
||||
"node-git-server": "^1.0.0",
|
||||
"nodemon": "^2.0.20",
|
||||
"opentimestamps": "^0.4.9",
|
||||
"prettier": "^2.8.1",
|
||||
"prettier": "3.3.3",
|
||||
"typescript": "^5.3.3",
|
||||
"vitest": "^2.1.2",
|
||||
"wait-port": "^1.0.4",
|
||||
@@ -8030,15 +8030,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.1.tgz",
|
||||
"integrity": "sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg==",
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz",
|
||||
"integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"prettier": "bin-prettier.js"
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||
@@ -11461,6 +11462,22 @@
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/xo/node_modules/prettier": {
|
||||
"version": "2.8.8",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
|
||||
"integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"prettier": "bin-prettier.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/xo/node_modules/queue-microtask": {
|
||||
"version": "1.2.3",
|
||||
"dev": true,
|
||||
@@ -17421,9 +17438,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"prettier": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.1.tgz",
|
||||
"integrity": "sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg==",
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz",
|
||||
"integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==",
|
||||
"dev": true
|
||||
},
|
||||
"prettier-linter-helpers": {
|
||||
@@ -19624,6 +19641,12 @@
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
},
|
||||
"prettier": {
|
||||
"version": "2.8.8",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
|
||||
"integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
|
||||
"dev": true
|
||||
},
|
||||
"queue-microtask": {
|
||||
"version": "1.2.3",
|
||||
"bundled": true,
|
||||
|
||||
@@ -33,14 +33,6 @@
|
||||
"generate-release-notes": "tsx scripts/generate-release-notes.ts",
|
||||
"todo": "git grep --line-number TODO -- ':!package.json'"
|
||||
},
|
||||
"prettier": {
|
||||
"printWidth": 120,
|
||||
"semi": false,
|
||||
"useTabs": true,
|
||||
"trailingComma": "all",
|
||||
"singleQuote": true,
|
||||
"bracketSpacing": false
|
||||
},
|
||||
"xo": {
|
||||
"prettier": true,
|
||||
"rules": {
|
||||
@@ -86,7 +78,7 @@
|
||||
"node-git-server": "^1.0.0",
|
||||
"nodemon": "^2.0.20",
|
||||
"opentimestamps": "^0.4.9",
|
||||
"prettier": "^2.8.1",
|
||||
"prettier": "3.3.3",
|
||||
"typescript": "^5.3.3",
|
||||
"vitest": "^2.1.2",
|
||||
"wait-port": "^1.0.4",
|
||||
|
||||
@@ -12,8 +12,8 @@ type DotProp<T, P extends string> = P extends `${infer K}.${infer R}`
|
||||
? DotProp<T[K], R>
|
||||
: never
|
||||
: P extends keyof T
|
||||
? T[P]
|
||||
: never
|
||||
? T[P]
|
||||
: never
|
||||
|
||||
type StorePath<T, P extends string> = DotProp<T, P> extends never ? 'The provided path does not exist in the store' : P
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import chalkTemplate from 'chalk-template'
|
||||
|
||||
const logLevels = ['silent', 'normal', 'verbose'] as const
|
||||
|
||||
export type LogLevel = typeof logLevels[number]
|
||||
export type LogLevel = (typeof logLevels)[number]
|
||||
|
||||
function value(logLevel: LogLevel) {
|
||||
return logLevels.indexOf(logLevel)
|
||||
|
||||
Reference in New Issue
Block a user