diff --git a/.github/workflows/build_release.yml b/.github/workflows/build_release.yml index 55208364db..850cf17183 100644 --- a/.github/workflows/build_release.yml +++ b/.github/workflows/build_release.yml @@ -20,7 +20,7 @@ jobs: build_docker: uses: ./.github/workflows/docker.yml with: - is_main_build: ${{ inputs.is_main_build }} + is_main_build: ${{ inputs.is_main_build || false }} permissions: contents: read packages: write diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1cd2927ce5..ac876a1833 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,5 +35,11 @@ jobs: - name: 📝 Prettier formatting run: pnpm lint:formatting + - name: 📝 Generate CSS types + run: pnpm test:generatecsstypes + - name: 💪 Type check run: pnpm test:typecheck + + - name: 📦 Build + run: pnpm build diff --git a/.gitignore b/.gitignore index e4512323a2..51a071534f 100644 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,5 @@ fly.toml /playwright-report/ /blob-report/ /playwright/.cache/ + +*.css.d.ts \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json index d55ea40c4d..fc984f7336 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -2,7 +2,7 @@ "recommendations": [ "ionic.ionic", "esbenp.prettier-vscode", - "styled-components.vscode-styled-components", - "github.vscode-github-actions" + "github.vscode-github-actions", + "clinyong.vscode-css-modules" ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index f662606e61..b2b8393e9d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,10 +7,10 @@ "source.fixAll.eslint": "explicit" }, "files.eol": "\n", - "eslint.codeActionsOnSave.rules": [ - "perfectionist/*" - ], "[shellscript]": { "editor.defaultFormatter": "foxundermoon.shell-format" - } -} \ No newline at end of file + }, + "eslint.codeActionsOnSave.rules": ["perfectionist/*"], + "css.lint.validProperties": ["composes"], + "css.lint.vendorPrefix": "ignore" +} diff --git a/android/capacitor.settings.gradle b/android/capacitor.settings.gradle index 56a8e6a0ad..63ad1aed7b 100644 --- a/android/capacitor.settings.gradle +++ b/android/capacitor.settings.gradle @@ -1,57 +1,57 @@ // DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN include ':capacitor-android' -project(':capacitor-android').projectDir = new File('../node_modules/.pnpm/@capacitor+android@6.1.2_@capacitor+core@6.1.2/node_modules/@capacitor/android/capacitor') +project(':capacitor-android').projectDir = new File('../node_modules/.pnpm/@capacitor+android@6.2.0_@capacitor+core@6.2.0/node_modules/@capacitor/android/capacitor') include ':capacitor-community-app-icon' -project(':capacitor-community-app-icon').projectDir = new File('../node_modules/.pnpm/@capacitor-community+app-icon@5.0.0_@capacitor+core@6.1.2/node_modules/@capacitor-community/app-icon/android') +project(':capacitor-community-app-icon').projectDir = new File('../node_modules/.pnpm/@capacitor-community+app-icon@5.0.0_@capacitor+core@6.2.0/node_modules/@capacitor-community/app-icon/android') include ':capacitor-app' -project(':capacitor-app').projectDir = new File('../node_modules/.pnpm/@capacitor+app@6.0.1_@capacitor+core@6.1.2/node_modules/@capacitor/app/android') +project(':capacitor-app').projectDir = new File('../node_modules/.pnpm/@capacitor+app@6.0.2_@capacitor+core@6.2.0/node_modules/@capacitor/app/android') include ':capacitor-filesystem' -project(':capacitor-filesystem').projectDir = new File('../node_modules/.pnpm/@capacitor+filesystem@6.0.1_@capacitor+core@6.1.2/node_modules/@capacitor/filesystem/android') +project(':capacitor-filesystem').projectDir = new File('../node_modules/.pnpm/@capacitor+filesystem@6.0.2_@capacitor+core@6.2.0/node_modules/@capacitor/filesystem/android') include ':capacitor-haptics' -project(':capacitor-haptics').projectDir = new File('../node_modules/.pnpm/@capacitor+haptics@6.0.1_patch_hash=isktf3ewuigcwl72katxy46idi_@capacitor+core@6.1.2/node_modules/@capacitor/haptics/android') +project(':capacitor-haptics').projectDir = new File('../node_modules/.pnpm/@capacitor+haptics@6.0.2_patch_hash=isktf3ewuigcwl72katxy46idi_@capacitor+core@6.2.0/node_modules/@capacitor/haptics/android') include ':capacitor-keyboard' -project(':capacitor-keyboard').projectDir = new File('../node_modules/.pnpm/@capacitor+keyboard@6.0.2_patch_hash=2ihcxo2fu55l7b6g5u7feswwlm_@capacitor+core@6.1.2/node_modules/@capacitor/keyboard/android') +project(':capacitor-keyboard').projectDir = new File('../node_modules/.pnpm/@capacitor+keyboard@6.0.3_patch_hash=2ihcxo2fu55l7b6g5u7feswwlm_@capacitor+core@6.2.0/node_modules/@capacitor/keyboard/android') include ':capacitor-network' -project(':capacitor-network').projectDir = new File('../node_modules/.pnpm/@capacitor+network@6.0.2_@capacitor+core@6.1.2/node_modules/@capacitor/network/android') +project(':capacitor-network').projectDir = new File('../node_modules/.pnpm/@capacitor+network@6.0.3_@capacitor+core@6.2.0/node_modules/@capacitor/network/android') include ':capacitor-share' -project(':capacitor-share').projectDir = new File('../node_modules/.pnpm/@capacitor+share@6.0.2_@capacitor+core@6.1.2/node_modules/@capacitor/share/android') +project(':capacitor-share').projectDir = new File('../node_modules/.pnpm/@capacitor+share@6.0.3_@capacitor+core@6.2.0/node_modules/@capacitor/share/android') include ':capacitor-splash-screen' -project(':capacitor-splash-screen').projectDir = new File('../node_modules/.pnpm/@capacitor+splash-screen@6.0.2_@capacitor+core@6.1.2/node_modules/@capacitor/splash-screen/android') +project(':capacitor-splash-screen').projectDir = new File('../node_modules/.pnpm/@capacitor+splash-screen@6.0.3_@capacitor+core@6.2.0/node_modules/@capacitor/splash-screen/android') include ':capacitor-status-bar' -project(':capacitor-status-bar').projectDir = new File('../node_modules/.pnpm/@capacitor+status-bar@6.0.1_@capacitor+core@6.1.2/node_modules/@capacitor/status-bar/android') +project(':capacitor-status-bar').projectDir = new File('../node_modules/.pnpm/@capacitor+status-bar@6.0.2_@capacitor+core@6.2.0/node_modules/@capacitor/status-bar/android') include ':capacitor-android-nav-mode' -project(':capacitor-android-nav-mode').projectDir = new File('../node_modules/.pnpm/capacitor-android-nav-mode@1.0.0_@capacitor+core@6.1.2/node_modules/capacitor-android-nav-mode/android') +project(':capacitor-android-nav-mode').projectDir = new File('../node_modules/.pnpm/capacitor-android-nav-mode@1.0.0_@capacitor+core@6.2.0/node_modules/capacitor-android-nav-mode/android') include ':capacitor-application-context' -project(':capacitor-application-context').projectDir = new File('../node_modules/.pnpm/capacitor-application-context@1.0.0_@capacitor+core@6.1.2/node_modules/capacitor-application-context/android') +project(':capacitor-application-context').projectDir = new File('../node_modules/.pnpm/capacitor-application-context@1.0.0_@capacitor+core@6.2.0/node_modules/capacitor-application-context/android') include ':capacitor-biometric-lock' -project(':capacitor-biometric-lock').projectDir = new File('../node_modules/.pnpm/capacitor-biometric-lock@1.0.0_@capacitor+core@6.1.2/node_modules/capacitor-biometric-lock/android') +project(':capacitor-biometric-lock').projectDir = new File('../node_modules/.pnpm/capacitor-biometric-lock@1.0.0_@capacitor+core@6.2.0/node_modules/capacitor-biometric-lock/android') include ':capacitor-clear-cache' -project(':capacitor-clear-cache').projectDir = new File('../node_modules/.pnpm/capacitor-clear-cache@1.0.1_@capacitor+core@6.1.2/node_modules/capacitor-clear-cache/android') +project(':capacitor-clear-cache').projectDir = new File('../node_modules/.pnpm/capacitor-clear-cache@1.0.1_@capacitor+core@6.2.0/node_modules/capacitor-clear-cache/android') include ':capacitor-launch-native' -project(':capacitor-launch-native').projectDir = new File('../node_modules/.pnpm/capacitor-launch-native@1.0.0_@capacitor+core@6.1.2/node_modules/capacitor-launch-native/android') +project(':capacitor-launch-native').projectDir = new File('../node_modules/.pnpm/capacitor-launch-native@1.0.0_@capacitor+core@6.2.0/node_modules/capacitor-launch-native/android') include ':capacitor-plugin-safe-area' -project(':capacitor-plugin-safe-area').projectDir = new File('../node_modules/.pnpm/capacitor-plugin-safe-area@3.0.3_@capacitor+core@6.1.2/node_modules/capacitor-plugin-safe-area/android') +project(':capacitor-plugin-safe-area').projectDir = new File('../node_modules/.pnpm/capacitor-plugin-safe-area@3.0.3_@capacitor+core@6.2.0/node_modules/capacitor-plugin-safe-area/android') include ':capacitor-reader' -project(':capacitor-reader').projectDir = new File('../node_modules/.pnpm/capacitor-reader@0.1.0_@capacitor+core@6.1.2/node_modules/capacitor-reader/android') +project(':capacitor-reader').projectDir = new File('../node_modules/.pnpm/capacitor-reader@0.2.0_@capacitor+core@6.2.0/node_modules/capacitor-reader/android') include ':capacitor-stash-media' -project(':capacitor-stash-media').projectDir = new File('../node_modules/.pnpm/capacitor-stash-media@2.0.1_@capacitor+core@6.1.2/node_modules/capacitor-stash-media/android') +project(':capacitor-stash-media').projectDir = new File('../node_modules/.pnpm/capacitor-stash-media@2.0.1_@capacitor+core@6.2.0/node_modules/capacitor-stash-media/android') include ':capacitor-tips' -project(':capacitor-tips').projectDir = new File('../node_modules/.pnpm/capacitor-tips@1.0.0_@capacitor+core@6.1.2/node_modules/capacitor-tips/android') +project(':capacitor-tips').projectDir = new File('../node_modules/.pnpm/capacitor-tips@1.0.0_@capacitor+core@6.2.0/node_modules/capacitor-tips/android') diff --git a/capacitor.config.ts b/capacitor.config.ts index 1c318d2930..efc2e8877d 100644 --- a/capacitor.config.ts +++ b/capacitor.config.ts @@ -15,6 +15,14 @@ const config: CapacitorConfig = { }, SplashScreen: { launchShowDuration: 3_000, + + // Important: Without this, the status bar color is grey in light mode + // https://github.com/ionic-team/capacitor-plugins/issues/1160 + launchFadeOutDuration: 0, + }, + CapacitorHttp: { + // Global shim is reverted in nativeFetch.ts + enabled: true, }, }, }; diff --git a/eslint.config.js b/eslint.config.js index 06025802cd..7fec0df90b 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -10,7 +10,6 @@ import vitestPlugin from "eslint-plugin-vitest"; import tseslint from "typescript-eslint"; import compilerOptions from "./compilerOptions.js"; -import packageJson from "./package.json" with { type: "json" }; export default tseslint.config( eslint.configs.recommended, @@ -108,18 +107,23 @@ export default tseslint.config( "warn", { newlinesBetween: "always", - ignoreCase: false, + partitionByComment: true, type: "natural", - internalPattern: Object.keys(packageJson.imports).map((i) => - i.endsWith("*") ? `${i}*` : i, - ), + ignoreCase: false, + tsconfigRootDir: ".", sortSideEffects: true, groups: [ "builtin", "external", "internal", ["parent", "sibling", "index"], + "css-modules", ], + customGroups: { + value: { + ["css-modules"]: ["\\.module\\.css$"], + }, + }, }, ], diff --git a/ios/App/Podfile b/ios/App/Podfile index 187e9e2245..6e17b88c38 100644 --- a/ios/App/Podfile +++ b/ios/App/Podfile @@ -1,4 +1,4 @@ -require_relative '../../node_modules/.pnpm/@capacitor+ios@6.1.2_@capacitor+core@6.1.2/node_modules/@capacitor/ios/scripts/pods_helpers' +require_relative '../../node_modules/.pnpm/@capacitor+ios@6.2.0_@capacitor+core@6.2.0/node_modules/@capacitor/ios/scripts/pods_helpers' platform :ios, '13.0' use_frameworks! @@ -9,26 +9,26 @@ use_frameworks! install! 'cocoapods', :disable_input_output_paths => true def capacitor_pods - pod 'Capacitor', :path => '../../node_modules/.pnpm/@capacitor+ios@6.1.2_@capacitor+core@6.1.2/node_modules/@capacitor/ios' - pod 'CapacitorCordova', :path => '../../node_modules/.pnpm/@capacitor+ios@6.1.2_@capacitor+core@6.1.2/node_modules/@capacitor/ios' - pod 'CapacitorCommunityAppIcon', :path => '../../node_modules/.pnpm/@capacitor-community+app-icon@5.0.0_@capacitor+core@6.1.2/node_modules/@capacitor-community/app-icon' - pod 'CapacitorApp', :path => '../../node_modules/.pnpm/@capacitor+app@6.0.1_@capacitor+core@6.1.2/node_modules/@capacitor/app' - pod 'CapacitorFilesystem', :path => '../../node_modules/.pnpm/@capacitor+filesystem@6.0.1_@capacitor+core@6.1.2/node_modules/@capacitor/filesystem' - pod 'CapacitorHaptics', :path => '../../node_modules/.pnpm/@capacitor+haptics@6.0.1_patch_hash=isktf3ewuigcwl72katxy46idi_@capacitor+core@6.1.2/node_modules/@capacitor/haptics' - pod 'CapacitorKeyboard', :path => '../../node_modules/.pnpm/@capacitor+keyboard@6.0.2_patch_hash=2ihcxo2fu55l7b6g5u7feswwlm_@capacitor+core@6.1.2/node_modules/@capacitor/keyboard' - pod 'CapacitorNetwork', :path => '../../node_modules/.pnpm/@capacitor+network@6.0.2_@capacitor+core@6.1.2/node_modules/@capacitor/network' - pod 'CapacitorShare', :path => '../../node_modules/.pnpm/@capacitor+share@6.0.2_@capacitor+core@6.1.2/node_modules/@capacitor/share' - pod 'CapacitorSplashScreen', :path => '../../node_modules/.pnpm/@capacitor+splash-screen@6.0.2_@capacitor+core@6.1.2/node_modules/@capacitor/splash-screen' - pod 'CapacitorStatusBar', :path => '../../node_modules/.pnpm/@capacitor+status-bar@6.0.1_@capacitor+core@6.1.2/node_modules/@capacitor/status-bar' - pod 'CapacitorAndroidNavMode', :path => '../../node_modules/.pnpm/capacitor-android-nav-mode@1.0.0_@capacitor+core@6.1.2/node_modules/capacitor-android-nav-mode' - pod 'CapacitorApplicationContext', :path => '../../node_modules/.pnpm/capacitor-application-context@1.0.0_@capacitor+core@6.1.2/node_modules/capacitor-application-context' - pod 'CapacitorBiometricLock', :path => '../../node_modules/.pnpm/capacitor-biometric-lock@1.0.0_@capacitor+core@6.1.2/node_modules/capacitor-biometric-lock' - pod 'CapacitorClearCache', :path => '../../node_modules/.pnpm/capacitor-clear-cache@1.0.1_@capacitor+core@6.1.2/node_modules/capacitor-clear-cache' - pod 'CapacitorLaunchNative', :path => '../../node_modules/.pnpm/capacitor-launch-native@1.0.0_@capacitor+core@6.1.2/node_modules/capacitor-launch-native' - pod 'CapacitorPluginSafeArea', :path => '../../node_modules/.pnpm/capacitor-plugin-safe-area@3.0.3_@capacitor+core@6.1.2/node_modules/capacitor-plugin-safe-area' - pod 'CapacitorReader', :path => '../../node_modules/.pnpm/capacitor-reader@0.1.0_@capacitor+core@6.1.2/node_modules/capacitor-reader' - pod 'CapacitorStashMedia', :path => '../../node_modules/.pnpm/capacitor-stash-media@2.0.1_@capacitor+core@6.1.2/node_modules/capacitor-stash-media' - pod 'CapacitorTips', :path => '../../node_modules/.pnpm/capacitor-tips@1.0.0_@capacitor+core@6.1.2/node_modules/capacitor-tips' + pod 'Capacitor', :path => '../../node_modules/.pnpm/@capacitor+ios@6.2.0_@capacitor+core@6.2.0/node_modules/@capacitor/ios' + pod 'CapacitorCordova', :path => '../../node_modules/.pnpm/@capacitor+ios@6.2.0_@capacitor+core@6.2.0/node_modules/@capacitor/ios' + pod 'CapacitorCommunityAppIcon', :path => '../../node_modules/.pnpm/@capacitor-community+app-icon@5.0.0_@capacitor+core@6.2.0/node_modules/@capacitor-community/app-icon' + pod 'CapacitorApp', :path => '../../node_modules/.pnpm/@capacitor+app@6.0.2_@capacitor+core@6.2.0/node_modules/@capacitor/app' + pod 'CapacitorFilesystem', :path => '../../node_modules/.pnpm/@capacitor+filesystem@6.0.2_@capacitor+core@6.2.0/node_modules/@capacitor/filesystem' + pod 'CapacitorHaptics', :path => '../../node_modules/.pnpm/@capacitor+haptics@6.0.2_patch_hash=isktf3ewuigcwl72katxy46idi_@capacitor+core@6.2.0/node_modules/@capacitor/haptics' + pod 'CapacitorKeyboard', :path => '../../node_modules/.pnpm/@capacitor+keyboard@6.0.3_patch_hash=2ihcxo2fu55l7b6g5u7feswwlm_@capacitor+core@6.2.0/node_modules/@capacitor/keyboard' + pod 'CapacitorNetwork', :path => '../../node_modules/.pnpm/@capacitor+network@6.0.3_@capacitor+core@6.2.0/node_modules/@capacitor/network' + pod 'CapacitorShare', :path => '../../node_modules/.pnpm/@capacitor+share@6.0.3_@capacitor+core@6.2.0/node_modules/@capacitor/share' + pod 'CapacitorSplashScreen', :path => '../../node_modules/.pnpm/@capacitor+splash-screen@6.0.3_@capacitor+core@6.2.0/node_modules/@capacitor/splash-screen' + pod 'CapacitorStatusBar', :path => '../../node_modules/.pnpm/@capacitor+status-bar@6.0.2_@capacitor+core@6.2.0/node_modules/@capacitor/status-bar' + pod 'CapacitorAndroidNavMode', :path => '../../node_modules/.pnpm/capacitor-android-nav-mode@1.0.0_@capacitor+core@6.2.0/node_modules/capacitor-android-nav-mode' + pod 'CapacitorApplicationContext', :path => '../../node_modules/.pnpm/capacitor-application-context@1.0.0_@capacitor+core@6.2.0/node_modules/capacitor-application-context' + pod 'CapacitorBiometricLock', :path => '../../node_modules/.pnpm/capacitor-biometric-lock@1.0.0_@capacitor+core@6.2.0/node_modules/capacitor-biometric-lock' + pod 'CapacitorClearCache', :path => '../../node_modules/.pnpm/capacitor-clear-cache@1.0.1_@capacitor+core@6.2.0/node_modules/capacitor-clear-cache' + pod 'CapacitorLaunchNative', :path => '../../node_modules/.pnpm/capacitor-launch-native@1.0.0_@capacitor+core@6.2.0/node_modules/capacitor-launch-native' + pod 'CapacitorPluginSafeArea', :path => '../../node_modules/.pnpm/capacitor-plugin-safe-area@3.0.3_@capacitor+core@6.2.0/node_modules/capacitor-plugin-safe-area' + pod 'CapacitorReader', :path => '../../node_modules/.pnpm/capacitor-reader@0.2.0_@capacitor+core@6.2.0/node_modules/capacitor-reader' + pod 'CapacitorStashMedia', :path => '../../node_modules/.pnpm/capacitor-stash-media@2.0.1_@capacitor+core@6.2.0/node_modules/capacitor-stash-media' + pod 'CapacitorTips', :path => '../../node_modules/.pnpm/capacitor-tips@1.0.0_@capacitor+core@6.2.0/node_modules/capacitor-tips' end target 'App' do diff --git a/ios/App/Podfile.lock b/ios/App/Podfile.lock index ca38d1b8f3..2025018e68 100644 --- a/ios/App/Podfile.lock +++ b/ios/App/Podfile.lock @@ -1,9 +1,9 @@ PODS: - - Capacitor (6.1.2): + - Capacitor (6.2.0): - CapacitorCordova - CapacitorAndroidNavMode (1.0.0): - Capacitor - - CapacitorApp (6.0.1): + - CapacitorApp (6.0.2): - Capacitor - CapacitorApplicationContext (1.0.0): - Capacitor @@ -13,57 +13,57 @@ PODS: - Capacitor - CapacitorCommunityAppIcon (5.0.0): - Capacitor - - CapacitorCordova (6.1.2) - - CapacitorFilesystem (6.0.1): + - CapacitorCordova (6.2.0) + - CapacitorFilesystem (6.0.2): - Capacitor - - CapacitorHaptics (6.0.1): + - CapacitorHaptics (6.0.2): - Capacitor - - CapacitorKeyboard (6.0.2): + - CapacitorKeyboard (6.0.3): - Capacitor - CapacitorLaunchNative (1.0.0): - Capacitor - - CapacitorNetwork (6.0.2): + - CapacitorNetwork (6.0.3): - Capacitor - CapacitorPluginSafeArea (3.0.3): - Capacitor - - CapacitorReader (0.1.0): + - CapacitorReader (0.2.0): - Capacitor - - CapacitorShare (6.0.2): + - CapacitorShare (6.0.3): - Capacitor - - CapacitorSplashScreen (6.0.2): + - CapacitorSplashScreen (6.0.3): - Capacitor - CapacitorStashMedia (2.0.1): - Capacitor - SDWebImage - - CapacitorStatusBar (6.0.1): + - CapacitorStatusBar (6.0.2): - Capacitor - CapacitorTips (1.0.0): - Capacitor - - SDWebImage (5.17.0): - - SDWebImage/Core (= 5.17.0) - - SDWebImage/Core (5.17.0) + - SDWebImage (5.18.7): + - SDWebImage/Core (= 5.18.7) + - SDWebImage/Core (5.18.7) DEPENDENCIES: - - "Capacitor (from `../../node_modules/.pnpm/@capacitor+ios@6.1.2_@capacitor+core@6.1.2/node_modules/@capacitor/ios`)" - - "CapacitorAndroidNavMode (from `../../node_modules/.pnpm/capacitor-android-nav-mode@1.0.0_@capacitor+core@6.1.2/node_modules/capacitor-android-nav-mode`)" - - "CapacitorApp (from `../../node_modules/.pnpm/@capacitor+app@6.0.1_@capacitor+core@6.1.2/node_modules/@capacitor/app`)" - - "CapacitorApplicationContext (from `../../node_modules/.pnpm/capacitor-application-context@1.0.0_@capacitor+core@6.1.2/node_modules/capacitor-application-context`)" - - "CapacitorBiometricLock (from `../../node_modules/.pnpm/capacitor-biometric-lock@1.0.0_@capacitor+core@6.1.2/node_modules/capacitor-biometric-lock`)" - - "CapacitorClearCache (from `../../node_modules/.pnpm/capacitor-clear-cache@1.0.1_@capacitor+core@6.1.2/node_modules/capacitor-clear-cache`)" - - "CapacitorCommunityAppIcon (from `../../node_modules/.pnpm/@capacitor-community+app-icon@5.0.0_@capacitor+core@6.1.2/node_modules/@capacitor-community/app-icon`)" - - "CapacitorCordova (from `../../node_modules/.pnpm/@capacitor+ios@6.1.2_@capacitor+core@6.1.2/node_modules/@capacitor/ios`)" - - "CapacitorFilesystem (from `../../node_modules/.pnpm/@capacitor+filesystem@6.0.1_@capacitor+core@6.1.2/node_modules/@capacitor/filesystem`)" - - "CapacitorHaptics (from `../../node_modules/.pnpm/@capacitor+haptics@6.0.1_patch_hash=isktf3ewuigcwl72katxy46idi_@capacitor+core@6.1.2/node_modules/@capacitor/haptics`)" - - "CapacitorKeyboard (from `../../node_modules/.pnpm/@capacitor+keyboard@6.0.2_patch_hash=2ihcxo2fu55l7b6g5u7feswwlm_@capacitor+core@6.1.2/node_modules/@capacitor/keyboard`)" - - "CapacitorLaunchNative (from `../../node_modules/.pnpm/capacitor-launch-native@1.0.0_@capacitor+core@6.1.2/node_modules/capacitor-launch-native`)" - - "CapacitorNetwork (from `../../node_modules/.pnpm/@capacitor+network@6.0.2_@capacitor+core@6.1.2/node_modules/@capacitor/network`)" - - "CapacitorPluginSafeArea (from `../../node_modules/.pnpm/capacitor-plugin-safe-area@3.0.3_@capacitor+core@6.1.2/node_modules/capacitor-plugin-safe-area`)" - - "CapacitorReader (from `../../node_modules/.pnpm/capacitor-reader@0.1.0_@capacitor+core@6.1.2/node_modules/capacitor-reader`)" - - "CapacitorShare (from `../../node_modules/.pnpm/@capacitor+share@6.0.2_@capacitor+core@6.1.2/node_modules/@capacitor/share`)" - - "CapacitorSplashScreen (from `../../node_modules/.pnpm/@capacitor+splash-screen@6.0.2_@capacitor+core@6.1.2/node_modules/@capacitor/splash-screen`)" - - "CapacitorStashMedia (from `../../node_modules/.pnpm/capacitor-stash-media@2.0.1_@capacitor+core@6.1.2/node_modules/capacitor-stash-media`)" - - "CapacitorStatusBar (from `../../node_modules/.pnpm/@capacitor+status-bar@6.0.1_@capacitor+core@6.1.2/node_modules/@capacitor/status-bar`)" - - "CapacitorTips (from `../../node_modules/.pnpm/capacitor-tips@1.0.0_@capacitor+core@6.1.2/node_modules/capacitor-tips`)" + - "Capacitor (from `../../node_modules/.pnpm/@capacitor+ios@6.2.0_@capacitor+core@6.2.0/node_modules/@capacitor/ios`)" + - "CapacitorAndroidNavMode (from `../../node_modules/.pnpm/capacitor-android-nav-mode@1.0.0_@capacitor+core@6.2.0/node_modules/capacitor-android-nav-mode`)" + - "CapacitorApp (from `../../node_modules/.pnpm/@capacitor+app@6.0.2_@capacitor+core@6.2.0/node_modules/@capacitor/app`)" + - "CapacitorApplicationContext (from `../../node_modules/.pnpm/capacitor-application-context@1.0.0_@capacitor+core@6.2.0/node_modules/capacitor-application-context`)" + - "CapacitorBiometricLock (from `../../node_modules/.pnpm/capacitor-biometric-lock@1.0.0_@capacitor+core@6.2.0/node_modules/capacitor-biometric-lock`)" + - "CapacitorClearCache (from `../../node_modules/.pnpm/capacitor-clear-cache@1.0.1_@capacitor+core@6.2.0/node_modules/capacitor-clear-cache`)" + - "CapacitorCommunityAppIcon (from `../../node_modules/.pnpm/@capacitor-community+app-icon@5.0.0_@capacitor+core@6.2.0/node_modules/@capacitor-community/app-icon`)" + - "CapacitorCordova (from `../../node_modules/.pnpm/@capacitor+ios@6.2.0_@capacitor+core@6.2.0/node_modules/@capacitor/ios`)" + - "CapacitorFilesystem (from `../../node_modules/.pnpm/@capacitor+filesystem@6.0.2_@capacitor+core@6.2.0/node_modules/@capacitor/filesystem`)" + - "CapacitorHaptics (from `../../node_modules/.pnpm/@capacitor+haptics@6.0.2_patch_hash=isktf3ewuigcwl72katxy46idi_@capacitor+core@6.2.0/node_modules/@capacitor/haptics`)" + - "CapacitorKeyboard (from `../../node_modules/.pnpm/@capacitor+keyboard@6.0.3_patch_hash=2ihcxo2fu55l7b6g5u7feswwlm_@capacitor+core@6.2.0/node_modules/@capacitor/keyboard`)" + - "CapacitorLaunchNative (from `../../node_modules/.pnpm/capacitor-launch-native@1.0.0_@capacitor+core@6.2.0/node_modules/capacitor-launch-native`)" + - "CapacitorNetwork (from `../../node_modules/.pnpm/@capacitor+network@6.0.3_@capacitor+core@6.2.0/node_modules/@capacitor/network`)" + - "CapacitorPluginSafeArea (from `../../node_modules/.pnpm/capacitor-plugin-safe-area@3.0.3_@capacitor+core@6.2.0/node_modules/capacitor-plugin-safe-area`)" + - "CapacitorReader (from `../../node_modules/.pnpm/capacitor-reader@0.2.0_@capacitor+core@6.2.0/node_modules/capacitor-reader`)" + - "CapacitorShare (from `../../node_modules/.pnpm/@capacitor+share@6.0.3_@capacitor+core@6.2.0/node_modules/@capacitor/share`)" + - "CapacitorSplashScreen (from `../../node_modules/.pnpm/@capacitor+splash-screen@6.0.3_@capacitor+core@6.2.0/node_modules/@capacitor/splash-screen`)" + - "CapacitorStashMedia (from `../../node_modules/.pnpm/capacitor-stash-media@2.0.1_@capacitor+core@6.2.0/node_modules/capacitor-stash-media`)" + - "CapacitorStatusBar (from `../../node_modules/.pnpm/@capacitor+status-bar@6.0.2_@capacitor+core@6.2.0/node_modules/@capacitor/status-bar`)" + - "CapacitorTips (from `../../node_modules/.pnpm/capacitor-tips@1.0.0_@capacitor+core@6.2.0/node_modules/capacitor-tips`)" SPEC REPOS: trunk: @@ -71,69 +71,69 @@ SPEC REPOS: EXTERNAL SOURCES: Capacitor: - :path: "../../node_modules/.pnpm/@capacitor+ios@6.1.2_@capacitor+core@6.1.2/node_modules/@capacitor/ios" + :path: "../../node_modules/.pnpm/@capacitor+ios@6.2.0_@capacitor+core@6.2.0/node_modules/@capacitor/ios" CapacitorAndroidNavMode: - :path: "../../node_modules/.pnpm/capacitor-android-nav-mode@1.0.0_@capacitor+core@6.1.2/node_modules/capacitor-android-nav-mode" + :path: "../../node_modules/.pnpm/capacitor-android-nav-mode@1.0.0_@capacitor+core@6.2.0/node_modules/capacitor-android-nav-mode" CapacitorApp: - :path: "../../node_modules/.pnpm/@capacitor+app@6.0.1_@capacitor+core@6.1.2/node_modules/@capacitor/app" + :path: "../../node_modules/.pnpm/@capacitor+app@6.0.2_@capacitor+core@6.2.0/node_modules/@capacitor/app" CapacitorApplicationContext: - :path: "../../node_modules/.pnpm/capacitor-application-context@1.0.0_@capacitor+core@6.1.2/node_modules/capacitor-application-context" + :path: "../../node_modules/.pnpm/capacitor-application-context@1.0.0_@capacitor+core@6.2.0/node_modules/capacitor-application-context" CapacitorBiometricLock: - :path: "../../node_modules/.pnpm/capacitor-biometric-lock@1.0.0_@capacitor+core@6.1.2/node_modules/capacitor-biometric-lock" + :path: "../../node_modules/.pnpm/capacitor-biometric-lock@1.0.0_@capacitor+core@6.2.0/node_modules/capacitor-biometric-lock" CapacitorClearCache: - :path: "../../node_modules/.pnpm/capacitor-clear-cache@1.0.1_@capacitor+core@6.1.2/node_modules/capacitor-clear-cache" + :path: "../../node_modules/.pnpm/capacitor-clear-cache@1.0.1_@capacitor+core@6.2.0/node_modules/capacitor-clear-cache" CapacitorCommunityAppIcon: - :path: "../../node_modules/.pnpm/@capacitor-community+app-icon@5.0.0_@capacitor+core@6.1.2/node_modules/@capacitor-community/app-icon" + :path: "../../node_modules/.pnpm/@capacitor-community+app-icon@5.0.0_@capacitor+core@6.2.0/node_modules/@capacitor-community/app-icon" CapacitorCordova: - :path: "../../node_modules/.pnpm/@capacitor+ios@6.1.2_@capacitor+core@6.1.2/node_modules/@capacitor/ios" + :path: "../../node_modules/.pnpm/@capacitor+ios@6.2.0_@capacitor+core@6.2.0/node_modules/@capacitor/ios" CapacitorFilesystem: - :path: "../../node_modules/.pnpm/@capacitor+filesystem@6.0.1_@capacitor+core@6.1.2/node_modules/@capacitor/filesystem" + :path: "../../node_modules/.pnpm/@capacitor+filesystem@6.0.2_@capacitor+core@6.2.0/node_modules/@capacitor/filesystem" CapacitorHaptics: - :path: "../../node_modules/.pnpm/@capacitor+haptics@6.0.1_patch_hash=isktf3ewuigcwl72katxy46idi_@capacitor+core@6.1.2/node_modules/@capacitor/haptics" + :path: "../../node_modules/.pnpm/@capacitor+haptics@6.0.2_patch_hash=isktf3ewuigcwl72katxy46idi_@capacitor+core@6.2.0/node_modules/@capacitor/haptics" CapacitorKeyboard: - :path: "../../node_modules/.pnpm/@capacitor+keyboard@6.0.2_patch_hash=2ihcxo2fu55l7b6g5u7feswwlm_@capacitor+core@6.1.2/node_modules/@capacitor/keyboard" + :path: "../../node_modules/.pnpm/@capacitor+keyboard@6.0.3_patch_hash=2ihcxo2fu55l7b6g5u7feswwlm_@capacitor+core@6.2.0/node_modules/@capacitor/keyboard" CapacitorLaunchNative: - :path: "../../node_modules/.pnpm/capacitor-launch-native@1.0.0_@capacitor+core@6.1.2/node_modules/capacitor-launch-native" + :path: "../../node_modules/.pnpm/capacitor-launch-native@1.0.0_@capacitor+core@6.2.0/node_modules/capacitor-launch-native" CapacitorNetwork: - :path: "../../node_modules/.pnpm/@capacitor+network@6.0.2_@capacitor+core@6.1.2/node_modules/@capacitor/network" + :path: "../../node_modules/.pnpm/@capacitor+network@6.0.3_@capacitor+core@6.2.0/node_modules/@capacitor/network" CapacitorPluginSafeArea: - :path: "../../node_modules/.pnpm/capacitor-plugin-safe-area@3.0.3_@capacitor+core@6.1.2/node_modules/capacitor-plugin-safe-area" + :path: "../../node_modules/.pnpm/capacitor-plugin-safe-area@3.0.3_@capacitor+core@6.2.0/node_modules/capacitor-plugin-safe-area" CapacitorReader: - :path: "../../node_modules/.pnpm/capacitor-reader@0.1.0_@capacitor+core@6.1.2/node_modules/capacitor-reader" + :path: "../../node_modules/.pnpm/capacitor-reader@0.2.0_@capacitor+core@6.2.0/node_modules/capacitor-reader" CapacitorShare: - :path: "../../node_modules/.pnpm/@capacitor+share@6.0.2_@capacitor+core@6.1.2/node_modules/@capacitor/share" + :path: "../../node_modules/.pnpm/@capacitor+share@6.0.3_@capacitor+core@6.2.0/node_modules/@capacitor/share" CapacitorSplashScreen: - :path: "../../node_modules/.pnpm/@capacitor+splash-screen@6.0.2_@capacitor+core@6.1.2/node_modules/@capacitor/splash-screen" + :path: "../../node_modules/.pnpm/@capacitor+splash-screen@6.0.3_@capacitor+core@6.2.0/node_modules/@capacitor/splash-screen" CapacitorStashMedia: - :path: "../../node_modules/.pnpm/capacitor-stash-media@2.0.1_@capacitor+core@6.1.2/node_modules/capacitor-stash-media" + :path: "../../node_modules/.pnpm/capacitor-stash-media@2.0.1_@capacitor+core@6.2.0/node_modules/capacitor-stash-media" CapacitorStatusBar: - :path: "../../node_modules/.pnpm/@capacitor+status-bar@6.0.1_@capacitor+core@6.1.2/node_modules/@capacitor/status-bar" + :path: "../../node_modules/.pnpm/@capacitor+status-bar@6.0.2_@capacitor+core@6.2.0/node_modules/@capacitor/status-bar" CapacitorTips: - :path: "../../node_modules/.pnpm/capacitor-tips@1.0.0_@capacitor+core@6.1.2/node_modules/capacitor-tips" + :path: "../../node_modules/.pnpm/capacitor-tips@1.0.0_@capacitor+core@6.2.0/node_modules/capacitor-tips" SPEC CHECKSUMS: - Capacitor: 679f9673fdf30597493a6362a5d5bf233d46abc2 + Capacitor: 1f3c7b9802d958cd8c4eb63895fff85dff2e1eea CapacitorAndroidNavMode: 94c169757cc0e9b82d7af168a5e59283e4bcc885 - CapacitorApp: 0bc633b4eae40a1f32cd2834788fad3bc42da6a1 + CapacitorApp: 2a8c3a0b0814322e5e6e15fe595f02c3808f0f8b CapacitorApplicationContext: 2bee68107e6efb8f89b5db102dc95a9cf74c9464 CapacitorBiometricLock: a91f2e8b28527e0d98032270f9363c4844abf1b9 CapacitorClearCache: 66a0b1bd6ed2d130d1c5467d3c001486cc1aa1eb CapacitorCommunityAppIcon: 4873c7de4cd50e68a36e08fe93f88f479e7b16a2 - CapacitorCordova: f48c89f96c319101cd2f0ce8a2b7449b5fb8b3dd - CapacitorFilesystem: 37fb3aa5c945b4539ab11c74a5c57925a302bf24 - CapacitorHaptics: fe689ade56ef20ec9b041a753c6da70c5d8ec9a9 - CapacitorKeyboard: 2700f9b18687be021e28b5a09b59eb151a46d5e0 + CapacitorCordova: b33e7f4aa4ed105dd43283acdd940964374a87d9 + CapacitorFilesystem: c832a3f6d4870c3872688e782ae8e33665e6ecbf + CapacitorHaptics: b53409aaca1203f79c6d0eb3ed5de40556339518 + CapacitorKeyboard: 460c6f9ec5e52c84f2742d5ce2e67bbc7ab0ebb0 CapacitorLaunchNative: 6508ec892ad035d5556658c10cc3b55bfbb7929d - CapacitorNetwork: 8796cf1f1104a00b289957b6150b7c60e1c2a8d3 + CapacitorNetwork: da96b5fff8d05b67f4658503aabb22f65bda2c0f CapacitorPluginSafeArea: e1eca7f70974f0e270d96f70cd0a5f51523164b1 - CapacitorReader: 6dbaa64adfbcaafe6713758078c3d510b2231083 - CapacitorShare: 591ae4693d85686ceb590db8e8b44aa014ec6490 - CapacitorSplashScreen: 250df9ef8014fac5c7c1fd231f0f8b1d8f0b5624 + CapacitorReader: 03775fab36b94587953bafcaa7131ade10cbf391 + CapacitorShare: 7af6ca761ce62030e8e9fbd2eb82416f5ceced38 + CapacitorSplashScreen: 68893659d77b5f82d753b3a70475082845e3039c CapacitorStashMedia: 10aa96dc5f874c4c27642528a4c327c46792abf2 - CapacitorStatusBar: b81d4fb5d4e0064c712018071b3ab4b810b39a63 + CapacitorStatusBar: 3b9ac7d0684770522c532d1158a1434512ab1477 CapacitorTips: 2087733aea06ec041b210085395ca934c8554907 - SDWebImage: 750adf017a315a280c60fde706ab1e552a3ae4e9 + SDWebImage: f9258c58221ed854cfa0e2b80ee4033710b1c6d3 -PODFILE CHECKSUM: 6b3917369f289c038252d105fb0992ec312a864c +PODFILE CHECKSUM: 810e83271706ad233eac03b47e2284efbdcfc205 COCOAPODS: 1.16.2 diff --git a/ios/App/VoyagerWatch Watch App/WatchSessionManager.swift b/ios/App/VoyagerWatch Watch App/WatchSessionManager.swift index 552e3c30ba..5d2b213f98 100644 --- a/ios/App/VoyagerWatch Watch App/WatchSessionManager.swift +++ b/ios/App/VoyagerWatch Watch App/WatchSessionManager.swift @@ -11,7 +11,7 @@ import WatchConnectivity class WatchSessionManager: NSObject, ObservableObject { static let shared = WatchSessionManager() - @Published var connectedInstance = "lemmy.world" // Variable to hold connected server hostname (optional) + @Published var connectedInstance = "lemm.ee" // Variable to hold connected server hostname (optional) @Published var authToken: String? // Variable to hold the auth token (optional) var loggedIn: Bool { diff --git a/package.json b/package.json index 5cb2d8edb1..010571ab9f 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "voyager", "description": "A progressive webapp Lemmy client", "private": true, - "version": "2.20.0", + "version": "2.21.1", "type": "module", "packageManager": "pnpm@9.12.2+sha512.22721b3a11f81661ae1ec68ce1a7b879425a1ca5b991c975b074ac220b187ce56c708fe5db69f4c962c989452eee76c82877f4ee80f474cebd61ee13461b6228", "scripts": { @@ -13,6 +13,7 @@ "preview": "vite preview", "test": "vitest", "test:e2e": "playwright test", + "test:generatecsstypes": "tcm src", "test:typecheck": "tsc", "lint": "eslint src --max-warnings=0", "lint:fix": "eslint src --max-warnings=0 --fix", @@ -24,18 +25,19 @@ "capacitor:copy:before": "rm -rf $CAPACITOR_WEB_DIR/splash && rm -rf $CAPACITOR_WEB_DIR/screenshots", "upgrade:packageManager": "corepack use pnpm@latest", "upgrade:react": "pnpm i --save react@experimental react-dom@experimental babel-plugin-react-compiler@experimental eslint-plugin-react-compiler@experimental eslint-plugin-react-hooks@experimental", - "release": "release-it && echo 'Version successfully bumped, but release not yet cut!' && ./scripts/postrelease.sh" + "release": "./scripts/prerelease.sh" }, "imports": { "#/*": "./src/*" }, "pnpm": { "overrides": { - "@ionic/core": "npm:voyager-ionic-core@8.4.0" + "@ionic/core": "npm:voyager-ionic-core@8.4.1" }, "patchedDependencies": { "@capacitor/haptics": "patches/@capacitor__haptics@6.0.1.patch", - "@capacitor/keyboard": "patches/@capacitor__keyboard@6.0.2.patch" + "@capacitor/keyboard": "patches/@capacitor__keyboard@6.0.2.patch", + "@capacitor/android": "patches/@capacitor__android.patch" }, "updateConfig": { "ignoreDependencies": [ @@ -52,40 +54,38 @@ "dependencies": { "@aeharding/remark-lemmy-spoiler": "^2.0.0", "@capacitor-community/app-icon": "^5.0.0", - "@capacitor/android": "^6.1.2", - "@capacitor/app": "^6.0.1", - "@capacitor/core": "^6.1.2", - "@capacitor/filesystem": "^6.0.1", - "@capacitor/haptics": "^6.0.1", - "@capacitor/ios": "^6.1.2", - "@capacitor/keyboard": "^6.0.2", - "@capacitor/network": "^6.0.2", - "@capacitor/share": "^6.0.2", - "@capacitor/splash-screen": "^6.0.2", - "@capacitor/status-bar": "^6.0.1", + "@capacitor/android": "^6.2.0", + "@capacitor/app": "^6.0.2", + "@capacitor/core": "^6.2.0", + "@capacitor/filesystem": "^6.0.2", + "@capacitor/haptics": "^6.0.2", + "@capacitor/ios": "^6.2.0", + "@capacitor/keyboard": "^6.0.3", + "@capacitor/network": "^6.0.3", + "@capacitor/share": "^6.0.3", + "@capacitor/splash-screen": "^6.0.3", + "@capacitor/status-bar": "^6.0.2", "@github/markdown-toolbar-element": "^2.2.3", - "@ionic/core": "npm:voyager-ionic-core@8.4.0", - "@ionic/react": "8.4.0", - "@ionic/react-router": "8.4.0", - "@linaria/core": "^6.2.0", - "@linaria/react": "^6.2.1", - "@mantine/hooks": "^7.14.0", - "@reduxjs/toolkit": "^2.3.0", + "@ionic/core": "npm:voyager-ionic-core@8.4.1", + "@ionic/react": "8.4.1", + "@ionic/react-router": "8.4.1", + "@mantine/hooks": "^7.14.3", + "@reduxjs/toolkit": "^2.4.0", "capacitor-android-nav-mode": "^1.0.0", "capacitor-application-context": "^1.0.0", "capacitor-biometric-lock": "^1.0.0", "capacitor-clear-cache": "^1.0.1", "capacitor-launch-native": "^1.0.0", "capacitor-plugin-safe-area": "^3.0.3", - "capacitor-reader": "^0.1.0", + "capacitor-reader": "^0.2.0", "capacitor-stash-media": "^2.0.1", "colorjs.io": "^0.5.2", "compare-versions": "^6.1.1", "date-fns": "^4.1.0", - "dexie": "^4.0.9", - "dexie-export-import": "^4.1.3", - "es-toolkit": "^1.27.0", - "eslint-plugin-perfectionist": "^3.9.1", + "dexie": "^4.0.10", + "dexie-export-import": "^4.1.4", + "es-toolkit": "^1.28.0", + "eslint-plugin-perfectionist": "^4.1.2", "history": "^4.10.1", "immer": "^10.1.1", "ionicons": "^7.4.0", @@ -98,9 +98,9 @@ "micromark-util-combine-extensions": "^2.0.1", "modern-screenshot": "^4.5.4", "photoswipe": "^5.4.4", - "react": "0.0.0-experimental-b01722d5-20241114", + "react": "0.0.0-experimental-7670501b-20241124", "react-animate-height": "^3.2.3", - "react-dom": "0.0.0-experimental-b01722d5-20241114", + "react-dom": "0.0.0-experimental-7670501b-20241124", "react-error-boundary": "^4.1.2", "react-intersection-observer": "^9.13.1", "react-markdown": "^9.0.1", @@ -116,49 +116,48 @@ "remark-parse": "^11.0.0", "remark-stringify": "^11.0.0", "remark-supersub-lemmy": "^1.0.0", - "ua-parser-js": "^1.0.39", + "ua-parser-js": "^2.0.0", "unified": "^11.0.5", "unist-util-visit": "^5.0.0", "use-long-press": "^3.2.0", - "virtua": "^0.37.0" + "virtua": "^0.38.1" }, "devDependencies": { - "@babel/preset-react": "^7.25.9", - "@babel/preset-typescript": "^7.26.0", - "@capacitor/cli": "^6.1.2", - "@eslint/js": "^9.14.0", + "@capacitor/cli": "^6.2.0", + "@eslint/js": "^9.16.0", "@ionic/cli": "^7.2.0", - "@playwright/test": "^1.48.2", + "@playwright/test": "^1.49.0", "@trapezedev/configure": "^7.1.3", "@types/history": "^4.7.11", "@types/mdast": "^4.0.4", - "@types/node": "^22.9.0", + "@types/node": "^22.10.1", "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", "@types/react-router": "^5.1.20", "@types/react-router-dom": "^5.3.3", "@types/ua-parser-js": "^0.7.39", - "@vitejs/plugin-legacy": "^5.4.3", - "@vitejs/plugin-react": "^4.3.3", - "@wyw-in-js/vite": "^0.5.5", - "babel-plugin-react-compiler": "0.0.0-experimental-19c7e06-20241113", - "eslint": "^9.14.0", + "@vitejs/plugin-legacy": "^6.0.0", + "@vitejs/plugin-react": "^4.3.4", + "autoprefixer": "^10.4.20", + "babel-plugin-react-compiler": "0.0.0-experimental-df7b47d-20241124", + "eslint": "^9.16.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-react": "^7.37.2", - "eslint-plugin-react-compiler": "0.0.0-experimental-19c7e06-20241113", - "eslint-plugin-react-hooks": "0.0.0-experimental-b01722d5-20241114", + "eslint-plugin-react-compiler": "0.0.0-experimental-df7b47d-20241124", + "eslint-plugin-react-hooks": "0.0.0-experimental-7670501b-20241124", "eslint-plugin-vitest": "^0.5.4", "jsdom": "^25.0.1", "mdast-util-lemmy-spoiler": "^2.0.0", - "prettier": "^3.3.3", + "postcss": "^8.4.49", + "prettier": "^3.4.1", "pwa-asset-generator": "^6.4.0", "release-it": "^17.10.0", - "typescript": "^5.6.3", - "typescript-eslint": "^8.14.0", - "vite": "^5.4.11", - "vite-plugin-pwa": "^0.21.0", + "typed-css-modules": "^0.9.1", + "typescript": "^5.7.2", + "typescript-eslint": "^8.16.0", + "vite": "^6.0.1", + "vite-plugin-pwa": "^0.21.1", "vite-plugin-svgr": "^4.3.0", - "vite-tsconfig-paths": "^5.1.2", - "vitest": "^2.1.5" + "vitest": "^2.1.6" } } diff --git a/patches/@capacitor__android.patch b/patches/@capacitor__android.patch new file mode 100644 index 0000000000..38ee05a22d --- /dev/null +++ b/patches/@capacitor__android.patch @@ -0,0 +1,13 @@ +diff --git a/capacitor/src/main/java/com/getcapacitor/Bridge.java b/capacitor/src/main/java/com/getcapacitor/Bridge.java +index 594146a0f8fc2903fd255c0b864db97d94ebfb1b..4f13ca78a4051e3b1bc5cd5d3de0e8a99aa44728 100644 +--- a/capacitor/src/main/java/com/getcapacitor/Bridge.java ++++ b/capacitor/src/main/java/com/getcapacitor/Bridge.java +@@ -417,7 +417,7 @@ public class Bridge { + PackageManager pm = getContext().getPackageManager(); + PackageInfo pInfo = InternalUtils.getPackageInfo(pm, getContext().getPackageName()); + versionCode = Integer.toString((int) PackageInfoCompat.getLongVersionCode(pInfo)); +- versionName = pInfo.versionName; ++ if (pInfo.versionName != null) versionName = pInfo.versionName; + } catch (Exception ex) { + Logger.error("Unable to get package info", ex); + } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 462c3b20d8..91b24b90c4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,9 +5,12 @@ settings: excludeLinksFromLockfile: false overrides: - '@ionic/core': npm:voyager-ionic-core@8.4.0 + '@ionic/core': npm:voyager-ionic-core@8.4.1 patchedDependencies: + '@capacitor/android': + hash: a7fuehdtpweg2aifrflzmu363i + path: patches/@capacitor__android.patch '@capacitor/haptics': hash: isktf3ewuigcwl72katxy46idi path: patches/@capacitor__haptics@6.0.1.patch @@ -24,88 +27,82 @@ importers: version: 2.0.0 '@capacitor-community/app-icon': specifier: ^5.0.0 - version: 5.0.0(@capacitor/core@6.1.2) + version: 5.0.0(@capacitor/core@6.2.0) '@capacitor/android': - specifier: ^6.1.2 - version: 6.1.2(@capacitor/core@6.1.2) + specifier: ^6.2.0 + version: 6.2.0(patch_hash=a7fuehdtpweg2aifrflzmu363i)(@capacitor/core@6.2.0) '@capacitor/app': - specifier: ^6.0.1 - version: 6.0.1(@capacitor/core@6.1.2) + specifier: ^6.0.2 + version: 6.0.2(@capacitor/core@6.2.0) '@capacitor/core': - specifier: ^6.1.2 - version: 6.1.2 + specifier: ^6.2.0 + version: 6.2.0 '@capacitor/filesystem': - specifier: ^6.0.1 - version: 6.0.1(@capacitor/core@6.1.2) + specifier: ^6.0.2 + version: 6.0.2(@capacitor/core@6.2.0) '@capacitor/haptics': - specifier: ^6.0.1 - version: 6.0.1(patch_hash=isktf3ewuigcwl72katxy46idi)(@capacitor/core@6.1.2) + specifier: ^6.0.2 + version: 6.0.2(patch_hash=isktf3ewuigcwl72katxy46idi)(@capacitor/core@6.2.0) '@capacitor/ios': - specifier: ^6.1.2 - version: 6.1.2(@capacitor/core@6.1.2) + specifier: ^6.2.0 + version: 6.2.0(@capacitor/core@6.2.0) '@capacitor/keyboard': - specifier: ^6.0.2 - version: 6.0.2(patch_hash=2ihcxo2fu55l7b6g5u7feswwlm)(@capacitor/core@6.1.2) + specifier: ^6.0.3 + version: 6.0.3(patch_hash=2ihcxo2fu55l7b6g5u7feswwlm)(@capacitor/core@6.2.0) '@capacitor/network': - specifier: ^6.0.2 - version: 6.0.2(@capacitor/core@6.1.2) + specifier: ^6.0.3 + version: 6.0.3(@capacitor/core@6.2.0) '@capacitor/share': - specifier: ^6.0.2 - version: 6.0.2(@capacitor/core@6.1.2) + specifier: ^6.0.3 + version: 6.0.3(@capacitor/core@6.2.0) '@capacitor/splash-screen': - specifier: ^6.0.2 - version: 6.0.2(@capacitor/core@6.1.2) + specifier: ^6.0.3 + version: 6.0.3(@capacitor/core@6.2.0) '@capacitor/status-bar': - specifier: ^6.0.1 - version: 6.0.1(@capacitor/core@6.1.2) + specifier: ^6.0.2 + version: 6.0.2(@capacitor/core@6.2.0) '@github/markdown-toolbar-element': specifier: ^2.2.3 version: 2.2.3 '@ionic/core': - specifier: npm:voyager-ionic-core@8.4.0 - version: voyager-ionic-core@8.4.0 + specifier: npm:voyager-ionic-core@8.4.1 + version: voyager-ionic-core@8.4.1 '@ionic/react': - specifier: 8.4.0 - version: 8.4.0(react-dom@0.0.0-experimental-b01722d5-20241114(react@0.0.0-experimental-b01722d5-20241114))(react@0.0.0-experimental-b01722d5-20241114) + specifier: 8.4.1 + version: 8.4.1(react-dom@0.0.0-experimental-7670501b-20241124(react@0.0.0-experimental-7670501b-20241124))(react@0.0.0-experimental-7670501b-20241124) '@ionic/react-router': - specifier: 8.4.0 - version: 8.4.0(react-dom@0.0.0-experimental-b01722d5-20241114(react@0.0.0-experimental-b01722d5-20241114))(react-router-dom@5.3.4(react@0.0.0-experimental-b01722d5-20241114))(react-router@5.3.4(react@0.0.0-experimental-b01722d5-20241114))(react@0.0.0-experimental-b01722d5-20241114) - '@linaria/core': - specifier: ^6.2.0 - version: 6.2.0 - '@linaria/react': - specifier: ^6.2.1 - version: 6.2.1(react@0.0.0-experimental-b01722d5-20241114) + specifier: 8.4.1 + version: 8.4.1(react-dom@0.0.0-experimental-7670501b-20241124(react@0.0.0-experimental-7670501b-20241124))(react-router-dom@5.3.4(react@0.0.0-experimental-7670501b-20241124))(react-router@5.3.4(react@0.0.0-experimental-7670501b-20241124))(react@0.0.0-experimental-7670501b-20241124) '@mantine/hooks': - specifier: ^7.14.0 - version: 7.14.0(react@0.0.0-experimental-b01722d5-20241114) + specifier: ^7.14.3 + version: 7.14.3(react@0.0.0-experimental-7670501b-20241124) '@reduxjs/toolkit': - specifier: ^2.3.0 - version: 2.3.0(react-redux@9.1.2(@types/react@18.3.12)(react@0.0.0-experimental-b01722d5-20241114)(redux@5.0.1))(react@0.0.0-experimental-b01722d5-20241114) + specifier: ^2.4.0 + version: 2.4.0(react-redux@9.1.2(@types/react@18.3.12)(react@0.0.0-experimental-7670501b-20241124)(redux@5.0.1))(react@0.0.0-experimental-7670501b-20241124) capacitor-android-nav-mode: specifier: ^1.0.0 - version: 1.0.0(@capacitor/core@6.1.2) + version: 1.0.0(@capacitor/core@6.2.0) capacitor-application-context: specifier: ^1.0.0 - version: 1.0.0(@capacitor/core@6.1.2) + version: 1.0.0(@capacitor/core@6.2.0) capacitor-biometric-lock: specifier: ^1.0.0 - version: 1.0.0(@capacitor/core@6.1.2) + version: 1.0.0(@capacitor/core@6.2.0) capacitor-clear-cache: specifier: ^1.0.1 - version: 1.0.1(@capacitor/core@6.1.2) + version: 1.0.1(@capacitor/core@6.2.0) capacitor-launch-native: specifier: ^1.0.0 - version: 1.0.0(@capacitor/core@6.1.2) + version: 1.0.0(@capacitor/core@6.2.0) capacitor-plugin-safe-area: specifier: ^3.0.3 - version: 3.0.3(@capacitor/core@6.1.2) + version: 3.0.3(@capacitor/core@6.2.0) capacitor-reader: - specifier: ^0.1.0 - version: 0.1.0(@capacitor/core@6.1.2) + specifier: ^0.2.0 + version: 0.2.0(@capacitor/core@6.2.0) capacitor-stash-media: specifier: ^2.0.1 - version: 2.0.1(@capacitor/core@6.1.2) + version: 2.0.1(@capacitor/core@6.2.0) colorjs.io: specifier: ^0.5.2 version: 0.5.2 @@ -116,17 +113,17 @@ importers: specifier: ^4.1.0 version: 4.1.0 dexie: - specifier: ^4.0.9 - version: 4.0.9 + specifier: ^4.0.10 + version: 4.0.10 dexie-export-import: - specifier: ^4.1.3 - version: 4.1.3(dexie@4.0.9) + specifier: ^4.1.4 + version: 4.1.4(dexie@4.0.10) es-toolkit: - specifier: ^1.27.0 - version: 1.27.0 + specifier: ^1.28.0 + version: 1.28.0 eslint-plugin-perfectionist: - specifier: ^3.9.1 - version: 3.9.1(eslint@9.14.0)(typescript@5.6.3) + specifier: ^4.1.2 + version: 4.1.2(eslint@9.16.0)(typescript@5.7.2) history: specifier: ^4.10.1 version: 4.10.1 @@ -164,41 +161,41 @@ importers: specifier: ^5.4.4 version: 5.4.4 react: - specifier: 0.0.0-experimental-b01722d5-20241114 - version: 0.0.0-experimental-b01722d5-20241114 + specifier: 0.0.0-experimental-7670501b-20241124 + version: 0.0.0-experimental-7670501b-20241124 react-animate-height: specifier: ^3.2.3 - version: 3.2.3(react-dom@0.0.0-experimental-b01722d5-20241114(react@0.0.0-experimental-b01722d5-20241114))(react@0.0.0-experimental-b01722d5-20241114) + version: 3.2.3(react-dom@0.0.0-experimental-7670501b-20241124(react@0.0.0-experimental-7670501b-20241124))(react@0.0.0-experimental-7670501b-20241124) react-dom: - specifier: 0.0.0-experimental-b01722d5-20241114 - version: 0.0.0-experimental-b01722d5-20241114(react@0.0.0-experimental-b01722d5-20241114) + specifier: 0.0.0-experimental-7670501b-20241124 + version: 0.0.0-experimental-7670501b-20241124(react@0.0.0-experimental-7670501b-20241124) react-error-boundary: specifier: ^4.1.2 - version: 4.1.2(react@0.0.0-experimental-b01722d5-20241114) + version: 4.1.2(react@0.0.0-experimental-7670501b-20241124) react-intersection-observer: specifier: ^9.13.1 - version: 9.13.1(react-dom@0.0.0-experimental-b01722d5-20241114(react@0.0.0-experimental-b01722d5-20241114))(react@0.0.0-experimental-b01722d5-20241114) + version: 9.13.1(react-dom@0.0.0-experimental-7670501b-20241124(react@0.0.0-experimental-7670501b-20241124))(react@0.0.0-experimental-7670501b-20241124) react-markdown: specifier: ^9.0.1 - version: 9.0.1(@types/react@18.3.12)(react@0.0.0-experimental-b01722d5-20241114) + version: 9.0.1(@types/react@18.3.12)(react@0.0.0-experimental-7670501b-20241124) react-redux: specifier: ^9.1.2 - version: 9.1.2(@types/react@18.3.12)(react@0.0.0-experimental-b01722d5-20241114)(redux@5.0.1) + version: 9.1.2(@types/react@18.3.12)(react@0.0.0-experimental-7670501b-20241124)(redux@5.0.1) react-reverse-portal: specifier: ^2.1.2 - version: 2.1.2(react-dom@0.0.0-experimental-b01722d5-20241114(react@0.0.0-experimental-b01722d5-20241114))(react@0.0.0-experimental-b01722d5-20241114) + version: 2.1.2(react-dom@0.0.0-experimental-7670501b-20241124(react@0.0.0-experimental-7670501b-20241124))(react@0.0.0-experimental-7670501b-20241124) react-router: specifier: ^5.3.4 - version: 5.3.4(react@0.0.0-experimental-b01722d5-20241114) + version: 5.3.4(react@0.0.0-experimental-7670501b-20241124) react-router-dom: specifier: ^5.3.4 - version: 5.3.4(react@0.0.0-experimental-b01722d5-20241114) + version: 5.3.4(react@0.0.0-experimental-7670501b-20241124) react-textarea-autosize: specifier: ^8.5.5 - version: 8.5.5(@types/react@18.3.12)(react@0.0.0-experimental-b01722d5-20241114) + version: 8.5.5(@types/react@18.3.12)(react@0.0.0-experimental-7670501b-20241124) react-transition-state: specifier: ^2.2.0 - version: 2.2.0(react-dom@0.0.0-experimental-b01722d5-20241114(react@0.0.0-experimental-b01722d5-20241114))(react@0.0.0-experimental-b01722d5-20241114) + version: 2.2.0(react-dom@0.0.0-experimental-7670501b-20241124(react@0.0.0-experimental-7670501b-20241124))(react@0.0.0-experimental-7670501b-20241124) rehype-highlight: specifier: ^6.0.0 version: 6.0.0 @@ -218,8 +215,8 @@ importers: specifier: ^1.0.0 version: 1.0.0 ua-parser-js: - specifier: ^1.0.39 - version: 1.0.39 + specifier: ^2.0.0 + version: 2.0.0 unified: specifier: ^11.0.5 version: 11.0.5 @@ -228,32 +225,26 @@ importers: version: 5.0.0 use-long-press: specifier: ^3.2.0 - version: 3.2.0(react@0.0.0-experimental-b01722d5-20241114) + version: 3.2.0(react@0.0.0-experimental-7670501b-20241124) virtua: - specifier: ^0.37.0 - version: 0.37.0(react-dom@0.0.0-experimental-b01722d5-20241114(react@0.0.0-experimental-b01722d5-20241114))(react@0.0.0-experimental-b01722d5-20241114) + specifier: ^0.38.1 + version: 0.38.1(react-dom@0.0.0-experimental-7670501b-20241124(react@0.0.0-experimental-7670501b-20241124))(react@0.0.0-experimental-7670501b-20241124) devDependencies: - '@babel/preset-react': - specifier: ^7.25.9 - version: 7.25.9(@babel/core@7.26.0) - '@babel/preset-typescript': - specifier: ^7.26.0 - version: 7.26.0(@babel/core@7.26.0) '@capacitor/cli': - specifier: ^6.1.2 - version: 6.1.2 + specifier: ^6.2.0 + version: 6.2.0 '@eslint/js': - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.16.0 + version: 9.16.0 '@ionic/cli': specifier: ^7.2.0 version: 7.2.0 '@playwright/test': - specifier: ^1.48.2 - version: 1.48.2 + specifier: ^1.49.0 + version: 1.49.0 '@trapezedev/configure': specifier: ^7.1.3 - version: 7.1.3(@types/node@22.9.0)(typescript@5.6.3) + version: 7.1.3(@types/node@22.10.1)(typescript@5.7.2) '@types/history': specifier: ^4.7.11 version: 4.7.11 @@ -261,8 +252,8 @@ importers: specifier: ^4.0.4 version: 4.0.4 '@types/node': - specifier: ^22.9.0 - version: 22.9.0 + specifier: ^22.10.1 + version: 22.10.1 '@types/react': specifier: ^18.3.12 version: 18.3.12 @@ -279,74 +270,80 @@ importers: specifier: ^0.7.39 version: 0.7.39 '@vitejs/plugin-legacy': - specifier: ^5.4.3 - version: 5.4.3(terser@5.36.0)(vite@5.4.11(@types/node@22.9.0)(terser@5.36.0)) + specifier: ^6.0.0 + version: 6.0.0(terser@5.36.0)(vite@6.0.1(@types/node@22.10.1)(less@4.2.0)(lightningcss@1.28.1)(sass@1.81.0)(stylus@0.62.0)(terser@5.36.0)) '@vitejs/plugin-react': - specifier: ^4.3.3 - version: 4.3.3(vite@5.4.11(@types/node@22.9.0)(terser@5.36.0)) - '@wyw-in-js/vite': - specifier: ^0.5.5 - version: 0.5.5(typescript@5.6.3)(vite@5.4.11(@types/node@22.9.0)(terser@5.36.0)) + specifier: ^4.3.4 + version: 4.3.4(vite@6.0.1(@types/node@22.10.1)(less@4.2.0)(lightningcss@1.28.1)(sass@1.81.0)(stylus@0.62.0)(terser@5.36.0)) + autoprefixer: + specifier: ^10.4.20 + version: 10.4.20(postcss@8.4.49) babel-plugin-react-compiler: - specifier: 0.0.0-experimental-19c7e06-20241113 - version: 0.0.0-experimental-19c7e06-20241113 + specifier: 0.0.0-experimental-df7b47d-20241124 + version: 0.0.0-experimental-df7b47d-20241124 eslint: - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.16.0 + version: 9.16.0 eslint-config-prettier: specifier: ^9.1.0 - version: 9.1.0(eslint@9.14.0) + version: 9.1.0(eslint@9.16.0) eslint-plugin-react: specifier: ^7.37.2 - version: 7.37.2(eslint@9.14.0) + version: 7.37.2(eslint@9.16.0) eslint-plugin-react-compiler: - specifier: 0.0.0-experimental-19c7e06-20241113 - version: 0.0.0-experimental-19c7e06-20241113(eslint@9.14.0) + specifier: 0.0.0-experimental-df7b47d-20241124 + version: 0.0.0-experimental-df7b47d-20241124(eslint@9.16.0) eslint-plugin-react-hooks: - specifier: 0.0.0-experimental-b01722d5-20241114 - version: 0.0.0-experimental-b01722d5-20241114(eslint@9.14.0) + specifier: 0.0.0-experimental-7670501b-20241124 + version: 0.0.0-experimental-7670501b-20241124(eslint@9.16.0) eslint-plugin-vitest: specifier: ^0.5.4 - version: 0.5.4(eslint@9.14.0)(typescript@5.6.3)(vitest@2.1.5(@types/node@22.9.0)(happy-dom@15.11.6)(jsdom@25.0.1)(terser@5.36.0)) + version: 0.5.4(eslint@9.16.0)(typescript@5.7.2)(vitest@2.1.6(@types/node@22.10.1)(happy-dom@15.11.6)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.28.1)(sass@1.81.0)(stylus@0.62.0)(terser@5.36.0)) jsdom: specifier: ^25.0.1 version: 25.0.1 mdast-util-lemmy-spoiler: specifier: ^2.0.0 version: 2.0.0 + postcss: + specifier: ^8.4.49 + version: 8.4.49 prettier: - specifier: ^3.3.3 - version: 3.3.3 + specifier: ^3.4.1 + version: 3.4.1 pwa-asset-generator: specifier: ^6.4.0 version: 6.4.0 release-it: specifier: ^17.10.0 - version: 17.10.0(typescript@5.6.3) + version: 17.10.0(typescript@5.7.2) + typed-css-modules: + specifier: ^0.9.1 + version: 0.9.1 typescript: - specifier: ^5.6.3 - version: 5.6.3 + specifier: ^5.7.2 + version: 5.7.2 typescript-eslint: - specifier: ^8.14.0 - version: 8.14.0(eslint@9.14.0)(typescript@5.6.3) + specifier: ^8.16.0 + version: 8.16.0(eslint@9.16.0)(typescript@5.7.2) vite: - specifier: ^5.4.11 - version: 5.4.11(@types/node@22.9.0)(terser@5.36.0) + specifier: ^6.0.1 + version: 6.0.1(@types/node@22.10.1)(less@4.2.0)(lightningcss@1.28.1)(sass@1.81.0)(stylus@0.62.0)(terser@5.36.0) vite-plugin-pwa: - specifier: ^0.21.0 - version: 0.21.0(vite@5.4.11(@types/node@22.9.0)(terser@5.36.0))(workbox-build@7.1.1(@types/babel__core@7.20.5))(workbox-window@7.3.0) + specifier: ^0.21.1 + version: 0.21.1(vite@6.0.1(@types/node@22.10.1)(less@4.2.0)(lightningcss@1.28.1)(sass@1.81.0)(stylus@0.62.0)(terser@5.36.0))(workbox-build@7.1.1(@types/babel__core@7.20.5))(workbox-window@7.3.0) vite-plugin-svgr: specifier: ^4.3.0 - version: 4.3.0(rollup@2.79.2)(typescript@5.6.3)(vite@5.4.11(@types/node@22.9.0)(terser@5.36.0)) - vite-tsconfig-paths: - specifier: ^5.1.2 - version: 5.1.2(typescript@5.6.3)(vite@5.4.11(@types/node@22.9.0)(terser@5.36.0)) + version: 4.3.0(rollup@2.79.2)(typescript@5.7.2)(vite@6.0.1(@types/node@22.10.1)(less@4.2.0)(lightningcss@1.28.1)(sass@1.81.0)(stylus@0.62.0)(terser@5.36.0)) vitest: - specifier: ^2.1.5 - version: 2.1.5(@types/node@22.9.0)(happy-dom@15.11.6)(jsdom@25.0.1)(terser@5.36.0) + specifier: ^2.1.6 + version: 2.1.6(@types/node@22.10.1)(happy-dom@15.11.6)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.28.1)(sass@1.81.0)(stylus@0.62.0)(terser@5.36.0) packages: + '@adobe/css-tools@4.3.3': + resolution: {integrity: sha512-rE0Pygv0sEZ4vBWHlAgJLGDU7Pm8xoO6p3wsEceb7GYAjScrOHpEo8KK/eVkAcnSM+slAEtXjA2JpdjLp4fJQQ==} + '@aeharding/remark-lemmy-spoiler@2.0.0': resolution: {integrity: sha512-Kw2LDXIeNyV2Ks1QXKYISEdwn4ufPev5gb4RzoSNSEUb1iL6aQmOUQvcuA7ePzXChNe6bmerkvJ2KKYXYaLYlQ==} @@ -502,13 +499,6 @@ packages: peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-proposal-private-methods@7.18.6': - resolution: {integrity: sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==} - engines: {node: '>=6.9.0'} - deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-methods instead. - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2': resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==} engines: {node: '>=6.9.0'} @@ -527,18 +517,6 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-jsx@7.25.9': - resolution: {integrity: sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-typescript@7.25.9': - resolution: {integrity: sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-unicode-sets-regex@7.18.6': resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} engines: {node: '>=6.9.0'} @@ -773,18 +751,6 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-display-name@7.25.9': - resolution: {integrity: sha512-KJfMlYIUxQB1CJfO3e0+h0ZHWOTLCPP115Awhaz8U0Zpq36Gl/cXlpoyMRnUWlhNUBAzldnCiAZNvCDj7CrKxQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx-development@7.25.9': - resolution: {integrity: sha512-9mj6rm7XVYs4mdLIpbZnHOYdpW42uoiBCTVowg7sP1thUOiANgMb4UtpRivR0pp5iL+ocvUv7X4mZgFRpJEzGw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-jsx-self@7.25.9': resolution: {integrity: sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg==} engines: {node: '>=6.9.0'} @@ -797,18 +763,6 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-jsx@7.25.9': - resolution: {integrity: sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-pure-annotations@7.25.9': - resolution: {integrity: sha512-KQ/Takk3T8Qzj5TppkS1be588lkbTp5uj7w6a0LeQaTMSckU/wK0oJ/pih+T690tkgI5jfmg2TqDJvd41Sj1Cg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-regenerator@7.25.9': resolution: {integrity: sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg==} engines: {node: '>=6.9.0'} @@ -857,12 +811,6 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-typescript@7.25.9': - resolution: {integrity: sha512-7PbZQZP50tzv2KGGnhh82GSyMB01yKY9scIjf1a+GfZCtInOWqUH5+1EBU4t9fyR5Oykkkc9vFTs4OHrhHXljQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-unicode-escapes@7.25.9': resolution: {integrity: sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==} engines: {node: '>=6.9.0'} @@ -898,18 +846,6 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 - '@babel/preset-react@7.25.9': - resolution: {integrity: sha512-D3to0uSPiWE7rBrdIICCd0tJSIGpLaaGptna2+w7Pft5xMqLpA1sz99DK5TZ1TjGbdQ/VI1eCSZ06dv3lT4JOw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/preset-typescript@7.26.0': - resolution: {integrity: sha512-NMk1IGZ5I/oHhoXEElcm+xUnL/szL6xflkFZmoEU9xj1qSJXpiS7rsspYo92B4DRCDvZn2erT5LdsCeXAKNCkg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/runtime@7.24.7': resolution: {integrity: sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==} engines: {node: '>=6.9.0'} @@ -939,61 +875,61 @@ packages: peerDependencies: '@capacitor/core': ^6.0.0 - '@capacitor/android@6.1.2': - resolution: {integrity: sha512-Yh0gQDY1bgRrL25J6ecIlvvs2kF8iNSwIPXjyw6Yz9mnwYxBazF5KZbjpKtGPnJgicJhFkYGsqOkEtxrve0EoQ==} + '@capacitor/android@6.2.0': + resolution: {integrity: sha512-3YIDPylV0Q2adEQ/H568p496QdYG0jK/XGMdx7OGSqdBZen92ciAsYdyhLtyl91UVsN1lBhDi5H6j3T2KS6aJg==} peerDependencies: - '@capacitor/core': ^6.1.0 + '@capacitor/core': ^6.2.0 - '@capacitor/app@6.0.1': - resolution: {integrity: sha512-0kXbOl7LPPMFVcAii3u/7Ps0DvXlr7dtHT97r9J1faDlgdQLQUvtGp48tjvFm48gqHI0aOPRJnTBr5JXW4ETYg==} + '@capacitor/app@6.0.2': + resolution: {integrity: sha512-SiGTGgslK4TbWJVImCUL1odul7/YFkVfkYtAYS9AAEzQpxBECBeRnuN3FFBcfZ9eiN1XxFBFchhiwpxtx/c7yQ==} peerDependencies: '@capacitor/core': ^6.0.0 - '@capacitor/cli@6.1.2': - resolution: {integrity: sha512-HKCNGE0RP8U7aiEF2vg5wTivJROS8BVfu8a3yYJb1mRQvzv+czpmtHNsTWS/WukvwoxUjyjRmsNQSAACHfMTmQ==} + '@capacitor/cli@6.2.0': + resolution: {integrity: sha512-EWcXG39mZh35zrHhOqzN1ILeSyMRyEqWVtQDXqMGjCXYRH6b6p5TvyvLDN8ZNy26tbhI3i79gfrgirt+mNwuuw==} engines: {node: '>=18.0.0'} hasBin: true - '@capacitor/core@6.1.2': - resolution: {integrity: sha512-xFy1/4qLFLp5WCIzIhtwUuVNNoz36+V7/BzHmLqgVJcvotc4MMjswW/TshnPQaLLujEOaLkA4h8ZJ0uoK3ImGg==} + '@capacitor/core@6.2.0': + resolution: {integrity: sha512-B9IlJtDpUqhhYb+T8+cp2Db/3RETX36STgjeU2kQZBs/SLAcFiMama227o+msRjLeo3DO+7HJjWVA1+XlyyPEg==} - '@capacitor/filesystem@6.0.1': - resolution: {integrity: sha512-eHhXm6tzBIQhErzFnfOE6eA1U+15DHc2212/COfzzGGRk/dyGympoVV3ct2YPVzvpTSxMEW3xFocORv/xD9gFg==} + '@capacitor/filesystem@6.0.2': + resolution: {integrity: sha512-OUDjGPljC3/q6wFnCCBUgElfZgAaSaoKeh0ij2eoDygn5KVXta+5CiJ7H7o2/ziTW6WOyvP0++EC3DT0TzR23A==} peerDependencies: '@capacitor/core': ^6.0.0 - '@capacitor/haptics@6.0.1': - resolution: {integrity: sha512-Q8hedLwfwTSWEYc3eoATzkdKHBaIceYe5bd7FjxQCENNH0is5Ft0EjSRPz/xpTn39ebK0ooZBDBCwsyl6tjiTA==} + '@capacitor/haptics@6.0.2': + resolution: {integrity: sha512-xcFdIH4iIIeW2+1lzmlYMVicqB9ytaiuZ9NE3a9laKFPvMGC7hdj6i6tHFezwPJ/96xkHOwXT2b0F8Mh9xtTWg==} peerDependencies: '@capacitor/core': ^6.0.0 - '@capacitor/ios@6.1.2': - resolution: {integrity: sha512-HaeW68KisBd/7TmavzPDlL2bpoDK5AjR2ZYrqU4TlGwM88GtQfvduBCAlSCj20X0w/4+rWMkseD9dAAkacjiyQ==} + '@capacitor/ios@6.2.0': + resolution: {integrity: sha512-gisvZBIrKT1siiumgpLPY63HmJe69Ed/dOmfQQ+U1MIJmOR5gWGWvfO7QSj/FMatVZS4Xt/8jCoUgzDD1U6kSw==} peerDependencies: - '@capacitor/core': ^6.1.0 + '@capacitor/core': ^6.2.0 - '@capacitor/keyboard@6.0.2': - resolution: {integrity: sha512-fOfO3rQ0ZXuTHpK03INVTwmBnpqMiH8EHPpNaHjwjKwdrVRWBvtgIFhuyHNXh53rdcXw+uHB+1RIiNabnCrITw==} + '@capacitor/keyboard@6.0.3': + resolution: {integrity: sha512-V/mURxBI68HvClYjrGBlOriWkwYN7r+cWid/igJz/3scNc/V81DgQ9fpoLr4W0I5NY7YxOesjIJLuLO+LT18mQ==} peerDependencies: '@capacitor/core': ^6.0.0 - '@capacitor/network@6.0.2': - resolution: {integrity: sha512-c0aZb0vRodvUO7ugZdQfMXr7LHUgZSKaJcOfu53gwuxGuvrIUvqPvaog+GlNLp7SB4Iw74Js7cemnIqsR5yxzw==} + '@capacitor/network@6.0.3': + resolution: {integrity: sha512-ODRgVY8AMIDXPoND6OvaaeMwRhtnq+K/IK7IEKV1pSg8CqJgqoD6je0omZnDqM+S1BKI2JOm8pe3gVvtcoehdw==} peerDependencies: '@capacitor/core': ^6.0.0 - '@capacitor/share@6.0.2': - resolution: {integrity: sha512-qQIeyjzFB1VgP4ojyNg2O98TCigDWLKZ5melVMSVeDO0YQov5OeammsVgaCGSzvYBPSgyOwX41QvcDWG4yHN1A==} + '@capacitor/share@6.0.3': + resolution: {integrity: sha512-BkNM73Ix+yxQ7fkni8CrrGcp1kSl7u+YNoPLwWKQ1MuQ5Uav0d+CT8M67ie+3dc4jASmegnzlC6tkTmFcPTLeA==} peerDependencies: '@capacitor/core': ^6.0.0 - '@capacitor/splash-screen@6.0.2': - resolution: {integrity: sha512-WC0KYZ+ev15up03xs4fTnoTKwBVUSxXsKKQr/8XAncvi/nAG8qrpanW8OlavSC5zF5e1IZZDLsI2GSv0SkZ7VQ==} + '@capacitor/splash-screen@6.0.3': + resolution: {integrity: sha512-tpVljeNGSwVCIc8lMQkyiCQFokk2PwgYPdDtPnGjFthqmXW/WhIxW8QYl4MUqyLwwgwTEbp4u3Kcv2zqQu2L6Q==} peerDependencies: '@capacitor/core': ^6.0.0 - '@capacitor/status-bar@6.0.1': - resolution: {integrity: sha512-Usd9hZZQVAqy+jJfL7jRcYI7dcsxN09Na1yttwdl+F1bk3Ztoukk7CGPDm5VgKUSs53ihQBOy1+sczCACxhNiw==} + '@capacitor/status-bar@6.0.2': + resolution: {integrity: sha512-AmRIX6QvFemItlY7/69ARkIAqitRQqJ2qwgZmD1KqgFb78pH+XFXm1guvS/a8CuOOm/IqZ4ddDbl20yxtBqzGA==} peerDependencies: '@capacitor/core': ^6.0.0 @@ -1001,147 +937,147 @@ packages: resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} - '@emotion/is-prop-valid@1.3.1': - resolution: {integrity: sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw==} - - '@emotion/memoize@0.9.0': - resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==} - - '@esbuild/aix-ppc64@0.21.5': - resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} - engines: {node: '>=12'} + '@esbuild/aix-ppc64@0.24.0': + resolution: {integrity: sha512-WtKdFM7ls47zkKHFVzMz8opM7LkcsIp9amDUBIAWirg70RM71WRSjdILPsY5Uv1D42ZpUfaPILDlfactHgsRkw==} + engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.21.5': - resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} - engines: {node: '>=12'} + '@esbuild/android-arm64@0.24.0': + resolution: {integrity: sha512-Vsm497xFM7tTIPYK9bNTYJyF/lsP590Qc1WxJdlB6ljCbdZKU9SY8i7+Iin4kyhV/KV5J2rOKsBQbB77Ab7L/w==} + engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.21.5': - resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} - engines: {node: '>=12'} + '@esbuild/android-arm@0.24.0': + resolution: {integrity: sha512-arAtTPo76fJ/ICkXWetLCc9EwEHKaeya4vMrReVlEIUCAUncH7M4bhMQ+M9Vf+FFOZJdTNMXNBrWwW+OXWpSew==} + engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.21.5': - resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} - engines: {node: '>=12'} + '@esbuild/android-x64@0.24.0': + resolution: {integrity: sha512-t8GrvnFkiIY7pa7mMgJd7p8p8qqYIz1NYiAoKc75Zyv73L3DZW++oYMSHPRarcotTKuSs6m3hTOa5CKHaS02TQ==} + engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.21.5': - resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} - engines: {node: '>=12'} + '@esbuild/darwin-arm64@0.24.0': + resolution: {integrity: sha512-CKyDpRbK1hXwv79soeTJNHb5EiG6ct3efd/FTPdzOWdbZZfGhpbcqIpiD0+vwmpu0wTIL97ZRPZu8vUt46nBSw==} + engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.21.5': - resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} - engines: {node: '>=12'} + '@esbuild/darwin-x64@0.24.0': + resolution: {integrity: sha512-rgtz6flkVkh58od4PwTRqxbKH9cOjaXCMZgWD905JOzjFKW+7EiUObfd/Kav+A6Gyud6WZk9w+xu6QLytdi2OA==} + engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.21.5': - resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} - engines: {node: '>=12'} + '@esbuild/freebsd-arm64@0.24.0': + resolution: {integrity: sha512-6Mtdq5nHggwfDNLAHkPlyLBpE5L6hwsuXZX8XNmHno9JuL2+bg2BX5tRkwjyfn6sKbxZTq68suOjgWqCicvPXA==} + engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.21.5': - resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} - engines: {node: '>=12'} + '@esbuild/freebsd-x64@0.24.0': + resolution: {integrity: sha512-D3H+xh3/zphoX8ck4S2RxKR6gHlHDXXzOf6f/9dbFt/NRBDIE33+cVa49Kil4WUjxMGW0ZIYBYtaGCa2+OsQwQ==} + engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.21.5': - resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} - engines: {node: '>=12'} + '@esbuild/linux-arm64@0.24.0': + resolution: {integrity: sha512-TDijPXTOeE3eaMkRYpcy3LarIg13dS9wWHRdwYRnzlwlA370rNdZqbcp0WTyyV/k2zSxfko52+C7jU5F9Tfj1g==} + engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.21.5': - resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} - engines: {node: '>=12'} + '@esbuild/linux-arm@0.24.0': + resolution: {integrity: sha512-gJKIi2IjRo5G6Glxb8d3DzYXlxdEj2NlkixPsqePSZMhLudqPhtZ4BUrpIuTjJYXxvF9njql+vRjB2oaC9XpBw==} + engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.21.5': - resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} - engines: {node: '>=12'} + '@esbuild/linux-ia32@0.24.0': + resolution: {integrity: sha512-K40ip1LAcA0byL05TbCQ4yJ4swvnbzHscRmUilrmP9Am7//0UjPreh4lpYzvThT2Quw66MhjG//20mrufm40mA==} + engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.21.5': - resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} - engines: {node: '>=12'} + '@esbuild/linux-loong64@0.24.0': + resolution: {integrity: sha512-0mswrYP/9ai+CU0BzBfPMZ8RVm3RGAN/lmOMgW4aFUSOQBjA31UP8Mr6DDhWSuMwj7jaWOT0p0WoZ6jeHhrD7g==} + engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.21.5': - resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} - engines: {node: '>=12'} + '@esbuild/linux-mips64el@0.24.0': + resolution: {integrity: sha512-hIKvXm0/3w/5+RDtCJeXqMZGkI2s4oMUGj3/jM0QzhgIASWrGO5/RlzAzm5nNh/awHE0A19h/CvHQe6FaBNrRA==} + engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.21.5': - resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} - engines: {node: '>=12'} + '@esbuild/linux-ppc64@0.24.0': + resolution: {integrity: sha512-HcZh5BNq0aC52UoocJxaKORfFODWXZxtBaaZNuN3PUX3MoDsChsZqopzi5UupRhPHSEHotoiptqikjN/B77mYQ==} + engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.21.5': - resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} - engines: {node: '>=12'} + '@esbuild/linux-riscv64@0.24.0': + resolution: {integrity: sha512-bEh7dMn/h3QxeR2KTy1DUszQjUrIHPZKyO6aN1X4BCnhfYhuQqedHaa5MxSQA/06j3GpiIlFGSsy1c7Gf9padw==} + engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.21.5': - resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} - engines: {node: '>=12'} + '@esbuild/linux-s390x@0.24.0': + resolution: {integrity: sha512-ZcQ6+qRkw1UcZGPyrCiHHkmBaj9SiCD8Oqd556HldP+QlpUIe2Wgn3ehQGVoPOvZvtHm8HPx+bH20c9pvbkX3g==} + engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.21.5': - resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} - engines: {node: '>=12'} + '@esbuild/linux-x64@0.24.0': + resolution: {integrity: sha512-vbutsFqQ+foy3wSSbmjBXXIJ6PL3scghJoM8zCL142cGaZKAdCZHyf+Bpu/MmX9zT9Q0zFBVKb36Ma5Fzfa8xA==} + engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-x64@0.21.5': - resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} - engines: {node: '>=12'} + '@esbuild/netbsd-x64@0.24.0': + resolution: {integrity: sha512-hjQ0R/ulkO8fCYFsG0FZoH+pWgTTDreqpqY7UnQntnaKv95uP5iW3+dChxnx7C3trQQU40S+OgWhUVwCjVFLvg==} + engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-x64@0.21.5': - resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} - engines: {node: '>=12'} + '@esbuild/openbsd-arm64@0.24.0': + resolution: {integrity: sha512-MD9uzzkPQbYehwcN583yx3Tu5M8EIoTD+tUgKF982WYL9Pf5rKy9ltgD0eUgs8pvKnmizxjXZyLt0z6DC3rRXg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.24.0': + resolution: {integrity: sha512-4ir0aY1NGUhIC1hdoCzr1+5b43mw99uNwVzhIq1OY3QcEwPDO3B7WNXBzaKY5Nsf1+N11i1eOfFcq+D/gOS15Q==} + engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/sunos-x64@0.21.5': - resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} - engines: {node: '>=12'} + '@esbuild/sunos-x64@0.24.0': + resolution: {integrity: sha512-jVzdzsbM5xrotH+W5f1s+JtUy1UWgjU0Cf4wMvffTB8m6wP5/kx0KiaLHlbJO+dMgtxKV8RQ/JvtlFcdZ1zCPA==} + engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.21.5': - resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} - engines: {node: '>=12'} + '@esbuild/win32-arm64@0.24.0': + resolution: {integrity: sha512-iKc8GAslzRpBytO2/aN3d2yb2z8XTVfNV0PjGlCxKo5SgWmNXx82I/Q3aG1tFfS+A2igVCY97TJ8tnYwpUWLCA==} + engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.21.5': - resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} - engines: {node: '>=12'} + '@esbuild/win32-ia32@0.24.0': + resolution: {integrity: sha512-vQW36KZolfIudCcTnaTpmLQ24Ha1RjygBo39/aLkM2kmjkWmZGEJ5Gn9l5/7tzXA42QGIoWbICfg6KLLkIw6yw==} + engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.21.5': - resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} - engines: {node: '>=12'} + '@esbuild/win32-x64@0.24.0': + resolution: {integrity: sha512-7IAFPrjSQIJrGsK6flwg7NFmwBoSTyF3rl7If0hNUFQU4ilTsEPL6GuMuU9BfIWVVGuRnuIidkSMC+c0Otu8IA==} + engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -1155,20 +1091,20 @@ packages: resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/config-array@0.18.0': - resolution: {integrity: sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==} + '@eslint/config-array@0.19.0': + resolution: {integrity: sha512-zdHg2FPIFNKPdcHWtiNT+jEFCHYVplAXRDlQDyqy0zGx/q2parwh7brGJSiTxRk/TSMkbM//zt/f5CHgyTyaSQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/core@0.7.0': - resolution: {integrity: sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==} + '@eslint/core@0.9.0': + resolution: {integrity: sha512-7ATR9F0e4W85D/0w7cU0SNj7qkAexMG+bAHEZOjo9akvGuhHE2m7umzWzfnpa0XAg5Kxc1BWmtPMV67jJ+9VUg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/eslintrc@3.1.0': - resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==} + '@eslint/eslintrc@3.2.0': + resolution: {integrity: sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.14.0': - resolution: {integrity: sha512-pFoEtFWCPyDOl+C6Ift+wC7Ro89otjigCf5vcuWqWgqNSQbRrpjSvdeE6ofLz4dHmyxD5f7gIdGT4+p36L6Twg==} + '@eslint/js@9.16.0': + resolution: {integrity: sha512-tw2HxzQkrbeuvyj1tG2Yqq+0H9wGoI2IMk4EOsQeX+vmd75FtJAzf+gTA69WF+baUKRYQ3x2kbLE08js5OsTVg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/object-schema@2.1.4': @@ -1230,16 +1166,16 @@ packages: engines: {node: '>=16.0.0'} hasBin: true - '@ionic/react-router@8.4.0': - resolution: {integrity: sha512-JmBiSlQtOb0yeOFa0O0iQ77koX7jcCkTfyMCWkOsSqXySU5yGuhnfOFNy6O7cbZ1J4lmCeNBqA29hRV7tmnPyg==} + '@ionic/react-router@8.4.1': + resolution: {integrity: sha512-OFfN07lBc/kNjyWqVNMraA/ZlqguveybCtXYuVuqHf0QshrakT+JYhuJQof5sEbqRq4GFbgqOeCJqL+3jozDZA==} peerDependencies: react: '>=16.8.6' react-dom: '>=16.8.6' react-router: ^5.0.1 react-router-dom: ^5.0.1 - '@ionic/react@8.4.0': - resolution: {integrity: sha512-wCtixCwf673Qnes1uGxmRoyUP4FnGtEyUVwtkcfj9IBrPUbw641Ws8J4jRjQ2rOO1WkWkSCeHKnd+KYCqyulZg==} + '@ionic/react@8.4.1': + resolution: {integrity: sha512-QGxcNilIAMWylgKFQuojESDm7T5aRopKDqsH7c0mdRZPMA5o5i9ErnjBfhZgG7ABuyZ7m+T3TWHqzE/umX43ng==} peerDependencies: react: '>=16.8.6' react-dom: '>=16.8.6' @@ -1348,18 +1284,8 @@ packages: '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - '@linaria/core@6.2.0': - resolution: {integrity: sha512-Ee+cwfhzhRM5X9rFogah3npw0OSqy80sJe/hlWIJxQD1WR6Zsbf+y78IlBPEzi6PvgoOiqdYtFjSUeWFqNVIDw==} - engines: {node: '>=16.0.0'} - - '@linaria/react@6.2.1': - resolution: {integrity: sha512-wfNRpYw8VMjKGRWU4XrHhWW9i3L71GrpuquwbWOUCq1q5YtxEoC2/qnz3yT4SOADCsfyDRAWhRhZxeCaDvYsGQ==} - engines: {node: '>=16.0.0'} - peerDependencies: - react: '>=16' - - '@mantine/hooks@7.14.0': - resolution: {integrity: sha512-BJ577AoQ5KnvbuaG174TYAmL2UqcX9qh9aL0aOx+gqyMM6GWeBXUXWx1kcMCzaDbYZwfQptU476fpSjHdcLjMw==} + '@mantine/hooks@7.14.3': + resolution: {integrity: sha512-cU3R9b8GLs6aCvpsVC56ZOOJCUIoDqX3RcLWkcfpA5a47LjWa/rzegP4YWfNW6/E9vodPJT4AEbYXVffYlyNwA==} peerDependencies: react: ^18.x || ^19.x @@ -1424,18 +1350,100 @@ packages: resolution: {integrity: sha512-MB4AYDsM5jhIHro/dq4ix1iWTLGToIGk6cWF5L6vanFaMble5jTX/UBQyiv05HsWnwUtY8JrfHy2LWfKwihqMw==} engines: {node: '>= 18'} - '@octokit/types@13.6.1': - resolution: {integrity: sha512-PHZE9Z+kWXb23Ndik8MKPirBPziOc0D2/3KH1P+6jK5nGWe96kadZuE4jev2/Jq7FvIfTlT2Ltg8Fv2x1v0a5g==} + '@octokit/types@13.6.2': + resolution: {integrity: sha512-WpbZfZUcZU77DrSW4wbsSgTPfKcp286q3ItaIgvSbBpZJlu6mnYXAkjZz6LVZPXkEvLIM8McanyZejKTYUHipA==} '@one-ini/wasm@0.1.1': resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==} + '@parcel/watcher-android-arm64@2.5.0': + resolution: {integrity: sha512-qlX4eS28bUcQCdribHkg/herLe+0A9RyYC+mm2PXpncit8z5b3nSqGVzMNR3CmtAOgRutiZ02eIJJgP/b1iEFQ==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [android] + + '@parcel/watcher-darwin-arm64@2.5.0': + resolution: {integrity: sha512-hyZ3TANnzGfLpRA2s/4U1kbw2ZI4qGxaRJbBH2DCSREFfubMswheh8TeiC1sGZ3z2jUf3s37P0BBlrD3sjVTUw==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [darwin] + + '@parcel/watcher-darwin-x64@2.5.0': + resolution: {integrity: sha512-9rhlwd78saKf18fT869/poydQK8YqlU26TMiNg7AIu7eBp9adqbJZqmdFOsbZ5cnLp5XvRo9wcFmNHgHdWaGYA==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [darwin] + + '@parcel/watcher-freebsd-x64@2.5.0': + resolution: {integrity: sha512-syvfhZzyM8kErg3VF0xpV8dixJ+RzbUaaGaeb7uDuz0D3FK97/mZ5AJQ3XNnDsXX7KkFNtyQyFrXZzQIcN49Tw==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [freebsd] + + '@parcel/watcher-linux-arm-glibc@2.5.0': + resolution: {integrity: sha512-0VQY1K35DQET3dVYWpOaPFecqOT9dbuCfzjxoQyif1Wc574t3kOSkKevULddcR9znz1TcklCE7Ht6NIxjvTqLA==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + + '@parcel/watcher-linux-arm-musl@2.5.0': + resolution: {integrity: sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + + '@parcel/watcher-linux-arm64-glibc@2.5.0': + resolution: {integrity: sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + + '@parcel/watcher-linux-arm64-musl@2.5.0': + resolution: {integrity: sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + + '@parcel/watcher-linux-x64-glibc@2.5.0': + resolution: {integrity: sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + + '@parcel/watcher-linux-x64-musl@2.5.0': + resolution: {integrity: sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + + '@parcel/watcher-win32-arm64@2.5.0': + resolution: {integrity: sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [win32] + + '@parcel/watcher-win32-ia32@2.5.0': + resolution: {integrity: sha512-+rgpsNRKwo8A53elqbbHXdOMtY/tAtTzManTWShB5Kk54N8Q9mzNWV7tV+IbGueCbcj826MfWGU3mprWtuf1TA==} + engines: {node: '>= 10.0.0'} + cpu: [ia32] + os: [win32] + + '@parcel/watcher-win32-x64@2.5.0': + resolution: {integrity: sha512-lPrxve92zEHdgeff3aiu4gDOIt4u7sJYha6wbdEZDCDUhtjTsOMiaJzG5lMY4GkWH8p0fMmO2Ppq5G5XXG+DQw==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [win32] + + '@parcel/watcher@2.5.0': + resolution: {integrity: sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ==} + engines: {node: '>= 10.0.0'} + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@playwright/test@1.48.2': - resolution: {integrity: sha512-54w1xCWfXuax7dz4W2M9uw0gDyh+ti/0K/MxcCUxChFh37kkdxPdfZDw5QBbuPUJHr1CiHJ1hXgSs+GgeQc5Zw==} + '@playwright/test@1.49.0': + resolution: {integrity: sha512-DMulbwQURa8rNIQrf94+jPJQ4FmOVdpE5ZppRNvWVjvhC+6sOeo28r8MgIpQRYouXRtt/FCCXU7zn20jnHR4Qw==} engines: {node: '>=18'} hasBin: true @@ -1457,8 +1465,8 @@ packages: '@prettier/plugin-xml@2.2.0': resolution: {integrity: sha512-UWRmygBsyj4bVXvDiqSccwT1kmsorcwQwaIy30yVh8T+Gspx4OlC0shX1y+ZuwXZvgnafmpRYKks0bAu9urJew==} - '@reduxjs/toolkit@2.3.0': - resolution: {integrity: sha512-WC7Yd6cNGfHx8zf+iu+Q1UPTfEcXhQ+ATi7CV1hlrSAaQBdlPzg7Ww/wJHNQem7qG9rxmWoFCDCPubSvFObGzA==} + '@reduxjs/toolkit@2.4.0': + resolution: {integrity: sha512-wJZEuSKj14tvNfxiIiJws0tQN77/rDqucBq528ApebMIRHyWpCanJVQRxQ8WWZC19iCDKxDsGlbAir3F1layxA==} peerDependencies: react: ^16.9.0 || ^17.0.0 || ^18 react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0 @@ -1517,93 +1525,93 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.26.0': - resolution: {integrity: sha512-gJNwtPDGEaOEgejbaseY6xMFu+CPltsc8/T+diUTTbOQLqD+bnrJq9ulH6WD69TqwqWmrfRAtUv30cCFZlbGTQ==} + '@rollup/rollup-android-arm-eabi@4.28.0': + resolution: {integrity: sha512-wLJuPLT6grGZsy34g4N1yRfYeouklTgPhH1gWXCYspenKYD0s3cR99ZevOGw5BexMNywkbV3UkjADisozBmpPQ==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.26.0': - resolution: {integrity: sha512-YJa5Gy8mEZgz5JquFruhJODMq3lTHWLm1fOy+HIANquLzfIOzE9RA5ie3JjCdVb9r46qfAQY/l947V0zfGJ0OQ==} + '@rollup/rollup-android-arm64@4.28.0': + resolution: {integrity: sha512-eiNkznlo0dLmVG/6wf+Ifi/v78G4d4QxRhuUl+s8EWZpDewgk7PX3ZyECUXU0Zq/Ca+8nU8cQpNC4Xgn2gFNDA==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.26.0': - resolution: {integrity: sha512-ErTASs8YKbqTBoPLp/kA1B1Um5YSom8QAc4rKhg7b9tyyVqDBlQxy7Bf2wW7yIlPGPg2UODDQcbkTlruPzDosw==} + '@rollup/rollup-darwin-arm64@4.28.0': + resolution: {integrity: sha512-lmKx9yHsppblnLQZOGxdO66gT77bvdBtr/0P+TPOseowE7D9AJoBw8ZDULRasXRWf1Z86/gcOdpBrV6VDUY36Q==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.26.0': - resolution: {integrity: sha512-wbgkYDHcdWW+NqP2mnf2NOuEbOLzDblalrOWcPyY6+BRbVhliavon15UploG7PpBRQ2bZJnbmh8o3yLoBvDIHA==} + '@rollup/rollup-darwin-x64@4.28.0': + resolution: {integrity: sha512-8hxgfReVs7k9Js1uAIhS6zq3I+wKQETInnWQtgzt8JfGx51R1N6DRVy3F4o0lQwumbErRz52YqwjfvuwRxGv1w==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.26.0': - resolution: {integrity: sha512-Y9vpjfp9CDkAG4q/uwuhZk96LP11fBz/bYdyg9oaHYhtGZp7NrbkQrj/66DYMMP2Yo/QPAsVHkV891KyO52fhg==} + '@rollup/rollup-freebsd-arm64@4.28.0': + resolution: {integrity: sha512-lA1zZB3bFx5oxu9fYud4+g1mt+lYXCoch0M0V/xhqLoGatbzVse0wlSQ1UYOWKpuSu3gyN4qEc0Dxf/DII1bhQ==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.26.0': - resolution: {integrity: sha512-A/jvfCZ55EYPsqeaAt/yDAG4q5tt1ZboWMHEvKAH9Zl92DWvMIbnZe/f/eOXze65aJaaKbL+YeM0Hz4kLQvdwg==} + '@rollup/rollup-freebsd-x64@4.28.0': + resolution: {integrity: sha512-aI2plavbUDjCQB/sRbeUZWX9qp12GfYkYSJOrdYTL/C5D53bsE2/nBPuoiJKoWp5SN78v2Vr8ZPnB+/VbQ2pFA==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.26.0': - resolution: {integrity: sha512-paHF1bMXKDuizaMODm2bBTjRiHxESWiIyIdMugKeLnjuS1TCS54MF5+Y5Dx8Ui/1RBPVRE09i5OUlaLnv8OGnA==} + '@rollup/rollup-linux-arm-gnueabihf@4.28.0': + resolution: {integrity: sha512-WXveUPKtfqtaNvpf0iOb0M6xC64GzUX/OowbqfiCSXTdi/jLlOmH0Ba94/OkiY2yTGTwteo4/dsHRfh5bDCZ+w==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.26.0': - resolution: {integrity: sha512-cwxiHZU1GAs+TMxvgPfUDtVZjdBdTsQwVnNlzRXC5QzIJ6nhfB4I1ahKoe9yPmoaA/Vhf7m9dB1chGPpDRdGXg==} + '@rollup/rollup-linux-arm-musleabihf@4.28.0': + resolution: {integrity: sha512-yLc3O2NtOQR67lI79zsSc7lk31xjwcaocvdD1twL64PK1yNaIqCeWI9L5B4MFPAVGEVjH5k1oWSGuYX1Wutxpg==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.26.0': - resolution: {integrity: sha512-4daeEUQutGRCW/9zEo8JtdAgtJ1q2g5oHaoQaZbMSKaIWKDQwQ3Yx0/3jJNmpzrsScIPtx/V+1AfibLisb3AMQ==} + '@rollup/rollup-linux-arm64-gnu@4.28.0': + resolution: {integrity: sha512-+P9G9hjEpHucHRXqesY+3X9hD2wh0iNnJXX/QhS/J5vTdG6VhNYMxJ2rJkQOxRUd17u5mbMLHM7yWGZdAASfcg==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.26.0': - resolution: {integrity: sha512-eGkX7zzkNxvvS05ROzJ/cO/AKqNvR/7t1jA3VZDi2vRniLKwAWxUr85fH3NsvtxU5vnUUKFHKh8flIBdlo2b3Q==} + '@rollup/rollup-linux-arm64-musl@4.28.0': + resolution: {integrity: sha512-1xsm2rCKSTpKzi5/ypT5wfc+4bOGa/9yI/eaOLW0oMs7qpC542APWhl4A37AENGZ6St6GBMWhCCMM6tXgTIplw==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.26.0': - resolution: {integrity: sha512-Odp/lgHbW/mAqw/pU21goo5ruWsytP7/HCC/liOt0zcGG0llYWKrd10k9Fj0pdj3prQ63N5yQLCLiE7HTX+MYw==} + '@rollup/rollup-linux-powerpc64le-gnu@4.28.0': + resolution: {integrity: sha512-zgWxMq8neVQeXL+ouSf6S7DoNeo6EPgi1eeqHXVKQxqPy1B2NvTbaOUWPn/7CfMKL7xvhV0/+fq/Z/J69g1WAQ==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.26.0': - resolution: {integrity: sha512-MBR2ZhCTzUgVD0OJdTzNeF4+zsVogIR1U/FsyuFerwcqjZGvg2nYe24SAHp8O5sN8ZkRVbHwlYeHqcSQ8tcYew==} + '@rollup/rollup-linux-riscv64-gnu@4.28.0': + resolution: {integrity: sha512-VEdVYacLniRxbRJLNtzwGt5vwS0ycYshofI7cWAfj7Vg5asqj+pt+Q6x4n+AONSZW/kVm+5nklde0qs2EUwU2g==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.26.0': - resolution: {integrity: sha512-YYcg8MkbN17fMbRMZuxwmxWqsmQufh3ZJFxFGoHjrE7bv0X+T6l3glcdzd7IKLiwhT+PZOJCblpnNlz1/C3kGQ==} + '@rollup/rollup-linux-s390x-gnu@4.28.0': + resolution: {integrity: sha512-LQlP5t2hcDJh8HV8RELD9/xlYtEzJkm/aWGsauvdO2ulfl3QYRjqrKW+mGAIWP5kdNCBheqqqYIGElSRCaXfpw==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.26.0': - resolution: {integrity: sha512-ZuwpfjCwjPkAOxpjAEjabg6LRSfL7cAJb6gSQGZYjGhadlzKKywDkCUnJ+KEfrNY1jH5EEoSIKLCb572jSiglA==} + '@rollup/rollup-linux-x64-gnu@4.28.0': + resolution: {integrity: sha512-Nl4KIzteVEKE9BdAvYoTkW19pa7LR/RBrT6F1dJCV/3pbjwDcaOq+edkP0LXuJ9kflW/xOK414X78r+K84+msw==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.26.0': - resolution: {integrity: sha512-+HJD2lFS86qkeF8kNu0kALtifMpPCZU80HvwztIKnYwym3KnA1os6nsX4BGSTLtS2QVAGG1P3guRgsYyMA0Yhg==} + '@rollup/rollup-linux-x64-musl@4.28.0': + resolution: {integrity: sha512-eKpJr4vBDOi4goT75MvW+0dXcNUqisK4jvibY9vDdlgLx+yekxSm55StsHbxUsRxSTt3JEQvlr3cGDkzcSP8bw==} cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.26.0': - resolution: {integrity: sha512-WUQzVFWPSw2uJzX4j6YEbMAiLbs0BUysgysh8s817doAYhR5ybqTI1wtKARQKo6cGop3pHnrUJPFCsXdoFaimQ==} + '@rollup/rollup-win32-arm64-msvc@4.28.0': + resolution: {integrity: sha512-Vi+WR62xWGsE/Oj+mD0FNAPY2MEox3cfyG0zLpotZdehPFXwz6lypkGs5y38Jd/NVSbOD02aVad6q6QYF7i8Bg==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.26.0': - resolution: {integrity: sha512-D4CxkazFKBfN1akAIY6ieyOqzoOoBV1OICxgUblWxff/pSjCA2khXlASUx7mK6W1oP4McqhgcCsu6QaLj3WMWg==} + '@rollup/rollup-win32-ia32-msvc@4.28.0': + resolution: {integrity: sha512-kN/Vpip8emMLn/eOza+4JwqDZBL6MPNpkdaEsgUtW1NYN3DZvZqSQrbKzJcTL6hd8YNmFTn7XGWMwccOcJBL0A==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.26.0': - resolution: {integrity: sha512-2x8MO1rm4PGEP0xWbubJW5RtbNLk3puzAMaLQd3B3JHVw4KcHlmXcO+Wewx9zCoo7EUFiMlu/aZbCJ7VjMzAag==} + '@rollup/rollup-win32-x64-msvc@4.28.0': + resolution: {integrity: sha512-Bvno2/aZT6usSa7lRDL2+hMjVAGjuqaymF1ApZm31JXzniR/hvr14jpU+/z4X6Gt5BPlzosscyJZGUvguXIqeQ==} cpu: [x64] os: [win32] @@ -1616,8 +1624,8 @@ packages: engines: {node: '>=16.0.0', npm: '>=7.10.0'} hasBin: true - '@stencil/core@4.22.2': - resolution: {integrity: sha512-eq2pYrrnzcLyBRANk0X/VVOfCtD0nCxWnEZ0AVdscuqfDkOjxa6SSZOfEhR9FAvrmESHp8y5jRCVPnf4n5CC4A==} + '@stencil/core@4.22.3': + resolution: {integrity: sha512-dYaletX938WgEA2oMROLdh8wpUn1MgBx2zg5kYqwuUR8aua4Gy9EqGQ3zBu1AvL5MzLlZC+lMlxe/g5Dg1ldpw==} engines: {node: '>=16.0.0', npm: '>=7.10.0'} hasBin: true @@ -1774,8 +1782,8 @@ packages: '@types/ms@0.7.34': resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} - '@types/node@22.9.0': - resolution: {integrity: sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==} + '@types/node@22.10.1': + resolution: {integrity: sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==} '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -1831,8 +1839,8 @@ packages: '@types/yauzl@2.10.3': resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} - '@typescript-eslint/eslint-plugin@8.14.0': - resolution: {integrity: sha512-tqp8H7UWFaZj0yNO6bycd5YjMwxa6wIHOLZvWPkidwbgLCsBMetQoGj7DPuAlWa2yGO3H48xmPwjhsSPPCGU5w==} + '@typescript-eslint/eslint-plugin@8.16.0': + resolution: {integrity: sha512-5YTHKV8MYlyMI6BaEG7crQ9BhSc8RxzshOReKwZwRWN0+XvvTOm+L/UYLCYxFpfwYuAAqhxiq4yae0CMFwbL7Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 @@ -1842,8 +1850,8 @@ packages: typescript: optional: true - '@typescript-eslint/parser@8.14.0': - resolution: {integrity: sha512-2p82Yn9juUJq0XynBXtFCyrBDb6/dJombnz6vbo6mgQEtWHfvHbQuEa9kAOVIt1c9YFwi7H6WxtPj1kg+80+RA==} + '@typescript-eslint/parser@8.16.0': + resolution: {integrity: sha512-D7DbgGFtsqIPIFMPJwCad9Gfi/hC0PWErRRHFnaCWoEDYi5tQUDiJCTmGUbBiLzjqAck4KcXt9Ayj0CNlIrF+w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -1856,14 +1864,15 @@ packages: resolution: {integrity: sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/scope-manager@8.14.0': - resolution: {integrity: sha512-aBbBrnW9ARIDn92Zbo7rguLnqQ/pOrUguVpbUwzOhkFg2npFDwTgPGqFqE0H5feXcOoJOfX3SxlJaKEVtq54dw==} + '@typescript-eslint/scope-manager@8.16.0': + resolution: {integrity: sha512-mwsZWubQvBki2t5565uxF0EYvG+FwdFb8bMtDuGQLdCCnGPrDEDvm1gtfynuKlnpzeBRqdFCkMf9jg1fnAK8sg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/type-utils@8.14.0': - resolution: {integrity: sha512-Xcz9qOtZuGusVOH5Uk07NGs39wrKkf3AxlkK79RBK6aJC1l03CobXjJbwBPSidetAOV+5rEVuiT1VSBUOAsanQ==} + '@typescript-eslint/type-utils@8.16.0': + resolution: {integrity: sha512-IqZHGG+g1XCWX9NyqnI/0CX5LL8/18awQqmkZSl2ynn8F76j579dByc0jhfVSnSnhf7zv76mKBQv9HQFKvDCgg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: + eslint: ^8.57.0 || ^9.0.0 typescript: '*' peerDependenciesMeta: typescript: @@ -1873,8 +1882,8 @@ packages: resolution: {integrity: sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/types@8.14.0': - resolution: {integrity: sha512-yjeB9fnO/opvLJFAsPNYlKPnEM8+z4og09Pk504dkqonT02AyL5Z9SSqlE0XqezS93v6CXn49VHvB2G7XSsl0g==} + '@typescript-eslint/types@8.16.0': + resolution: {integrity: sha512-NzrHj6thBAOSE4d9bsuRNMvk+BvaQvmY4dDglgkgGC0EW/tB3Kelnp3tAKH87GEwzoxgeQn9fNGRyFJM/xd+GQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@typescript-eslint/typescript-estree@7.18.0': @@ -1886,8 +1895,8 @@ packages: typescript: optional: true - '@typescript-eslint/typescript-estree@8.14.0': - resolution: {integrity: sha512-OPXPLYKGZi9XS/49rdaCbR5j/S14HazviBlUQFvSKz3npr3NikF+mrgK7CFVur6XEt95DZp/cmke9d5i3vtVnQ==} + '@typescript-eslint/typescript-estree@8.16.0': + resolution: {integrity: sha512-E2+9IzzXMc1iaBy9zmo+UYvluE3TW7bCGWSF41hVWUE01o8nzr1rvOQYSxelxr6StUvRcTMe633eY8mXASMaNw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '*' @@ -1901,82 +1910,68 @@ packages: peerDependencies: eslint: ^8.56.0 - '@typescript-eslint/utils@8.14.0': - resolution: {integrity: sha512-OGqj6uB8THhrHj0Fk27DcHPojW7zKwKkPmHXHvQ58pLYp4hy8CSUdTKykKeh+5vFqTTVmjz0zCOOPKRovdsgHA==} + '@typescript-eslint/utils@8.16.0': + resolution: {integrity: sha512-C1zRy/mOL8Pj157GiX4kaw7iyRLKfJXBR3L82hk5kS/GyHcOFmy4YUq/zfZti72I9wnuQtA/+xzft4wCC8PJdA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true '@typescript-eslint/visitor-keys@7.18.0': resolution: {integrity: sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/visitor-keys@8.14.0': - resolution: {integrity: sha512-vG0XZo8AdTH9OE6VFRwAZldNc7qtJ/6NLGWak+BtENuEUXGZgFpihILPiBvKXvJ2nFu27XNGC6rKiwuaoMbYzQ==} + '@typescript-eslint/visitor-keys@8.16.0': + resolution: {integrity: sha512-pq19gbaMOmFE3CbL0ZB8J8BFCo2ckfHBfaIsaOZgBIF4EoISJIdLX5xRhd0FGB0LlHReNRuzoJoMGpTjq8F2CQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@ungap/structured-clone@1.2.0': resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} - '@vitejs/plugin-legacy@5.4.3': - resolution: {integrity: sha512-wsyXK9mascyplcqvww1gA1xYiy29iRHfyciw+a0t7qRNdzX6PdfSWmOoCi74epr87DujM+5J+rnnSv+4PazqVg==} - engines: {node: ^18.0.0 || >=20.0.0} + '@vitejs/plugin-legacy@6.0.0': + resolution: {integrity: sha512-pWt9cWaGJAKYw+67VLpN8hSP+G+yAQnrf5Pqh/NzSDKFl/4KpxTtwb5OLQezHoZOxghahO/ha3IpvblBbX/t6A==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} peerDependencies: - terser: ^5.4.0 - vite: ^5.0.0 + terser: ^5.16.0 + vite: ^6.0.0 - '@vitejs/plugin-react@4.3.3': - resolution: {integrity: sha512-NooDe9GpHGqNns1i8XDERg0Vsg5SSYRhRxxyTGogUdkdNt47jal+fbuYi+Yfq6pzRCKXyoPcWisfxE6RIM3GKA==} + '@vitejs/plugin-react@4.3.4': + resolution: {integrity: sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: - vite: ^4.2.0 || ^5.0.0 + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 - '@vitest/expect@2.1.5': - resolution: {integrity: sha512-nZSBTW1XIdpZvEJyoP/Sy8fUg0b8od7ZpGDkTUcfJ7wz/VoZAFzFfLyxVxGFhUjJzhYqSbIpfMtl/+k/dpWa3Q==} + '@vitest/expect@2.1.6': + resolution: {integrity: sha512-9M1UR9CAmrhJOMoSwVnPh2rELPKhYo0m/CSgqw9PyStpxtkwhmdM6XYlXGKeYyERY1N6EIuzkQ7e3Lm1WKCoUg==} - '@vitest/mocker@2.1.5': - resolution: {integrity: sha512-XYW6l3UuBmitWqSUXTNXcVBUCRytDogBsWuNXQijc00dtnU/9OqpXWp4OJroVrad/gLIomAq9aW8yWDBtMthhQ==} + '@vitest/mocker@2.1.6': + resolution: {integrity: sha512-MHZp2Z+Q/A3am5oD4WSH04f9B0T7UvwEb+v5W0kCYMhtXGYbdyl2NUk1wdSMqGthmhpiThPDp/hEoVwu16+u1A==} peerDependencies: msw: ^2.4.9 - vite: ^5.0.0 + vite: ^5.0.0 || ^6.0.0 peerDependenciesMeta: msw: optional: true vite: optional: true - '@vitest/pretty-format@2.1.5': - resolution: {integrity: sha512-4ZOwtk2bqG5Y6xRGHcveZVr+6txkH7M2e+nPFd6guSoN638v/1XQ0K06eOpi0ptVU/2tW/pIU4IoPotY/GZ9fw==} - - '@vitest/runner@2.1.5': - resolution: {integrity: sha512-pKHKy3uaUdh7X6p1pxOkgkVAFW7r2I818vHDthYLvUyjRfkKOU6P45PztOch4DZarWQne+VOaIMwA/erSSpB9g==} - - '@vitest/snapshot@2.1.5': - resolution: {integrity: sha512-zmYw47mhfdfnYbuhkQvkkzYroXUumrwWDGlMjpdUr4jBd3HZiV2w7CQHj+z7AAS4VOtWxI4Zt4bWt4/sKcoIjg==} - - '@vitest/spy@2.1.5': - resolution: {integrity: sha512-aWZF3P0r3w6DiYTVskOYuhBc7EMc3jvn1TkBg8ttylFFRqNN2XGD7V5a4aQdk6QiUzZQ4klNBSpCLJgWNdIiNw==} + '@vitest/pretty-format@2.1.6': + resolution: {integrity: sha512-exZyLcEnHgDMKc54TtHca4McV4sKT+NKAe9ix/yhd/qkYb/TP8HTyXRFDijV19qKqTZM0hPL4753zU/U8L/gAA==} - '@vitest/utils@2.1.5': - resolution: {integrity: sha512-yfj6Yrp0Vesw2cwJbP+cl04OC+IHFsuQsrsJBL9pyGeQXE56v1UAOQco+SR55Vf1nQzfV0QJg1Qum7AaWUwwYg==} + '@vitest/runner@2.1.6': + resolution: {integrity: sha512-SjkRGSFyrA82m5nz7To4CkRSEVWn/rwQISHoia/DB8c6IHIhaE/UNAo+7UfeaeJRE979XceGl00LNkIz09RFsA==} - '@wyw-in-js/processor-utils@0.5.5': - resolution: {integrity: sha512-L3IcAfoowhM0fw9Cnv2CNzfjWNLKpYl2CFqam6NvwpiXNR1kXz/GpO0AOiKvCs5h4Ps5kWxE2e8knXLpk8q/2g==} - engines: {node: '>=16.0.0'} + '@vitest/snapshot@2.1.6': + resolution: {integrity: sha512-5JTWHw8iS9l3v4/VSuthCndw1lN/hpPB+mlgn1BUhFbobeIUj1J1V/Bj2t2ovGEmkXLTckFjQddsxS5T6LuVWw==} - '@wyw-in-js/shared@0.5.5': - resolution: {integrity: sha512-Wnvp3RGfynHk81lrp/0fA+Yv5yuIr2Ej13N3lawQeqbK4KlMag3P9npyIljGrEiwK2Bv4byHuXsJFgLI0Fo8bw==} - engines: {node: '>=16.0.0'} + '@vitest/spy@2.1.6': + resolution: {integrity: sha512-oTFObV8bd4SDdRka5O+mSh5w9irgx5IetrD5i+OsUUsk/shsBoHifwCzy45SAORzAhtNiprUVaK3hSCCzZh1jQ==} - '@wyw-in-js/transform@0.5.5': - resolution: {integrity: sha512-XMZjhS8poHpxfPg41rkc6eh3Mr2BZAFM7OzYN4jPZUicpJKv7uQAU2dLEqnyDcDllo04LbZIryb2fXwpr+pqPw==} - engines: {node: '>=16.0.0'} - - '@wyw-in-js/vite@0.5.5': - resolution: {integrity: sha512-JynvzqiehPl6ClvbzwaGGkJbPFa2xYdrHyiKnp6NPIJyTSakOSYPKuFEaTRW/25YohMC/+oUdDlMJG+q8GrY0g==} - engines: {node: '>=16.0.0'} - peerDependencies: - vite: '>=3.2.7' + '@vitest/utils@2.1.6': + resolution: {integrity: sha512-ixNkFy3k4vokOUTU2blIUvOgKq/N2PW8vKIjZZYsGJCMX69MRa9J2sKqX5hY/k5O5Gty3YJChepkqZ3KM9LyIQ==} '@xml-tools/parser@1.0.11': resolution: {integrity: sha512-aKqQ077XnR+oQtHJlrAflaZaL7qZsulWc/i/ZEooar5JiWj1eLt0+Wg28cpa+XLney107wXqneC+oG1IZvxkTA==} @@ -2064,6 +2059,10 @@ packages: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + arg@4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} @@ -2140,16 +2139,17 @@ packages: atomically@2.0.3: resolution: {integrity: sha512-kU6FmrwZ3Lx7/7y3hPS5QnbJfaohcIul5fGqf7ok+4KklIEk9tJ0C2IQPdacSbVUWv6zVHXEBWoWd6NrVMT7Cw==} + autoprefixer@10.4.20: + resolution: {integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} - babel-merge@3.0.0: - resolution: {integrity: sha512-eBOBtHnzt9xvnjpYNI5HmaPp/b2vMveE5XggzqHnQeHJ8mFIBrBv6WZEVIj5jJ2uwTItkqKo9gWzEEcBxEq0yw==} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - peerDependencies: - '@babel/core': ^7.0.0 - babel-plugin-polyfill-corejs2@0.4.12: resolution: {integrity: sha512-CPWT6BwvhrTO2d8QVorhTCQw9Y43zOu7G9HigcfxvepOU6b8o3tcWad6oVgZIsZCTt42FFv97aA7ZJsbM4+8og==} peerDependencies: @@ -2165,8 +2165,8 @@ packages: peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - babel-plugin-react-compiler@0.0.0-experimental-19c7e06-20241113: - resolution: {integrity: sha512-0pYT7/PeJ5FpKJQOF1NrMNE8a6tL3ncCoRvdRW8w84RDPe+klLGkyksqcYz3J6dwpF9+d7ECzJRIeaQkmviYfQ==} + babel-plugin-react-compiler@0.0.0-experimental-df7b47d-20241124: + resolution: {integrity: sha512-N/8wJ9kQgQcudapIj6C+M4trt2OaK7w8yJHL0BRYp31z8VG3sRTQsyOnzG/tNQbviG35TfMSDwrMQUOLJlnIVA==} bail@2.0.2: resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} @@ -2188,6 +2188,10 @@ packages: resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==} engines: {node: '>=0.6'} + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} @@ -2272,8 +2276,8 @@ packages: resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==} engines: {node: '>=16'} - caniuse-lite@1.0.30001680: - resolution: {integrity: sha512-rPQy70G6AGUMnbwS1z6Xg+RkHYPAi18ihs47GH0jcxIG7wArmPgY3XbS2sRdBbxJljp3thdT8BIqv9ccCypiPA==} + caniuse-lite@1.0.30001684: + resolution: {integrity: sha512-G1LRwLIQjBQoyq0ZJGqGIJUXzJ8irpbjHLpVRXDvBEScFJ9b17sgK6vlx0GAJFE21okD7zXl08rRRUfq6HdoEQ==} capacitor-android-nav-mode@1.0.0: resolution: {integrity: sha512-Z7tdvC7NHDBqTnVwpuMYJTrSSWu7yLdNb0VHZjb76iwIzQ4wTNAigx7wC5fXx2S1GiN9vGT1Duby7fRmHq1mLg==} @@ -2305,8 +2309,8 @@ packages: peerDependencies: '@capacitor/core': ^6.0.0 - capacitor-reader@0.1.0: - resolution: {integrity: sha512-RMPiOQCHOdMOP6rUrL6m80JOdxohzyrR9bdberh5NNtJxEteTQNqimenUM+0lV9eYrx1ncieNzKYxh9zTvrmcA==} + capacitor-reader@0.2.0: + resolution: {integrity: sha512-lzqp/suT/Vq3Wx7Ks5T9zg7GxpYnBpBG9LamxV5u3hR89mY2LU+GbeDmj4II4ATKFOhZZaon2rnHiBXY7V9VAw==} peerDependencies: '@capacitor/core': ^6.0.0 @@ -2363,6 +2367,14 @@ packages: chevrotain@7.1.1: resolution: {integrity: sha512-wy3mC1x4ye+O+QkEinVJkPf5u2vsrDIYW9G7ZuwFl6v/Yu0LwUuT2POsb+NUWApebyxfkQq6+yDfRExbnI5rcw==} + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + + chokidar@4.0.1: + resolution: {integrity: sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==} + engines: {node: '>= 14.16.0'} + chownr@1.1.4: resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} @@ -2558,6 +2570,9 @@ packages: cookiejar@2.1.4: resolution: {integrity: sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==} + copy-anything@2.0.6: + resolution: {integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==} + core-js-compat@3.39.0: resolution: {integrity: sha512-VgEUx3VwlExr5no0tXlBt+silBvhTryPwCXRI2Id1PN8WTKu7MreethvddqOubrYxkFdv/RnYrqlv1sFNAUelw==} @@ -2591,8 +2606,8 @@ packages: cross-fetch@3.1.5: resolution: {integrity: sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==} - cross-spawn@7.0.5: - resolution: {integrity: sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==} + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} crypto-random-string@2.0.0: @@ -2606,6 +2621,11 @@ packages: resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} engines: {node: '>= 6'} + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + cssstyle@4.1.0: resolution: {integrity: sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==} engines: {node: '>=18'} @@ -2694,10 +2714,6 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - deepmerge@2.2.1: - resolution: {integrity: sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==} - engines: {node: '>=0.10.0'} - deepmerge@4.3.1: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} @@ -2748,19 +2764,27 @@ packages: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} + detect-europe-js@0.1.2: + resolution: {integrity: sha512-lgdERlL3u0aUdHocoouzT10d9I89VVhk0qNRmll7mXdGfJT1/wqZ2ZLA4oJAjeACPY5fT1wsbq2AT+GkuInsow==} + + detect-libc@1.0.3: + resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} + engines: {node: '>=0.10'} + hasBin: true + devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} devtools-protocol@0.0.981744: resolution: {integrity: sha512-0cuGS8+jhR67Fy7qG3i3Pc7Aw494sb9yG9QgpG97SFVWwolgYjlhJg7n+UaHxOQT30d1TYu/EYe9k01ivLErIg==} - dexie-export-import@4.1.3: - resolution: {integrity: sha512-5fHab8/+ff6gAadNCNN8xKYq1e2Pg/rRtlKneW1aqP3BPF4eMxkopp6jX3asFZQKqKvhO1Boj8wlf95hWhrsMA==} + dexie-export-import@4.1.4: + resolution: {integrity: sha512-3bw171qUuOTWSYLXI7C/0M6p1X65Rho3tu1IvD9By8jn0+3t3dLSkDlZ1BC6MbABl3kRlhtGigzC+SF+qcS5Og==} peerDependencies: dexie: ^2.0.4 || ^3.0.0 || ^4.0.1 - dexie@4.0.9: - resolution: {integrity: sha512-VQG1huEVSAdDZssb9Bb9mFy+d3jAE0PT4d1nIRYlT46ip1fzbs1tXi0SlUayRDgV3tTbJG8ZRqAo2um49gtynA==} + dexie@4.0.10: + resolution: {integrity: sha512-eM2RzuR3i+M046r2Q0Optl3pS31qTWf8aFuA7H9wnsHTwl8EPvroVLwvQene/6paAs39Tbk6fWZcn2aZaHkc/w==} dezalgo@1.0.4: resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==} @@ -2825,8 +2849,8 @@ packages: engines: {node: '>=0.10.0'} hasBin: true - electron-to-chromium@1.5.59: - resolution: {integrity: sha512-faAXB6+gEbC8FsiRdpOXgOe4snP49YwjiXynEB8Mp7sUx80W5eN+BnnBHJ/F7eIeLzs+QBfDD40bJMm97oEFcw==} + electron-to-chromium@1.5.67: + resolution: {integrity: sha512-nz88NNBsD7kQSAGGJyp8hS6xSPtWwqNogA0mjtc2nUYeEf3nURK9qpV18TuBdDmEDgVWotS8Wkzf+V52dSQ/LQ==} elementtree@0.1.7: resolution: {integrity: sha512-wkgGT6kugeQk/P6VZ/f4T+4HB41BVgNBq5CDIZVbQ02nvTVqAiVTbskxxu3eA/X96lMlfYOwnLQpN2v5E1zDEg==} @@ -2856,6 +2880,10 @@ packages: resolution: {integrity: sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + errno@0.1.8: + resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==} + hasBin: true + error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} @@ -2889,16 +2917,16 @@ packages: es-shim-unscopables@1.0.2: resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} - es-to-primitive@1.2.1: - resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} + es-to-primitive@1.3.0: + resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} - es-toolkit@1.27.0: - resolution: {integrity: sha512-ETSFA+ZJArcuSCpzD2TjAy6UHpx4E4uqFsoDg9F/nTLogrLmVVZQ+zNxco5h7cWnA1nNak07IXsLcaSMih+ZPQ==} + es-toolkit@1.28.0: + resolution: {integrity: sha512-CxyuOl9b2CoaOOR+J8mrEIbWlD5NuDQ8IFh+mcS5jBecPfyYTz7dY1mPk7qaIEY+lauiRtrUs7yHfzLKw8AFNA==} - esbuild@0.21.5: - resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} - engines: {node: '>=12'} + esbuild@0.24.0: + resolution: {integrity: sha512-FuLPevChGDshgSicjisSooU0cemp/sGXR841D5LHMB7mTVOmsEHcAxaH3irL53+8YDIeVNQEySh4DaYU/iuPqQ==} + engines: {node: '>=18'} hasBin: true escalade@3.2.0: @@ -2932,33 +2960,20 @@ packages: peerDependencies: eslint: '>=7.0.0' - eslint-plugin-perfectionist@3.9.1: - resolution: {integrity: sha512-9WRzf6XaAxF4Oi5t/3TqKP5zUjERhasHmLFHin2Yw6ZAp/EP/EVA2dr3BhQrrHWCm5SzTMZf0FcjDnBkO2xFkA==} + eslint-plugin-perfectionist@4.1.2: + resolution: {integrity: sha512-YjXPWB/rKe/gPUsyuxw75wTUrzN5MuJnRV0PH9NoonFvgcdVIXk551mkBKPr59nRZCbu7S3dFHwfo4gA42DB2w==} engines: {node: ^18.0.0 || >=20.0.0} peerDependencies: - astro-eslint-parser: ^1.0.2 eslint: '>=8.0.0' - svelte: '>=3.0.0' - svelte-eslint-parser: ^0.41.1 - vue-eslint-parser: '>=9.0.0' - peerDependenciesMeta: - astro-eslint-parser: - optional: true - svelte: - optional: true - svelte-eslint-parser: - optional: true - vue-eslint-parser: - optional: true - eslint-plugin-react-compiler@0.0.0-experimental-19c7e06-20241113: - resolution: {integrity: sha512-6mPuGd+KxEKRohM2dlym0HkfnSMgf95GphTIJvHIMx4bcaQGFwJOB+tQNxSslnvuSbhUJRdVpSe3dFF7ZbjIsA==} + eslint-plugin-react-compiler@0.0.0-experimental-df7b47d-20241124: + resolution: {integrity: sha512-vTe5ffzXynVuWCXGs7V6KnRkED4rweKuRj++zznuQktHJOBv1lY136HakX8x40/ERWY8nOM+RUCN9XSuxL+mJw==} engines: {node: ^14.17.0 || ^16.0.0 || >= 18.0.0} peerDependencies: eslint: '>=7' - eslint-plugin-react-hooks@0.0.0-experimental-b01722d5-20241114: - resolution: {integrity: sha512-5a8wketWDcWSVHavR8l6O/ipiifdbg7WgX5GxlhUtLSclk3DoqXOvrmqvVPSB95V07xSbORYHEZlwcQ8yQwk5A==} + eslint-plugin-react-hooks@0.0.0-experimental-7670501b-20241124: + resolution: {integrity: sha512-r8KdTSNDLmTN19c1b1LZxxmyHc88L8OmrGeaDjgxM3yDXhLb3FNj6Cdde0ks0sKHl12TH1bZDzddbH3xMsjvbw==} engines: {node: '>=10'} peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 @@ -2994,8 +3009,8 @@ packages: resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@9.14.0: - resolution: {integrity: sha512-c2FHsVBr87lnUtjP4Yhvk4yEhKrQavGafRA/Se1ouse8PfbfC/Qh9Mxa00yWsZRlqeUB9raXip0aiiUZkgnr9g==} + eslint@9.16.0: + resolution: {integrity: sha512-whp8mSQI4C8VXd+fLgSM0lh3UlmcFtVwUQjyKCFfsp+2ItAIYhlq/hqGahGqHE6cv9unM41VlqKk2VtKYR2TaA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true peerDependencies: @@ -3144,8 +3159,8 @@ packages: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} - flatted@3.3.1: - resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} + flatted@3.3.2: + resolution: {integrity: sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==} for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} @@ -3168,6 +3183,9 @@ packages: formidable@3.5.2: resolution: {integrity: sha512-Jqc1btCy3QzRbJaICGwKcBfGWuLADRerLzDqi2NwSt/UkXLsHJw2TVResiaoBufHVHy9aSgClOHCeJsSsFLTbg==} + fraction.js@4.3.7: + resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} @@ -3317,11 +3335,9 @@ packages: resolution: {integrity: sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==} engines: {node: '>=18'} - globrex@0.1.2: - resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} - - gopd@1.0.1: - resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + gopd@1.1.0: + resolution: {integrity: sha512-FQoVQnqcdk4hVM4JN1eromaun4iuS34oStkdlLENLdpULsuQcTyXj8w7ayhuUfPwEYZ1ZOooOTT6fdA9Vmx/RA==} + engines: {node: '>= 0.4'} graceful-fs@4.2.10: resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} @@ -3385,8 +3401,8 @@ packages: hast-util-from-html@2.0.3: resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==} - hast-util-from-parse5@8.0.1: - resolution: {integrity: sha512-Er/Iixbc7IEa7r/XLtuG52zoqn/b3Xng/w6aZQ0xGVxzhw5xUFxcRqdPzP6yFi/4HBYRaifaI5fQ1RH8n0ZeOQ==} + hast-util-from-parse5@8.0.2: + resolution: {integrity: sha512-SfMzfdAi/zAoZ1KkFEyyeXBn7u/ShQrfd675ZEE9M3qj+PMFX05xubzRyF76CCSJu8au9jgVxDV1+okFvgZU4A==} hast-util-has-property@3.0.0: resolution: {integrity: sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==} @@ -3415,8 +3431,8 @@ packages: hast-util-to-jsx-runtime@2.3.2: resolution: {integrity: sha512-1ngXYb+V9UT5h+PxNRa1O1FYguZK/XL+gkeqvp7EdHlB9oHUG0eYRo/vY5inBdcqo3RkPMC58/H94HvkbfGdyg==} - hast-util-to-mdast@10.1.0: - resolution: {integrity: sha512-DsL/SvCK9V7+vfc6SLQ+vKIyBDXTk2KLSbfBYkH4zeF/uR1yBajHRhkzuaUSGOB1WJSTieJBdHwxlC+HLKvZZw==} + hast-util-to-mdast@10.1.1: + resolution: {integrity: sha512-ObMDBFkVPHa0/47FUPO6UuupETRXNTY9y2dGBQQzEUrFq6LjUVwZEoUjjj/agvQ6oS+fAIyNzgNEa6h3lhaoKA==} hast-util-to-text@3.1.2: resolution: {integrity: sha512-tcllLfp23dJJ+ju5wCCZHVpzsQQ43+moJbqVX3jNWPB7z/KFC4FyZD6R7y94cHL6MQ33YtMZL8Z0aIXXI4XFTw==} @@ -3427,14 +3443,14 @@ packages: hast-util-whitespace@3.0.0: resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} - hastscript@8.0.0: - resolution: {integrity: sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw==} + hastscript@9.0.0: + resolution: {integrity: sha512-jzaLBGavEDKHrc5EfFImKN7nZKKBdSLIdGvCwDZ9TfzbF2ffXiov8CKE445L2Z1Ek2t/m4SKQ2j6Ipv7NyUolw==} - hermes-estree@0.20.1: - resolution: {integrity: sha512-SQpZK4BzR48kuOg0v4pb3EAGNclzIlqMj3Opu/mu7bbAoFw6oig6cEt/RAi0zTFW/iW6Iz9X9ggGuZTAZ/yZHg==} + hermes-estree@0.25.1: + resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} - hermes-parser@0.20.1: - resolution: {integrity: sha512-BL5P83cwCogI8D7rrDCgsFY0tdYUtmFP9XaXtl2IQjC+2Xo+4okjfXintlTxcIwl4qeGddEl28Z11kbVIw0aNA==} + hermes-parser@0.25.1: + resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} hexoid@1.0.0: resolution: {integrity: sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==} @@ -3461,9 +3477,6 @@ packages: resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} engines: {node: '>=10'} - html-element-attributes@1.3.1: - resolution: {integrity: sha512-UrRKgp5sQmRnDy4TEwAUsu14XBUlzKB8U3hjIYDjcZ3Hbp86Jtftzxfgrv6E/ii/h78tsaZwAnAE8HwnHr0dPA==} - html-encoding-sniffer@4.0.0: resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} engines: {node: '>=18'} @@ -3509,6 +3522,15 @@ packages: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} + icss-replace-symbols@1.1.0: + resolution: {integrity: sha512-chIaY3Vh2mh2Q3RGXttaDIzeiPvaVXJ+C4DAh/w3c37SKZ/U6PGMmuicR2EQQp9bKG8zLMCl7I+PtIoOOPp8Gg==} + + icss-utils@5.1.0: + resolution: {integrity: sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + idb@7.1.1: resolution: {integrity: sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==} @@ -3519,9 +3541,17 @@ packages: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} + image-size@0.5.5: + resolution: {integrity: sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==} + engines: {node: '>=0.10.0'} + hasBin: true + immer@10.1.1: resolution: {integrity: sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==} + immutable@5.0.3: + resolution: {integrity: sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==} + import-fresh@3.3.0: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} engines: {node: '>=6'} @@ -3602,6 +3632,10 @@ packages: is-bigint@1.0.4: resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + is-boolean-object@1.1.2: resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} engines: {node: '>= 0.4'} @@ -3646,16 +3680,13 @@ packages: resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} engines: {node: '>=0.10.0'} - is-extendable@1.0.1: - resolution: {integrity: sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==} - engines: {node: '>=0.10.0'} - is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} - is-finalizationregistry@1.0.2: - resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==} + is-finalizationregistry@1.1.0: + resolution: {integrity: sha512-qfMdqbAQEwBw78ZyReKnlA8ezmPdb9BemzIIip/JkjaZUhitfXDkkr+3QTboW0JrSXT1QWyYShpvnNHGZ4c4yA==} + engines: {node: '>= 0.4'} is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} @@ -3745,15 +3776,11 @@ packages: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} - is-plain-object@2.0.4: - resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} - engines: {node: '>=0.10.0'} - is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} - is-regex@1.1.4: - resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} + is-regex@1.2.0: + resolution: {integrity: sha512-B6ohK4ZmoftlUe+uvenXSbPJFo6U37BH7oO1B3nQH8f/7h27N56s85MhUtbFJAziz5dcmuR3i8ovUl35zp8pFA==} engines: {node: '>= 0.4'} is-regexp@1.0.0: @@ -3771,6 +3798,9 @@ packages: is-ssh@1.4.0: resolution: {integrity: sha512-x7+VxdxOdlV3CYpjvRLBv5Lo9OJerlYanjwFrPR9fuGPjCiNiCzFgAWpiLAohSbsnH4ZAys3SBh+hq5rJosxUQ==} + is-standalone-pwa@0.1.1: + resolution: {integrity: sha512-9Cbovsa52vNQCjdXOzeQq5CnCbAcRk05aU62K20WO372NrTv0NxibLFCK6lQ4/iZEFdEA3p3t2VNOn8AJ53F5g==} + is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} @@ -3791,6 +3821,9 @@ packages: resolution: {integrity: sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==} engines: {node: '>=0.10.0'} + is-there@4.5.1: + resolution: {integrity: sha512-vIZ7HTXAoRoIwYSsTnxb0sg9L6rth+JOulNcavsbskQkCIWoSM2cjFOWZs4wGziGZER+Xgs/HXiCQZgiL8ppxQ==} + is-typed-array@1.1.13: resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} engines: {node: '>= 0.4'} @@ -3821,6 +3854,9 @@ packages: resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} engines: {node: '>= 0.4'} + is-what@3.14.1: + resolution: {integrity: sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==} + is-whitespace@0.3.0: resolution: {integrity: sha512-RydPhl4S6JwAyj0JJjshWJEFG6hNye3pZFBRZaTUfZFwGHxzppNaNOVgQuS/E/SlhrApuMXrpnK1EEIXfdo3Dg==} engines: {node: '>=0.10.0'} @@ -3845,10 +3881,6 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - isobject@3.0.1: - resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} - engines: {node: '>=0.10.0'} - issue-parser@7.0.1: resolution: {integrity: sha512-3YZcUUR2Wt1WsapF+S/WiA2WmlW0cWAoPccMqne7AxEBhCdFeTPjfv/Axb8V2gyCgY3nRw+ksZ3xSUX+R47iAg==} engines: {node: ^18.17 || >=20.6.1} @@ -3987,6 +4019,11 @@ packages: lemmy-js-client@0.20.0-alpha.18: resolution: {integrity: sha512-oZy8DboTWfUar4mPWpi7SYrOEjTBJxkvd1e6QaVwoA5UhqQV1WhxEYbzrpi/gXnEokaVQ0i5sjtL/Y2PHMO3MQ==} + less@4.2.0: + resolution: {integrity: sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==} + engines: {node: '>=6'} + hasBin: true + leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} @@ -3998,6 +4035,70 @@ packages: lighthouse-logger@1.4.2: resolution: {integrity: sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==} + lightningcss-darwin-arm64@1.28.1: + resolution: {integrity: sha512-VG3vvzM0m/rguCdm76DdobNeNJnHK+jWcdkNLFWHLh9YCotRvbRIt45JxwcHlIF8TDqWStVLTdghq5NaigVCBQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.28.1: + resolution: {integrity: sha512-O7ORdislvKfMohFl4Iq7fxKqdJOuuxArcglVI3amuFO5DJ0wfV3Gxgi1JRo49slfr7OVzJQEHLG4muTWYM5cTQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.28.1: + resolution: {integrity: sha512-b7sF89B31kYYijxVcFO7l5u6UNA862YstNu+3YbLl/IQKzveL4a5cwR5cdpG+OOhErg/c2u9WCmzZoX2I5GBvw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.28.1: + resolution: {integrity: sha512-p61kXwvhUDLLzkWHjzSFfUBW/F0iy3jr3CWi3k8SKULtJEsJXTI9DqRm9EixxMSe2AMBQBt4auTYiQL4B1N51A==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.28.1: + resolution: {integrity: sha512-iO+fN9hOMmzfwqcG2/BgUtMKD48H2JO/SXU44fyIwpY2veb65QF5xiRrQ9l1FwIxbGK3231KBYCtAqv+xf+NsQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.28.1: + resolution: {integrity: sha512-dnMHeXEmCUzHHZjaDpQBYuBKcN9nPC3nPFKl70bcj5Bkn5EmkcgEqm5p035LKOgvAwk1XwLpQCML6pXmCwz0NQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.28.1: + resolution: {integrity: sha512-7vWDISaMUn+oo2TwRdf2hl/BLdPxvywv9JKEqNZB/0K7bXwV4XE9wN/C2sAp1gGuh6QBA8lpjF4JIPt3HNlCHA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.28.1: + resolution: {integrity: sha512-IHCu9tVGP+x5BCpA2rF3D04DBokcBza/a8AuHQU+1AiMKubuMegPwcL7RatBgK4ztFHeYnnD5NdhwhRfYMAtNA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.28.1: + resolution: {integrity: sha512-Erm72kHmMg/3h350PTseskz+eEGBM17Fuu79WW2Qqt0BfWSF1jHHc12lkJCWMYl5jcBHPs5yZdgNHtJ7IJS3Uw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.28.1: + resolution: {integrity: sha512-ZPQtvx+uQBzrSdHH8p4H3M9Alue+x369TPZAA3b4K3d92FPhpZCuBG04+HQzspam9sVeID9mI6f3VRAs2ezaEA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.28.1: + resolution: {integrity: sha512-KRDkHlLlNj3DWh79CDt93fPlRJh2W1AuHV0ZSZAMMuN7lqlsZTV5842idfS1urWG8q9tc17velp1gCXhY7sLnQ==} + engines: {node: '>= 12.0.0'} + lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} @@ -4135,8 +4236,12 @@ packages: magic-string@0.25.9: resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} - magic-string@0.30.12: - resolution: {integrity: sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==} + magic-string@0.30.14: + resolution: {integrity: sha512-5c99P1WKTed11ZC0HMJOj6CDIue6F8ySu+bJL+85q1zBEIY8IklrJ1eiKC2NDRh3Ct3FcvmJPyQHb9erXMTJNw==} + + make-dir@2.1.0: + resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} + engines: {node: '>=6'} make-error@1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} @@ -4283,8 +4388,8 @@ packages: micromark-util-sanitize-uri@2.0.1: resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} - micromark-util-subtokenize@2.0.2: - resolution: {integrity: sha512-xKxhkB62vwHUuuxHe9Xqty3UaAsizV2YKq5OV344u3hFBbf8zIYrhYOWhAQb94MtMPkjTOzzjJ/hid9/dR5vFA==} + micromark-util-subtokenize@2.0.3: + resolution: {integrity: sha512-VXJJuNxYWSoYL6AJ6OQECCFGhIU2GGHMw8tahogePBrjkG8aCCas3ibkp7RnVOSTClg2is05/R7maAhF1XyQMg==} micromark-util-symbol@2.0.1: resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} @@ -4307,6 +4412,11 @@ packages: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} + mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + mime@2.6.0: resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} engines: {node: '>=4.0.0'} @@ -4385,6 +4495,11 @@ packages: engines: {node: '>=10'} hasBin: true + mkdirp@3.0.1: + resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} + engines: {node: '>=10'} + hasBin: true + modern-screenshot@4.5.4: resolution: {integrity: sha512-4O9hT31e2XqAga5tIuNe8YemB8SnjHYClD1lHu0DqgiZ4Mld6Hf4t3Oz+3RnxQm+95cMatFsmJRI1IIMub13ww==} @@ -4408,8 +4523,8 @@ packages: resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - nanoid@3.3.7: - resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + nanoid@3.3.8: + resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true @@ -4418,12 +4533,18 @@ packages: engines: {node: '>=16.0.0'} hasBin: true - natural-compare-lite@1.4.0: - resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} - natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + natural-orderby@5.0.0: + resolution: {integrity: sha512-kKHJhxwpR/Okycz4HhQKKlhWe4ASEfPgkSWNmKFHd7+ezuQlxkA5cM3+XkBPvm1gmHen3w53qsYAv+8GwRrBlg==} + engines: {node: '>=18'} + + needle@3.3.1: + resolution: {integrity: sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==} + engines: {node: '>= 4.4.x'} + hasBin: true + neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} @@ -4438,6 +4559,9 @@ packages: no-case@3.0.4: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} + node-addon-api@7.1.1: + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + node-fetch@2.6.7: resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} engines: {node: 4.x || >=6.0.0} @@ -4462,6 +4586,14 @@ packages: resolution: {integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==} engines: {node: '>=10'} + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + normalize-range@0.1.2: + resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} + engines: {node: '>=0.10.0'} + npm-run-path@4.0.1: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} @@ -4473,8 +4605,8 @@ packages: nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} - nwsapi@2.2.13: - resolution: {integrity: sha512-cTGB9ptp9dY9A5VbMSe7fQBcl/tt22Vcqdq8+eN93rblOuE0aCFu4aZ2vMwct/2t+lFnosm8RkQW1I0Omb1UtQ==} + nwsapi@2.2.16: + resolution: {integrity: sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==} object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} @@ -4500,10 +4632,6 @@ packages: resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} engines: {node: '>= 0.4'} - object.omit@3.0.0: - resolution: {integrity: sha512-EO+BCv6LJfu+gBIF3ggLicFebFLN5zqzz/WWJlMFfkMyGth+oBkhxzDl0wx2W4GkLzuQs/FsSkXZb2IMWQqmBQ==} - engines: {node: '>=0.10.0'} - object.values@1.2.0: resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} engines: {node: '>= 0.4'} @@ -4625,6 +4753,10 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} + parse-node-version@1.0.1: + resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==} + engines: {node: '>= 0.10'} + parse-path@7.0.0: resolution: {integrity: sha512-Euf9GG8WT9CdqwuWJGdf3RkUcTBArppHABkO7Lm8IzRQp0e2r/kkFnmhu4TSK30Wcu5rVAZLmfPKSBBi9tWFog==} @@ -4712,17 +4844,21 @@ packages: resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} engines: {node: '>=4'} + pify@4.0.1: + resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} + engines: {node: '>=6'} + pkg-dir@4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} - playwright-core@1.48.2: - resolution: {integrity: sha512-sjjw+qrLFlriJo64du+EK0kJgZzoQPsabGF4lBvsid+3CNIZIYLgnMj9V6JY5VhM2Peh20DJWIVpVljLLnlawA==} + playwright-core@1.49.0: + resolution: {integrity: sha512-R+3KKTQF3npy5GTiKH/T+kdhoJfJojjHESR1YEWhYuEKRVfVaxH3+4+GvXE5xyCngCxhxnykk0Vlah9v8fs3jA==} engines: {node: '>=18'} hasBin: true - playwright@1.48.2: - resolution: {integrity: sha512-NjYvYgp4BPmiwfe31j4gHLa3J7bD2WiBz8Lk2RoSsmX38SVIARZ18VYjxLjAcDsAhA+F4iSEXTSGgjua0rrlgQ==} + playwright@1.49.0: + resolution: {integrity: sha512-eKpmys0UFDnfNb3vfsf8Vx2LEOtflgRebl0Im2eQQnYMA4Aqd+Zw8bEOB+7ZKvN76901mRnqdsiOGKxzVTbi7A==} engines: {node: '>=18'} hasBin: true @@ -4734,6 +4870,37 @@ packages: resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} engines: {node: '>= 0.4'} + postcss-modules-extract-imports@3.1.0: + resolution: {integrity: sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + + postcss-modules-local-by-default@4.1.0: + resolution: {integrity: sha512-rm0bdSv4jC3BDma3s9H19ZddW0aHX6EoqwDYU2IfZhRN+53QrufTRo2IdkAbRqLx4R2IYbZnbjKKxg4VN5oU9Q==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + + postcss-modules-scope@3.2.1: + resolution: {integrity: sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + + postcss-modules-values@4.0.0: + resolution: {integrity: sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + + postcss-selector-parser@7.0.0: + resolution: {integrity: sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==} + engines: {node: '>=4'} + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + postcss@8.4.49: resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} engines: {node: ^10 || ^12 || >=14} @@ -4747,8 +4914,8 @@ packages: engines: {node: '>=10.13.0'} hasBin: true - prettier@3.3.3: - resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} + prettier@3.4.1: + resolution: {integrity: sha512-G+YdqtITVZmOJje6QkXQWzl3fSfMxFwm1tjTyo9exhkmWSqC4Yhd1+lug++IlR2mvRVAxEDDWYkQdeSztajqgg==} engines: {node: '>=14'} hasBin: true @@ -4798,6 +4965,9 @@ packages: proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + prr@1.0.1: + resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} + pump@3.0.2: resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} @@ -4826,8 +4996,8 @@ packages: (For a CapTP with native promises, see @endo/eventual-send and @endo/captp) - qs@6.13.0: - resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} + qs@6.13.1: + resolution: {integrity: sha512-EJPeIn0CYrGu+hli1xilKAPXODtJ12T0sP63Ijx2/khC2JtuaN3JyNIpvmnkmaEtha9ocbG4A4cMcr+TvqvwQg==} engines: {node: '>=0.6'} queue-microtask@1.2.3: @@ -4851,19 +5021,16 @@ packages: react: '>=16.8.0' react-dom: '>=16.8.0' - react-dom@0.0.0-experimental-b01722d5-20241114: - resolution: {integrity: sha512-UdD47xg3Eg0yj5hvNeR+VLLLOa53VJJ1vBPXD9rXYBh1oEgLss4TIWIg6jYxC7o9WshgLG+VUABbpCRUPL317w==} + react-dom@0.0.0-experimental-7670501b-20241124: + resolution: {integrity: sha512-150W/wDCbC/W8WpDowFCY3294u1WYTnpgc4owl3BVzsAkBeGxgKN1CNT4IC1xNI05CGDDG9lyGE9M0wvDj0fTQ==} peerDependencies: - react: 0.0.0-experimental-b01722d5-20241114 + react: 0.0.0-experimental-7670501b-20241124 react-error-boundary@4.1.2: resolution: {integrity: sha512-GQDxZ5Jd+Aq/qUxbCm1UtzmL/s++V7zKgE8yMktJiCQXCCFZnMZh9ng+6/Ne6PjNSXH0L9CjeOEREfRnq6Duag==} peerDependencies: react: '>=16.13.1' - react-html-attributes@1.4.6: - resolution: {integrity: sha512-uS3MmThNKFH2EZUQQw4k5pIcU7XIr208UE5dktrj/GOH1CMagqxDl4DCLpt3o2l9x+IB5nVYBeN3Cr4IutBXAg==} - react-intersection-observer@9.13.1: resolution: {integrity: sha512-tSzDaTy0qwNPLJHg8XZhlyHTgGW6drFKTtvjdL+p6um12rcnp8Z5XstE+QNBJ7c64n5o0Lj4ilUleA41bmDoMw==} peerDependencies: @@ -4929,8 +5096,8 @@ packages: react: '>=16.8.0' react-dom: '>=16.8.0' - react@0.0.0-experimental-b01722d5-20241114: - resolution: {integrity: sha512-QrufoF9PdRu/I/8ciQJy8zaYUj2LsT4Mud3FR5zqQlyawzY0Vw1zXDSNQiA9N9rUWl8rq+CG8IyqqA1vIphdNA==} + react@0.0.0-experimental-7670501b-20241124: + resolution: {integrity: sha512-A7FwEzKrEj3Trjm+EQAgGYaBriKgIfRf2q6byM8RpEip1PDG/6g8giycr0Y03JLSlkKNDoHXqq9z+YQudpCSCg==} engines: {node: '>=0.10.0'} read-pkg-up@3.0.0: @@ -4956,6 +5123,14 @@ packages: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + readdirp@4.0.2: + resolution: {integrity: sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==} + engines: {node: '>= 14.16.0'} + rechoir@0.6.2: resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} engines: {node: '>= 0.10'} @@ -4972,8 +5147,8 @@ packages: redux@5.0.1: resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==} - reflect.getprototypeof@1.0.6: - resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==} + reflect.getprototypeof@1.0.7: + resolution: {integrity: sha512-bMvFGIUKlc/eSfXNX+aZ+EL95/EgZzuwA0OBPTbZZDEJw/0AkentjMuM1oiRfwHrshqk4RzdgiTg5CcDalXN5g==} engines: {node: '>= 0.4'} regenerate-unicode-properties@10.2.0: @@ -4996,12 +5171,12 @@ packages: resolution: {integrity: sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==} engines: {node: '>= 0.4'} - regexpu-core@6.1.1: - resolution: {integrity: sha512-k67Nb9jvwJcJmVpw0jPttR1/zVfnKf8Km0IPatrU/zJ5XeG3+Slx0xLXs9HByJSzXzrlz5EDvN6yLNMDc2qdnw==} + regexpu-core@6.2.0: + resolution: {integrity: sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==} engines: {node: '>=4'} - registry-auth-token@5.0.2: - resolution: {integrity: sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==} + registry-auth-token@5.0.3: + resolution: {integrity: sha512-1bpc9IyC+e+CNFRaWyn77tk4xGG4PPUyfakSmA6F6cvUDjrm58dfyJ3II+9yb10EDkHoy1LaPSmHaWLOH3m6HA==} engines: {node: '>=14'} registry-url@6.0.1: @@ -5011,8 +5186,8 @@ packages: regjsgen@0.8.0: resolution: {integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==} - regjsparser@0.11.2: - resolution: {integrity: sha512-3OGZZ4HoLJkkAZx/48mTXJNlmqTGOzc0o9OWQPuWpkOlXXPbyN6OafCcoXUnBqE2D3f/T5L+pWc1kdEmnfnRsA==} + regjsparser@0.12.0: + resolution: {integrity: sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==} hasBin: true rehype-highlight@6.0.0: @@ -5112,8 +5287,8 @@ packages: engines: {node: '>=10.0.0'} hasBin: true - rollup@4.26.0: - resolution: {integrity: sha512-ilcl12hnWonG8f+NxU6BlgysVA0gvY2l8N0R84S1HcINbW20bvwuCngJkkInV6LXhwRpucsW5k1ovDwEdBVrNg==} + rollup@4.28.0: + resolution: {integrity: sha512-G9GOrmgWHBma4YfCcX8PjH0qhXSdH8B4HDE2o4/jaxj93S4DPCIDoLcXz99eWMji4hB29UFCEd7B2gwGJDR9cQ==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -5163,9 +5338,17 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + sass@1.81.0: + resolution: {integrity: sha512-Q4fOxRfhmv3sqCLoGfvrC9pRV8btc0UtqL9mN6Yrv6Qi9ScL55CVH1vlPP863ISLEEMNLLuu9P+enCeGHlnzhA==} + engines: {node: '>=14.0.0'} + hasBin: true + sax@1.1.4: resolution: {integrity: sha512-5f3k2PbGGp+YtKJjOItpg3P99IMD84E4HOvcfleTb5joCHNXYLsR9yWFPOYGgaeMPDubQILTCMdsFb2OMeOjtg==} + sax@1.3.0: + resolution: {integrity: sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==} + sax@1.4.1: resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} @@ -5173,8 +5356,8 @@ packages: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} engines: {node: '>=v12.22.7'} - scheduler@0.0.0-experimental-b01722d5-20241114: - resolution: {integrity: sha512-tyiYxLy5j5cKbJO4E5s7CF7MCfOF0iHeAZw895JLeigcSUOOZDh0omf8AlvJrcICclobRxu1UIWnJCkjc93jWg==} + scheduler@0.0.0-experimental-7670501b-20241124: + resolution: {integrity: sha512-3gEk9E54G93Oio+DIwptiqdPQdhU28UYOOL4F5ktKEnkFuUdTme8CDcvPOmca5Hg9URhp1tNZnW8m6gP993YdQ==} semver@5.7.2: resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} @@ -5422,8 +5605,9 @@ packages: style-to-object@1.0.8: resolution: {integrity: sha512-xT47I/Eo0rwJmaXC4oilDGDWLohVhR6o/xAQcPQN8q6QBuZVL8qMYL85kLmST5cPjAorwvqIA4qXTRQoYHaL6g==} - stylis@4.3.4: - resolution: {integrity: sha512-osIBl6BGUmSfDkyH2mB7EFvCJntXDrLhKjHTRj/rK6xLH0yuPrHULDRQzKokSOD4VoorhtKpfcfW1GAntu8now==} + stylus@0.62.0: + resolution: {integrity: sha512-v3YCf31atbwJQIMtPNX8hcQ+okD4NQaTuKGUWfII8eaqn+3otrbttGL1zSMZAAtiPsBztQnujVBugg/cXFUpyg==} + hasBin: true superagent@8.1.2: resolution: {integrity: sha512-6WTxW1EB6yCxV5VFOIPQruWGHqc3yI7hEmZK6h+pyk69Lk/Ut7rLUY6W/ONF2MjBuGjvmMiIpsrVJ2vjrHlslA==} @@ -5483,9 +5667,6 @@ packages: resolution: {integrity: sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==} engines: {node: '>=0.10'} - text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - through2@2.0.5: resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} @@ -5523,11 +5704,11 @@ packages: resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} engines: {node: '>=14.0.0'} - tldts-core@6.1.61: - resolution: {integrity: sha512-In7VffkDWUPgwa+c9picLUxvb0RltVwTkSgMNFgvlGSWveCzGBemBqTsgJCL4EDFWZ6WH0fKTsot6yNhzy3ZzQ==} + tldts-core@6.1.65: + resolution: {integrity: sha512-Uq5t0N0Oj4nQSbU8wFN1YYENvMthvwU13MQrMJRspYCGLSAZjAfoBOJki5IQpnBM/WFskxxC/gIOTwaedmHaSg==} - tldts@6.1.61: - resolution: {integrity: sha512-rv8LUyez4Ygkopqn+M6OLItAOT9FF3REpPQDkdMx5ix8w4qkuE7Vo2o/vw1nxKQYmJDV8JpAMJQr1b+lTKf0FA==} + tldts@6.1.65: + resolution: {integrity: sha512-xU9gLTfAGsADQ2PcWee6Hg8RFAv0DnjMGVJmDnUmI8a9+nYmapMQix4afwrdaCtT+AqP4MaxEzu7cCrYmBPbzQ==} hasBin: true tmp@0.0.33: @@ -5573,16 +5754,12 @@ packages: trough@2.2.0: resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} - ts-api-utils@1.4.0: - resolution: {integrity: sha512-032cPxaEKwM+GT3vA5JXNzIaizx388rhsSW79vGRNGXfRRAdEAn2mvk36PvK5HnOchyWZ7afLEXqYCvPCrzuzQ==} + ts-api-utils@1.4.3: + resolution: {integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==} engines: {node: '>=16'} peerDependencies: typescript: '>=4.2.0' - ts-invariant@0.10.3: - resolution: {integrity: sha512-uivwYcQaxAucv1CzRp2n/QdYPo4ILf9VXgH19zEIjFx2EJufV16P0JtJVpYHy89DItG6Kwj2oIUjrcK5au+4tQ==} - engines: {node: '>=8'} - ts-node@10.9.2: resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} hasBin: true @@ -5597,16 +5774,6 @@ packages: '@swc/wasm': optional: true - tsconfck@3.1.4: - resolution: {integrity: sha512-kdqWFGVJqe+KGYvlSO9NIaWn9jT1Ny4oKVzAJsKii5eoE9snzTJzL4+MMVOMn+fikWGFmKEylcXL710V/kIPJQ==} - engines: {node: ^18 || >=20} - hasBin: true - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true - tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} @@ -5641,8 +5808,8 @@ packages: resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} engines: {node: '>=12.20'} - type-fest@4.26.1: - resolution: {integrity: sha512-yOGpmOAL7CkKe/91I5O3gPICmJNLJ1G4zFYVAsRHg7M64biSnPtRj0WNQt++bRkjYOqjWXrhnUw1utzmVErAdg==} + type-fest@4.29.0: + resolution: {integrity: sha512-RPYt6dKyemXJe7I6oNstcH24myUGSReicxcHTvCLgzm4e0n8y05dGvcGB15/SoPRBmhlMthWQ9pvKyL81ko8nQ==} engines: {node: '>=16'} typed-array-buffer@1.0.2: @@ -5653,33 +5820,42 @@ packages: resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} engines: {node: '>= 0.4'} - typed-array-byte-offset@1.0.2: - resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} + typed-array-byte-offset@1.0.3: + resolution: {integrity: sha512-GsvTyUHTriq6o/bHcTd0vM7OQ9JEdlvluu9YISaA7+KzDzPaIzEeDFNkTfhdE3MYcNhNi0vq/LlegYgIs5yPAw==} engines: {node: '>= 0.4'} - typed-array-length@1.0.6: - resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} + typed-array-length@1.0.7: + resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} engines: {node: '>= 0.4'} + typed-css-modules@0.9.1: + resolution: {integrity: sha512-W2HWKncdKd+bLWsnuWB2EyuQBzZ7KJ9Byr/67KLiiyGegcN52rOveun9JR8yAvuL5IXunRMxt0eORMtAUj5bmA==} + engines: {node: '>=18.0.0'} + hasBin: true + typedarray-to-buffer@3.1.5: resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} - typescript-eslint@8.14.0: - resolution: {integrity: sha512-K8fBJHxVL3kxMmwByvz8hNdBJ8a0YqKzKDX6jRlrjMuNXyd5T2V02HIq37+OiWXvUUOXgOOGiSSOh26Mh8pC3w==} + typescript-eslint@8.16.0: + resolution: {integrity: sha512-wDkVmlY6O2do4V+lZd0GtRfbtXbeD0q9WygwXXSJnC1xorE8eqyC2L1tJimqpSeFrOzRlYtWnUp/uzgHQOgfBQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: + eslint: ^8.57.0 || ^9.0.0 typescript: '*' peerDependenciesMeta: typescript: optional: true - typescript@5.6.3: - resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} + typescript@5.7.2: + resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==} engines: {node: '>=14.17'} hasBin: true - ua-parser-js@1.0.39: - resolution: {integrity: sha512-k24RCVWlEcjkdOxYmVJgeD/0a1TiSpqLg+ZalVGV9lsnr4yqu0w7tX/x2xX6G4zpkgQnRf89lxuZ1wsbjXM8lw==} + ua-is-frozen@0.1.2: + resolution: {integrity: sha512-RwKDW2p3iyWn4UbaxpP2+VxwqXh0jpvdxsYpZ5j/MLLiQOfbsV5shpgQiw93+KMYQPcteeMQ289MaAFzs3G9pw==} + + ua-parser-js@2.0.0: + resolution: {integrity: sha512-SASgD4RlB7+SCMmlVNqrhPw0f/2pGawWBzJ2+LwGTD0GgNnrKGzPJDiraGHJDwW9Zm5DH2lTmUpqDpbZjJY4+Q==} hasBin: true uglify-js@3.19.3: @@ -5693,8 +5869,8 @@ packages: unbzip2-stream@1.4.3: resolution: {integrity: sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==} - undici-types@6.19.8: - resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + undici-types@6.20.0: + resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} unicode-canonical-property-names-ecmascript@2.0.1: resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} @@ -5855,8 +6031,8 @@ packages: vfile@6.0.3: resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} - virtua@0.37.0: - resolution: {integrity: sha512-SNVvEj4aNYgc1ayey29M8f3PtrmTlD+i8GRyrKH4u6fZLoEIX8I+0IhK3F4Ro6AxV19t+UhEVtrwBf5fY/NSdg==} + virtua@0.38.1: + resolution: {integrity: sha512-3fwjY1kI4nVLztUwlnqn+BF5Cy8NbFg4S1J/ZM+LrDK/Sbrs+l6N5wxATQfAK+2OL7bfnQ4Dc6OX2B19/BFK5Q==} peerDependencies: react: '>=16.14.0' react-dom: '>=16.14.0' @@ -5875,17 +6051,17 @@ packages: vue: optional: true - vite-node@2.1.5: - resolution: {integrity: sha512-rd0QIgx74q4S1Rd56XIiL2cYEdyWn13cunYBIuqh9mpmQr7gGS0IxXoP8R6OaZtNQQLyXSWbd4rXKYUbhFpK5w==} - engines: {node: ^18.0.0 || >=20.0.0} + vite-node@2.1.6: + resolution: {integrity: sha512-DBfJY0n9JUwnyLxPSSUmEePT21j8JZp/sR9n+/gBwQU6DcQOioPdb8/pibWfXForbirSagZCilseYIwaL3f95A==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true - vite-plugin-pwa@0.21.0: - resolution: {integrity: sha512-gnDE5sN2hdxA4vTl0pe6PCTPXqChk175jH8dZVVTBjFhWarZZoXaAdoTIKCIa8Zbx94sC0CnCOyERBWpxvry+g==} + vite-plugin-pwa@0.21.1: + resolution: {integrity: sha512-rkTbKFbd232WdiRJ9R3u+hZmf5SfQljX1b45NF6oLA6DSktEKpYllgTo1l2lkiZWMWV78pABJtFjNXfBef3/3Q==} engines: {node: '>=16.0.0'} peerDependencies: '@vite-pwa/assets-generator': ^0.2.6 - vite: ^3.1.0 || ^4.0.0 || ^5.0.0 + vite: ^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 workbox-build: ^7.3.0 workbox-window: ^7.3.0 peerDependenciesMeta: @@ -5897,30 +6073,27 @@ packages: peerDependencies: vite: '>=2.6.0' - vite-tsconfig-paths@5.1.2: - resolution: {integrity: sha512-gEIbKfJzSEv0yR3XS2QEocKetONoWkbROj6hGx0FHM18qKUojhvcokQsxQx5nMkelZq2n37zbSGCJn+FSODSjA==} - peerDependencies: - vite: '*' - peerDependenciesMeta: - vite: - optional: true - - vite@5.4.11: - resolution: {integrity: sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==} - engines: {node: ^18.0.0 || >=20.0.0} + vite@6.0.1: + resolution: {integrity: sha512-Ldn6gorLGr4mCdFnmeAOLweJxZ34HjKnDm4HGo6P66IEqTxQb36VEdFJQENKxWjupNfoIjvRUnswjn1hpYEpjQ==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true peerDependencies: - '@types/node': ^18.0.0 || >=20.0.0 + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: '>=1.21.0' less: '*' lightningcss: ^1.21.0 sass: '*' sass-embedded: '*' stylus: '*' sugarss: '*' - terser: ^5.4.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 peerDependenciesMeta: '@types/node': optional: true + jiti: + optional: true less: optional: true lightningcss: @@ -5935,16 +6108,20 @@ packages: optional: true terser: optional: true + tsx: + optional: true + yaml: + optional: true - vitest@2.1.5: - resolution: {integrity: sha512-P4ljsdpuzRTPI/kbND2sDZ4VmieerR2c9szEZpjc+98Z9ebvnXmM5+0tHEKqYZumXqlvnmfWsjeFOjXVriDG7A==} - engines: {node: ^18.0.0 || >=20.0.0} + vitest@2.1.6: + resolution: {integrity: sha512-isUCkvPL30J4c5O5hgONeFRsDmlw6kzFEdLQHLezmDdKQHy8Ke/B/dgdTMEgU0vm+iZ0TjW8GuK83DiahBoKWQ==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' - '@types/node': ^18.0.0 || >=20.0.0 - '@vitest/browser': 2.1.5 - '@vitest/ui': 2.1.5 + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + '@vitest/browser': 2.1.6 + '@vitest/ui': 2.1.6 happy-dom: '*' jsdom: '*' peerDependenciesMeta: @@ -5961,8 +6138,8 @@ packages: jsdom: optional: true - voyager-ionic-core@8.4.0: - resolution: {integrity: sha512-KrftxFWnZi9jNSGwDJIzyopqKLpjw1wrB7Cf5DxustKIxJbk8MPPxhZdl9TiVs70L4eAvxx0vAog4pmkeQZ45Q==} + voyager-ionic-core@8.4.1: + resolution: {integrity: sha512-s8UwhKGvFBOHco2Ff6AnfhzD8l2fe5AFJxDsY4gLHFir6gHS59hMd6h5Px4fOT6PaSBtf/7L6kFly3cTqg0WqQ==} w3c-xmlserializer@5.0.0: resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} @@ -6012,8 +6189,8 @@ packages: which-boxed-primitive@1.0.2: resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} - which-builtin-type@1.1.4: - resolution: {integrity: sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==} + which-builtin-type@1.2.0: + resolution: {integrity: sha512-I+qLGQ/vucCby4tf5HsLmGueEla4ZhwTBSqaooS+Y0BuxN4Cp+okmGuV+8mXZ84KDI9BA+oklo+RzKg0ONdSUA==} engines: {node: '>= 0.4'} which-collection@1.0.2: @@ -6023,8 +6200,8 @@ packages: which-module@2.0.1: resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} - which-typed-array@1.1.15: - resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} + which-typed-array@1.1.16: + resolution: {integrity: sha512-g+N+GAWiRj66DngFwHvISJd+ITsyphZvD1vChfVg6cEdnzy53GzB3oy0fUNlvhz7H7+MiqhYr26qxQShCpKTTQ==} engines: {node: '>= 0.4'} which@2.0.2: @@ -6273,6 +6450,9 @@ packages: snapshots: + '@adobe/css-tools@4.3.3': + optional: true + '@aeharding/remark-lemmy-spoiler@2.0.0': dependencies: '@types/mdast': 4.0.4 @@ -6367,7 +6547,7 @@ snapshots: dependencies: '@babel/core': 7.26.0 '@babel/helper-annotate-as-pure': 7.25.9 - regexpu-core: 6.1.1 + regexpu-core: 6.2.0 semver: 6.3.1 '@babel/helper-define-polyfill-provider@0.6.3(@babel/core@7.26.0)': @@ -6500,14 +6680,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-proposal-private-methods@7.18.6(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - transitivePeerDependencies: - - supports-color - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 @@ -6522,16 +6694,6 @@ snapshots: '@babel/core': 7.26.0 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-jsx@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - - '@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 @@ -6793,18 +6955,6 @@ snapshots: '@babel/core': 7.26.0 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-react-display-name@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - - '@babel/plugin-transform-react-jsx-development@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/plugin-transform-react-jsx': 7.25.9(@babel/core@7.26.0) - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-react-jsx-self@7.25.9(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 @@ -6815,23 +6965,6 @@ snapshots: '@babel/core': 7.26.0 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-react-jsx@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-module-imports': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.0) - '@babel/types': 7.26.0 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-react-pure-annotations@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-regenerator@7.25.9(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 @@ -6877,17 +7010,6 @@ snapshots: '@babel/core': 7.26.0 '@babel/helper-plugin-utils': 7.25.9 - '@babel/plugin-transform-typescript@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 - '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.0) - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-unicode-escapes@7.25.9(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 @@ -6993,29 +7115,6 @@ snapshots: '@babel/types': 7.26.0 esutils: 2.0.3 - '@babel/preset-react@7.25.9(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-validator-option': 7.25.9 - '@babel/plugin-transform-react-display-name': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-react-jsx': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-react-jsx-development': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-react-pure-annotations': 7.25.9(@babel/core@7.26.0) - transitivePeerDependencies: - - supports-color - - '@babel/preset-typescript@7.26.0(@babel/core@7.26.0)': - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - '@babel/helper-validator-option': 7.25.9 - '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-modules-commonjs': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-typescript': 7.25.9(@babel/core@7.26.0) - transitivePeerDependencies: - - supports-color - '@babel/runtime@7.24.7': dependencies: regenerator-runtime: 0.14.1 @@ -7051,23 +7150,22 @@ snapshots: '@babel/helper-string-parser': 7.25.9 '@babel/helper-validator-identifier': 7.25.9 - '@capacitor-community/app-icon@5.0.0(@capacitor/core@6.1.2)': + '@capacitor-community/app-icon@5.0.0(@capacitor/core@6.2.0)': dependencies: - '@capacitor/core': 6.1.2 + '@capacitor/core': 6.2.0 - '@capacitor/android@6.1.2(@capacitor/core@6.1.2)': + '@capacitor/android@6.2.0(patch_hash=a7fuehdtpweg2aifrflzmu363i)(@capacitor/core@6.2.0)': dependencies: - '@capacitor/core': 6.1.2 + '@capacitor/core': 6.2.0 - '@capacitor/app@6.0.1(@capacitor/core@6.1.2)': + '@capacitor/app@6.0.2(@capacitor/core@6.2.0)': dependencies: - '@capacitor/core': 6.1.2 + '@capacitor/core': 6.2.0 - '@capacitor/cli@6.1.2': + '@capacitor/cli@6.2.0': dependencies: '@ionic/cli-framework-output': 2.2.8 '@ionic/utils-fs': 3.1.7 - '@ionic/utils-process': 2.1.12 '@ionic/utils-subprocess': 2.1.11 '@ionic/utils-terminal': 2.3.5 commander: 9.5.0 @@ -7086,129 +7184,126 @@ snapshots: transitivePeerDependencies: - supports-color - '@capacitor/core@6.1.2': + '@capacitor/core@6.2.0': dependencies: tslib: 2.8.1 - '@capacitor/filesystem@6.0.1(@capacitor/core@6.1.2)': + '@capacitor/filesystem@6.0.2(@capacitor/core@6.2.0)': dependencies: - '@capacitor/core': 6.1.2 + '@capacitor/core': 6.2.0 - '@capacitor/haptics@6.0.1(patch_hash=isktf3ewuigcwl72katxy46idi)(@capacitor/core@6.1.2)': + '@capacitor/haptics@6.0.2(patch_hash=isktf3ewuigcwl72katxy46idi)(@capacitor/core@6.2.0)': dependencies: - '@capacitor/core': 6.1.2 + '@capacitor/core': 6.2.0 - '@capacitor/ios@6.1.2(@capacitor/core@6.1.2)': + '@capacitor/ios@6.2.0(@capacitor/core@6.2.0)': dependencies: - '@capacitor/core': 6.1.2 + '@capacitor/core': 6.2.0 - '@capacitor/keyboard@6.0.2(patch_hash=2ihcxo2fu55l7b6g5u7feswwlm)(@capacitor/core@6.1.2)': + '@capacitor/keyboard@6.0.3(patch_hash=2ihcxo2fu55l7b6g5u7feswwlm)(@capacitor/core@6.2.0)': dependencies: - '@capacitor/core': 6.1.2 + '@capacitor/core': 6.2.0 - '@capacitor/network@6.0.2(@capacitor/core@6.1.2)': + '@capacitor/network@6.0.3(@capacitor/core@6.2.0)': dependencies: - '@capacitor/core': 6.1.2 + '@capacitor/core': 6.2.0 - '@capacitor/share@6.0.2(@capacitor/core@6.1.2)': + '@capacitor/share@6.0.3(@capacitor/core@6.2.0)': dependencies: - '@capacitor/core': 6.1.2 + '@capacitor/core': 6.2.0 - '@capacitor/splash-screen@6.0.2(@capacitor/core@6.1.2)': + '@capacitor/splash-screen@6.0.3(@capacitor/core@6.2.0)': dependencies: - '@capacitor/core': 6.1.2 + '@capacitor/core': 6.2.0 - '@capacitor/status-bar@6.0.1(@capacitor/core@6.1.2)': + '@capacitor/status-bar@6.0.2(@capacitor/core@6.2.0)': dependencies: - '@capacitor/core': 6.1.2 + '@capacitor/core': 6.2.0 '@cspotcode/source-map-support@0.8.1': dependencies: '@jridgewell/trace-mapping': 0.3.9 - '@emotion/is-prop-valid@1.3.1': - dependencies: - '@emotion/memoize': 0.9.0 - - '@emotion/memoize@0.9.0': {} + '@esbuild/aix-ppc64@0.24.0': + optional: true - '@esbuild/aix-ppc64@0.21.5': + '@esbuild/android-arm64@0.24.0': optional: true - '@esbuild/android-arm64@0.21.5': + '@esbuild/android-arm@0.24.0': optional: true - '@esbuild/android-arm@0.21.5': + '@esbuild/android-x64@0.24.0': optional: true - '@esbuild/android-x64@0.21.5': + '@esbuild/darwin-arm64@0.24.0': optional: true - '@esbuild/darwin-arm64@0.21.5': + '@esbuild/darwin-x64@0.24.0': optional: true - '@esbuild/darwin-x64@0.21.5': + '@esbuild/freebsd-arm64@0.24.0': optional: true - '@esbuild/freebsd-arm64@0.21.5': + '@esbuild/freebsd-x64@0.24.0': optional: true - '@esbuild/freebsd-x64@0.21.5': + '@esbuild/linux-arm64@0.24.0': optional: true - '@esbuild/linux-arm64@0.21.5': + '@esbuild/linux-arm@0.24.0': optional: true - '@esbuild/linux-arm@0.21.5': + '@esbuild/linux-ia32@0.24.0': optional: true - '@esbuild/linux-ia32@0.21.5': + '@esbuild/linux-loong64@0.24.0': optional: true - '@esbuild/linux-loong64@0.21.5': + '@esbuild/linux-mips64el@0.24.0': optional: true - '@esbuild/linux-mips64el@0.21.5': + '@esbuild/linux-ppc64@0.24.0': optional: true - '@esbuild/linux-ppc64@0.21.5': + '@esbuild/linux-riscv64@0.24.0': optional: true - '@esbuild/linux-riscv64@0.21.5': + '@esbuild/linux-s390x@0.24.0': optional: true - '@esbuild/linux-s390x@0.21.5': + '@esbuild/linux-x64@0.24.0': optional: true - '@esbuild/linux-x64@0.21.5': + '@esbuild/netbsd-x64@0.24.0': optional: true - '@esbuild/netbsd-x64@0.21.5': + '@esbuild/openbsd-arm64@0.24.0': optional: true - '@esbuild/openbsd-x64@0.21.5': + '@esbuild/openbsd-x64@0.24.0': optional: true - '@esbuild/sunos-x64@0.21.5': + '@esbuild/sunos-x64@0.24.0': optional: true - '@esbuild/win32-arm64@0.21.5': + '@esbuild/win32-arm64@0.24.0': optional: true - '@esbuild/win32-ia32@0.21.5': + '@esbuild/win32-ia32@0.24.0': optional: true - '@esbuild/win32-x64@0.21.5': + '@esbuild/win32-x64@0.24.0': optional: true - '@eslint-community/eslint-utils@4.4.1(eslint@9.14.0)': + '@eslint-community/eslint-utils@4.4.1(eslint@9.16.0)': dependencies: - eslint: 9.14.0 + eslint: 9.16.0 eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.1': {} - '@eslint/config-array@0.18.0': + '@eslint/config-array@0.19.0': dependencies: '@eslint/object-schema': 2.1.4 debug: 4.3.7 @@ -7216,9 +7311,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/core@0.7.0': {} + '@eslint/core@0.9.0': {} - '@eslint/eslintrc@3.1.0': + '@eslint/eslintrc@3.2.0': dependencies: ajv: 6.12.6 debug: 4.3.7 @@ -7232,7 +7327,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@9.14.0': {} + '@eslint/js@9.16.0': {} '@eslint/object-schema@2.1.4': {} @@ -7329,21 +7424,21 @@ snapshots: transitivePeerDependencies: - supports-color - '@ionic/react-router@8.4.0(react-dom@0.0.0-experimental-b01722d5-20241114(react@0.0.0-experimental-b01722d5-20241114))(react-router-dom@5.3.4(react@0.0.0-experimental-b01722d5-20241114))(react-router@5.3.4(react@0.0.0-experimental-b01722d5-20241114))(react@0.0.0-experimental-b01722d5-20241114)': + '@ionic/react-router@8.4.1(react-dom@0.0.0-experimental-7670501b-20241124(react@0.0.0-experimental-7670501b-20241124))(react-router-dom@5.3.4(react@0.0.0-experimental-7670501b-20241124))(react-router@5.3.4(react@0.0.0-experimental-7670501b-20241124))(react@0.0.0-experimental-7670501b-20241124)': dependencies: - '@ionic/react': 8.4.0(react-dom@0.0.0-experimental-b01722d5-20241114(react@0.0.0-experimental-b01722d5-20241114))(react@0.0.0-experimental-b01722d5-20241114) - react: 0.0.0-experimental-b01722d5-20241114 - react-dom: 0.0.0-experimental-b01722d5-20241114(react@0.0.0-experimental-b01722d5-20241114) - react-router: 5.3.4(react@0.0.0-experimental-b01722d5-20241114) - react-router-dom: 5.3.4(react@0.0.0-experimental-b01722d5-20241114) + '@ionic/react': 8.4.1(react-dom@0.0.0-experimental-7670501b-20241124(react@0.0.0-experimental-7670501b-20241124))(react@0.0.0-experimental-7670501b-20241124) + react: 0.0.0-experimental-7670501b-20241124 + react-dom: 0.0.0-experimental-7670501b-20241124(react@0.0.0-experimental-7670501b-20241124) + react-router: 5.3.4(react@0.0.0-experimental-7670501b-20241124) + react-router-dom: 5.3.4(react@0.0.0-experimental-7670501b-20241124) tslib: 2.8.1 - '@ionic/react@8.4.0(react-dom@0.0.0-experimental-b01722d5-20241114(react@0.0.0-experimental-b01722d5-20241114))(react@0.0.0-experimental-b01722d5-20241114)': + '@ionic/react@8.4.1(react-dom@0.0.0-experimental-7670501b-20241124(react@0.0.0-experimental-7670501b-20241124))(react@0.0.0-experimental-7670501b-20241124)': dependencies: - '@ionic/core': voyager-ionic-core@8.4.0 + '@ionic/core': voyager-ionic-core@8.4.1 ionicons: 7.4.0 - react: 0.0.0-experimental-b01722d5-20241114 - react-dom: 0.0.0-experimental-b01722d5-20241114(react@0.0.0-experimental-b01722d5-20241114) + react: 0.0.0-experimental-7670501b-20241124 + react-dom: 0.0.0-experimental-7670501b-20241124(react@0.0.0-experimental-7670501b-20241124) tslib: 2.8.1 '@ionic/utils-array@2.1.5': @@ -7460,7 +7555,7 @@ snapshots: '@ionic/utils-process': 2.1.10 '@ionic/utils-stream': 3.1.5 '@ionic/utils-terminal': 2.3.3 - cross-spawn: 7.0.5 + cross-spawn: 7.0.6 debug: 4.3.7 tslib: 2.8.1 transitivePeerDependencies: @@ -7473,7 +7568,7 @@ snapshots: '@ionic/utils-process': 2.1.11 '@ionic/utils-stream': 3.1.6 '@ionic/utils-terminal': 2.3.4 - cross-spawn: 7.0.5 + cross-spawn: 7.0.6 debug: 4.3.7 tslib: 2.8.1 transitivePeerDependencies: @@ -7486,7 +7581,7 @@ snapshots: '@ionic/utils-process': 2.1.12 '@ionic/utils-stream': 3.1.7 '@ionic/utils-terminal': 2.3.5 - cross-spawn: 7.0.5 + cross-spawn: 7.0.6 debug: 4.3.7 tslib: 2.8.1 transitivePeerDependencies: @@ -7565,34 +7660,14 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 - '@jridgewell/trace-mapping@0.3.9': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.0 - - '@linaria/core@6.2.0': - dependencies: - '@wyw-in-js/processor-utils': 0.5.5 - transitivePeerDependencies: - - supports-color - - '@linaria/react@6.2.1(react@0.0.0-experimental-b01722d5-20241114)': + '@jridgewell/trace-mapping@0.3.9': dependencies: - '@emotion/is-prop-valid': 1.3.1 - '@linaria/core': 6.2.0 - '@wyw-in-js/processor-utils': 0.5.5 - '@wyw-in-js/shared': 0.5.5 - minimatch: 9.0.5 - react: 0.0.0-experimental-b01722d5-20241114 - react-html-attributes: 1.4.6 - resolve: 1.22.8 - ts-invariant: 0.10.3 - transitivePeerDependencies: - - supports-color + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 - '@mantine/hooks@7.14.0(react@0.0.0-experimental-b01722d5-20241114)': + '@mantine/hooks@7.14.3(react@0.0.0-experimental-7670501b-20241124)': dependencies: - react: 0.0.0-experimental-b01722d5-20241114 + react: 0.0.0-experimental-7670501b-20241124 '@nodelib/fs.scandir@2.1.5': dependencies: @@ -7614,19 +7689,19 @@ snapshots: '@octokit/graphql': 7.1.0 '@octokit/request': 8.4.0 '@octokit/request-error': 5.1.0 - '@octokit/types': 13.6.1 + '@octokit/types': 13.6.2 before-after-hook: 2.2.3 universal-user-agent: 6.0.1 '@octokit/endpoint@9.0.5': dependencies: - '@octokit/types': 13.6.1 + '@octokit/types': 13.6.2 universal-user-agent: 6.0.1 '@octokit/graphql@7.1.0': dependencies: '@octokit/request': 8.4.0 - '@octokit/types': 13.6.1 + '@octokit/types': 13.6.2 universal-user-agent: 6.0.1 '@octokit/openapi-types@22.2.0': {} @@ -7634,7 +7709,7 @@ snapshots: '@octokit/plugin-paginate-rest@11.3.1(@octokit/core@5.2.0)': dependencies: '@octokit/core': 5.2.0 - '@octokit/types': 13.6.1 + '@octokit/types': 13.6.2 '@octokit/plugin-request-log@4.0.1(@octokit/core@5.2.0)': dependencies: @@ -7643,11 +7718,11 @@ snapshots: '@octokit/plugin-rest-endpoint-methods@13.2.2(@octokit/core@5.2.0)': dependencies: '@octokit/core': 5.2.0 - '@octokit/types': 13.6.1 + '@octokit/types': 13.6.2 '@octokit/request-error@5.1.0': dependencies: - '@octokit/types': 13.6.1 + '@octokit/types': 13.6.2 deprecation: 2.3.1 once: 1.4.0 @@ -7655,7 +7730,7 @@ snapshots: dependencies: '@octokit/endpoint': 9.0.5 '@octokit/request-error': 5.1.0 - '@octokit/types': 13.6.1 + '@octokit/types': 13.6.2 universal-user-agent: 6.0.1 '@octokit/rest@20.1.1': @@ -7665,18 +7740,79 @@ snapshots: '@octokit/plugin-request-log': 4.0.1(@octokit/core@5.2.0) '@octokit/plugin-rest-endpoint-methods': 13.2.2(@octokit/core@5.2.0) - '@octokit/types@13.6.1': + '@octokit/types@13.6.2': dependencies: '@octokit/openapi-types': 22.2.0 '@one-ini/wasm@0.1.1': {} + '@parcel/watcher-android-arm64@2.5.0': + optional: true + + '@parcel/watcher-darwin-arm64@2.5.0': + optional: true + + '@parcel/watcher-darwin-x64@2.5.0': + optional: true + + '@parcel/watcher-freebsd-x64@2.5.0': + optional: true + + '@parcel/watcher-linux-arm-glibc@2.5.0': + optional: true + + '@parcel/watcher-linux-arm-musl@2.5.0': + optional: true + + '@parcel/watcher-linux-arm64-glibc@2.5.0': + optional: true + + '@parcel/watcher-linux-arm64-musl@2.5.0': + optional: true + + '@parcel/watcher-linux-x64-glibc@2.5.0': + optional: true + + '@parcel/watcher-linux-x64-musl@2.5.0': + optional: true + + '@parcel/watcher-win32-arm64@2.5.0': + optional: true + + '@parcel/watcher-win32-ia32@2.5.0': + optional: true + + '@parcel/watcher-win32-x64@2.5.0': + optional: true + + '@parcel/watcher@2.5.0': + dependencies: + detect-libc: 1.0.3 + is-glob: 4.0.3 + micromatch: 4.0.8 + node-addon-api: 7.1.1 + optionalDependencies: + '@parcel/watcher-android-arm64': 2.5.0 + '@parcel/watcher-darwin-arm64': 2.5.0 + '@parcel/watcher-darwin-x64': 2.5.0 + '@parcel/watcher-freebsd-x64': 2.5.0 + '@parcel/watcher-linux-arm-glibc': 2.5.0 + '@parcel/watcher-linux-arm-musl': 2.5.0 + '@parcel/watcher-linux-arm64-glibc': 2.5.0 + '@parcel/watcher-linux-arm64-musl': 2.5.0 + '@parcel/watcher-linux-x64-glibc': 2.5.0 + '@parcel/watcher-linux-x64-musl': 2.5.0 + '@parcel/watcher-win32-arm64': 2.5.0 + '@parcel/watcher-win32-ia32': 2.5.0 + '@parcel/watcher-win32-x64': 2.5.0 + optional: true + '@pkgjs/parseargs@0.11.0': optional: true - '@playwright/test@1.48.2': + '@playwright/test@1.49.0': dependencies: - playwright: 1.48.2 + playwright: 1.49.0 '@pnpm/config.env-replace@1.1.0': {} @@ -7693,22 +7829,22 @@ snapshots: '@prettier/plugin-xml@1.2.0': dependencies: '@xml-tools/parser': 1.0.11 - prettier: 3.3.3 + prettier: 3.4.1 '@prettier/plugin-xml@2.2.0': dependencies: '@xml-tools/parser': 1.0.11 - prettier: 3.3.3 + prettier: 3.4.1 - '@reduxjs/toolkit@2.3.0(react-redux@9.1.2(@types/react@18.3.12)(react@0.0.0-experimental-b01722d5-20241114)(redux@5.0.1))(react@0.0.0-experimental-b01722d5-20241114)': + '@reduxjs/toolkit@2.4.0(react-redux@9.1.2(@types/react@18.3.12)(react@0.0.0-experimental-7670501b-20241124)(redux@5.0.1))(react@0.0.0-experimental-7670501b-20241124)': dependencies: immer: 10.1.1 redux: 5.0.1 redux-thunk: 3.1.0(redux@5.0.1) reselect: 5.1.1 optionalDependencies: - react: 0.0.0-experimental-b01722d5-20241114 - react-redux: 9.1.2(@types/react@18.3.12)(react@0.0.0-experimental-b01722d5-20241114)(redux@5.0.1) + react: 0.0.0-experimental-7670501b-20241124 + react-redux: 9.1.2(@types/react@18.3.12)(react@0.0.0-experimental-7670501b-20241124)(redux@5.0.1) '@rollup/plugin-babel@5.3.1(@babel/core@7.26.0)(@types/babel__core@7.20.5)(rollup@2.79.2)': dependencies: @@ -7760,65 +7896,65 @@ snapshots: optionalDependencies: rollup: 2.79.2 - '@rollup/rollup-android-arm-eabi@4.26.0': + '@rollup/rollup-android-arm-eabi@4.28.0': optional: true - '@rollup/rollup-android-arm64@4.26.0': + '@rollup/rollup-android-arm64@4.28.0': optional: true - '@rollup/rollup-darwin-arm64@4.26.0': + '@rollup/rollup-darwin-arm64@4.28.0': optional: true - '@rollup/rollup-darwin-x64@4.26.0': + '@rollup/rollup-darwin-x64@4.28.0': optional: true - '@rollup/rollup-freebsd-arm64@4.26.0': + '@rollup/rollup-freebsd-arm64@4.28.0': optional: true - '@rollup/rollup-freebsd-x64@4.26.0': + '@rollup/rollup-freebsd-x64@4.28.0': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.26.0': + '@rollup/rollup-linux-arm-gnueabihf@4.28.0': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.26.0': + '@rollup/rollup-linux-arm-musleabihf@4.28.0': optional: true - '@rollup/rollup-linux-arm64-gnu@4.26.0': + '@rollup/rollup-linux-arm64-gnu@4.28.0': optional: true - '@rollup/rollup-linux-arm64-musl@4.26.0': + '@rollup/rollup-linux-arm64-musl@4.28.0': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.26.0': + '@rollup/rollup-linux-powerpc64le-gnu@4.28.0': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.26.0': + '@rollup/rollup-linux-riscv64-gnu@4.28.0': optional: true - '@rollup/rollup-linux-s390x-gnu@4.26.0': + '@rollup/rollup-linux-s390x-gnu@4.28.0': optional: true - '@rollup/rollup-linux-x64-gnu@4.26.0': + '@rollup/rollup-linux-x64-gnu@4.28.0': optional: true - '@rollup/rollup-linux-x64-musl@4.26.0': + '@rollup/rollup-linux-x64-musl@4.28.0': optional: true - '@rollup/rollup-win32-arm64-msvc@4.26.0': + '@rollup/rollup-win32-arm64-msvc@4.28.0': optional: true - '@rollup/rollup-win32-ia32-msvc@4.26.0': + '@rollup/rollup-win32-ia32-msvc@4.28.0': optional: true - '@rollup/rollup-win32-x64-msvc@4.26.0': + '@rollup/rollup-win32-x64-msvc@4.28.0': optional: true '@sindresorhus/merge-streams@2.3.0': {} '@stencil/core@4.20.0': {} - '@stencil/core@4.22.2': {} + '@stencil/core@4.22.3': {} '@surma/rollup-plugin-off-main-thread@2.2.3': dependencies: @@ -7871,12 +8007,12 @@ snapshots: '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.26.0) '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.26.0) - '@svgr/core@8.1.0(typescript@5.6.3)': + '@svgr/core@8.1.0(typescript@5.7.2)': dependencies: '@babel/core': 7.26.0 '@svgr/babel-preset': 8.1.0(@babel/core@7.26.0) camelcase: 6.3.0 - cosmiconfig: 8.3.6(typescript@5.6.3) + cosmiconfig: 8.3.6(typescript@5.7.2) snake-case: 3.0.4 transitivePeerDependencies: - supports-color @@ -7887,11 +8023,11 @@ snapshots: '@babel/types': 7.26.0 entities: 4.5.0 - '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.6.3))': + '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.7.2))': dependencies: '@babel/core': 7.26.0 '@svgr/babel-preset': 8.1.0(@babel/core@7.26.0) - '@svgr/core': 8.1.0(typescript@5.6.3) + '@svgr/core': 8.1.0(typescript@5.7.2) '@svgr/hast-util-to-babel-ast': 8.0.0 svg-parser: 2.0.4 transitivePeerDependencies: @@ -7899,14 +8035,14 @@ snapshots: '@tootallnate/quickjs-emscripten@0.23.0': {} - '@trapezedev/configure@7.1.3(@types/node@22.9.0)(typescript@5.6.3)': + '@trapezedev/configure@7.1.3(@types/node@22.10.1)(typescript@5.7.2)': dependencies: '@ionic/cli-framework-output': 2.2.8 '@ionic/utils-fs': 3.1.7 '@ionic/utils-subprocess': 2.1.14 '@ionic/utils-terminal': 2.3.5 '@prettier/plugin-xml': 1.2.0 - '@trapezedev/project': 7.1.3(@types/node@22.9.0)(typescript@5.6.3) + '@trapezedev/project': 7.1.3(@types/node@22.10.1)(typescript@5.7.2) '@types/fs-extra': 9.0.13 '@types/jest': 27.5.2 '@types/lodash': 4.17.13 @@ -7922,7 +8058,7 @@ snapshots: prompts: 2.4.2 replace: 1.2.2 tmp: 0.2.3 - ts-node: 10.9.2(@types/node@22.9.0)(typescript@5.6.3) + ts-node: 10.9.2(@types/node@22.10.1)(typescript@5.7.2) yaml: 1.10.2 yargs: 17.7.2 transitivePeerDependencies: @@ -7934,7 +8070,7 @@ snapshots: '@trapezedev/gradle-parse@7.1.3': {} - '@trapezedev/project@7.1.3(@types/node@22.9.0)(typescript@5.6.3)': + '@trapezedev/project@7.1.3(@types/node@22.10.1)(typescript@5.7.2)': dependencies: '@ionic/utils-fs': 3.1.7 '@ionic/utils-subprocess': 2.1.14 @@ -7942,7 +8078,7 @@ snapshots: '@trapezedev/gradle-parse': 7.1.3 '@xmldom/xmldom': 0.7.13 conventional-changelog: 3.1.25 - cross-spawn: 7.0.5 + cross-spawn: 7.0.6 diff: 5.2.0 env-paths: 3.0.0 gradle-to-js: 2.0.1 @@ -7956,7 +8092,7 @@ snapshots: replace: 1.2.2 tempy: 1.0.1 tmp: 0.2.3 - ts-node: 10.9.2(@types/node@22.9.0)(typescript@5.6.3) + ts-node: 10.9.2(@types/node@22.10.1)(typescript@5.7.2) xcode: 3.0.1 xml-js: 1.6.11 xpath: 0.0.32 @@ -8011,11 +8147,11 @@ snapshots: '@types/fs-extra@8.1.5': dependencies: - '@types/node': 22.9.0 + '@types/node': 22.10.1 '@types/fs-extra@9.0.13': dependencies: - '@types/node': 22.9.0 + '@types/node': 22.10.1 '@types/hast@2.3.10': dependencies: @@ -8044,20 +8180,20 @@ snapshots: '@types/ms@0.7.34': {} - '@types/node@22.9.0': + '@types/node@22.10.1': dependencies: - undici-types: 6.19.8 + undici-types: 6.20.0 '@types/normalize-package-data@2.4.4': {} '@types/plist@3.0.5': dependencies: - '@types/node': 22.9.0 + '@types/node': 22.10.1 xmlbuilder: 15.1.1 '@types/prompts@2.4.9': dependencies: - '@types/node': 22.9.0 + '@types/node': 22.10.1 kleur: 3.0.3 '@types/prop-types@15.7.13': {} @@ -8102,37 +8238,37 @@ snapshots: '@types/yauzl@2.10.3': dependencies: - '@types/node': 22.9.0 + '@types/node': 22.10.1 optional: true - '@typescript-eslint/eslint-plugin@8.14.0(@typescript-eslint/parser@8.14.0(eslint@9.14.0)(typescript@5.6.3))(eslint@9.14.0)(typescript@5.6.3)': + '@typescript-eslint/eslint-plugin@8.16.0(@typescript-eslint/parser@8.16.0(eslint@9.16.0)(typescript@5.7.2))(eslint@9.16.0)(typescript@5.7.2)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.14.0(eslint@9.14.0)(typescript@5.6.3) - '@typescript-eslint/scope-manager': 8.14.0 - '@typescript-eslint/type-utils': 8.14.0(eslint@9.14.0)(typescript@5.6.3) - '@typescript-eslint/utils': 8.14.0(eslint@9.14.0)(typescript@5.6.3) - '@typescript-eslint/visitor-keys': 8.14.0 - eslint: 9.14.0 + '@typescript-eslint/parser': 8.16.0(eslint@9.16.0)(typescript@5.7.2) + '@typescript-eslint/scope-manager': 8.16.0 + '@typescript-eslint/type-utils': 8.16.0(eslint@9.16.0)(typescript@5.7.2) + '@typescript-eslint/utils': 8.16.0(eslint@9.16.0)(typescript@5.7.2) + '@typescript-eslint/visitor-keys': 8.16.0 + eslint: 9.16.0 graphemer: 1.4.0 ignore: 5.3.2 natural-compare: 1.4.0 - ts-api-utils: 1.4.0(typescript@5.6.3) + ts-api-utils: 1.4.3(typescript@5.7.2) optionalDependencies: - typescript: 5.6.3 + typescript: 5.7.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.14.0(eslint@9.14.0)(typescript@5.6.3)': + '@typescript-eslint/parser@8.16.0(eslint@9.16.0)(typescript@5.7.2)': dependencies: - '@typescript-eslint/scope-manager': 8.14.0 - '@typescript-eslint/types': 8.14.0 - '@typescript-eslint/typescript-estree': 8.14.0(typescript@5.6.3) - '@typescript-eslint/visitor-keys': 8.14.0 + '@typescript-eslint/scope-manager': 8.16.0 + '@typescript-eslint/types': 8.16.0 + '@typescript-eslint/typescript-estree': 8.16.0(typescript@5.7.2) + '@typescript-eslint/visitor-keys': 8.16.0 debug: 4.3.7 - eslint: 9.14.0 + eslint: 9.16.0 optionalDependencies: - typescript: 5.6.3 + typescript: 5.7.2 transitivePeerDependencies: - supports-color @@ -8141,28 +8277,28 @@ snapshots: '@typescript-eslint/types': 7.18.0 '@typescript-eslint/visitor-keys': 7.18.0 - '@typescript-eslint/scope-manager@8.14.0': + '@typescript-eslint/scope-manager@8.16.0': dependencies: - '@typescript-eslint/types': 8.14.0 - '@typescript-eslint/visitor-keys': 8.14.0 + '@typescript-eslint/types': 8.16.0 + '@typescript-eslint/visitor-keys': 8.16.0 - '@typescript-eslint/type-utils@8.14.0(eslint@9.14.0)(typescript@5.6.3)': + '@typescript-eslint/type-utils@8.16.0(eslint@9.16.0)(typescript@5.7.2)': dependencies: - '@typescript-eslint/typescript-estree': 8.14.0(typescript@5.6.3) - '@typescript-eslint/utils': 8.14.0(eslint@9.14.0)(typescript@5.6.3) + '@typescript-eslint/typescript-estree': 8.16.0(typescript@5.7.2) + '@typescript-eslint/utils': 8.16.0(eslint@9.16.0)(typescript@5.7.2) debug: 4.3.7 - ts-api-utils: 1.4.0(typescript@5.6.3) + eslint: 9.16.0 + ts-api-utils: 1.4.3(typescript@5.7.2) optionalDependencies: - typescript: 5.6.3 + typescript: 5.7.2 transitivePeerDependencies: - - eslint - supports-color '@typescript-eslint/types@7.18.0': {} - '@typescript-eslint/types@8.14.0': {} + '@typescript-eslint/types@8.16.0': {} - '@typescript-eslint/typescript-estree@7.18.0(typescript@5.6.3)': + '@typescript-eslint/typescript-estree@7.18.0(typescript@5.7.2)': dependencies: '@typescript-eslint/types': 7.18.0 '@typescript-eslint/visitor-keys': 7.18.0 @@ -8171,172 +8307,128 @@ snapshots: is-glob: 4.0.3 minimatch: 9.0.5 semver: 7.6.3 - ts-api-utils: 1.4.0(typescript@5.6.3) + ts-api-utils: 1.4.3(typescript@5.7.2) optionalDependencies: - typescript: 5.6.3 + typescript: 5.7.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@8.14.0(typescript@5.6.3)': + '@typescript-eslint/typescript-estree@8.16.0(typescript@5.7.2)': dependencies: - '@typescript-eslint/types': 8.14.0 - '@typescript-eslint/visitor-keys': 8.14.0 + '@typescript-eslint/types': 8.16.0 + '@typescript-eslint/visitor-keys': 8.16.0 debug: 4.3.7 fast-glob: 3.3.2 is-glob: 4.0.3 minimatch: 9.0.5 semver: 7.6.3 - ts-api-utils: 1.4.0(typescript@5.6.3) + ts-api-utils: 1.4.3(typescript@5.7.2) optionalDependencies: - typescript: 5.6.3 + typescript: 5.7.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@7.18.0(eslint@9.14.0)(typescript@5.6.3)': + '@typescript-eslint/utils@7.18.0(eslint@9.16.0)(typescript@5.7.2)': dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@9.14.0) + '@eslint-community/eslint-utils': 4.4.1(eslint@9.16.0) '@typescript-eslint/scope-manager': 7.18.0 '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.6.3) - eslint: 9.14.0 + '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.7.2) + eslint: 9.16.0 transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/utils@8.14.0(eslint@9.14.0)(typescript@5.6.3)': + '@typescript-eslint/utils@8.16.0(eslint@9.16.0)(typescript@5.7.2)': dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@9.14.0) - '@typescript-eslint/scope-manager': 8.14.0 - '@typescript-eslint/types': 8.14.0 - '@typescript-eslint/typescript-estree': 8.14.0(typescript@5.6.3) - eslint: 9.14.0 + '@eslint-community/eslint-utils': 4.4.1(eslint@9.16.0) + '@typescript-eslint/scope-manager': 8.16.0 + '@typescript-eslint/types': 8.16.0 + '@typescript-eslint/typescript-estree': 8.16.0(typescript@5.7.2) + eslint: 9.16.0 + optionalDependencies: + typescript: 5.7.2 transitivePeerDependencies: - supports-color - - typescript '@typescript-eslint/visitor-keys@7.18.0': dependencies: '@typescript-eslint/types': 7.18.0 eslint-visitor-keys: 3.4.3 - '@typescript-eslint/visitor-keys@8.14.0': + '@typescript-eslint/visitor-keys@8.16.0': dependencies: - '@typescript-eslint/types': 8.14.0 - eslint-visitor-keys: 3.4.3 + '@typescript-eslint/types': 8.16.0 + eslint-visitor-keys: 4.2.0 '@ungap/structured-clone@1.2.0': {} - '@vitejs/plugin-legacy@5.4.3(terser@5.36.0)(vite@5.4.11(@types/node@22.9.0)(terser@5.36.0))': + '@vitejs/plugin-legacy@6.0.0(terser@5.36.0)(vite@6.0.1(@types/node@22.10.1)(less@4.2.0)(lightningcss@1.28.1)(sass@1.81.0)(stylus@0.62.0)(terser@5.36.0))': dependencies: '@babel/core': 7.26.0 '@babel/preset-env': 7.26.0(@babel/core@7.26.0) browserslist: 4.24.2 browserslist-to-esbuild: 2.1.1(browserslist@4.24.2) core-js: 3.39.0 - magic-string: 0.30.12 + magic-string: 0.30.14 regenerator-runtime: 0.14.1 systemjs: 6.15.1 terser: 5.36.0 - vite: 5.4.11(@types/node@22.9.0)(terser@5.36.0) + vite: 6.0.1(@types/node@22.10.1)(less@4.2.0)(lightningcss@1.28.1)(sass@1.81.0)(stylus@0.62.0)(terser@5.36.0) transitivePeerDependencies: - supports-color - '@vitejs/plugin-react@4.3.3(vite@5.4.11(@types/node@22.9.0)(terser@5.36.0))': + '@vitejs/plugin-react@4.3.4(vite@6.0.1(@types/node@22.10.1)(less@4.2.0)(lightningcss@1.28.1)(sass@1.81.0)(stylus@0.62.0)(terser@5.36.0))': dependencies: '@babel/core': 7.26.0 '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.0) '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.0) '@types/babel__core': 7.20.5 react-refresh: 0.14.2 - vite: 5.4.11(@types/node@22.9.0)(terser@5.36.0) + vite: 6.0.1(@types/node@22.10.1)(less@4.2.0)(lightningcss@1.28.1)(sass@1.81.0)(stylus@0.62.0)(terser@5.36.0) transitivePeerDependencies: - supports-color - '@vitest/expect@2.1.5': + '@vitest/expect@2.1.6': dependencies: - '@vitest/spy': 2.1.5 - '@vitest/utils': 2.1.5 + '@vitest/spy': 2.1.6 + '@vitest/utils': 2.1.6 chai: 5.1.2 tinyrainbow: 1.2.0 - '@vitest/mocker@2.1.5(vite@5.4.11(@types/node@22.9.0)(terser@5.36.0))': + '@vitest/mocker@2.1.6(vite@6.0.1(@types/node@22.10.1)(less@4.2.0)(lightningcss@1.28.1)(sass@1.81.0)(stylus@0.62.0)(terser@5.36.0))': dependencies: - '@vitest/spy': 2.1.5 + '@vitest/spy': 2.1.6 estree-walker: 3.0.3 - magic-string: 0.30.12 + magic-string: 0.30.14 optionalDependencies: - vite: 5.4.11(@types/node@22.9.0)(terser@5.36.0) + vite: 6.0.1(@types/node@22.10.1)(less@4.2.0)(lightningcss@1.28.1)(sass@1.81.0)(stylus@0.62.0)(terser@5.36.0) - '@vitest/pretty-format@2.1.5': + '@vitest/pretty-format@2.1.6': dependencies: tinyrainbow: 1.2.0 - '@vitest/runner@2.1.5': + '@vitest/runner@2.1.6': dependencies: - '@vitest/utils': 2.1.5 + '@vitest/utils': 2.1.6 pathe: 1.1.2 - '@vitest/snapshot@2.1.5': + '@vitest/snapshot@2.1.6': dependencies: - '@vitest/pretty-format': 2.1.5 - magic-string: 0.30.12 + '@vitest/pretty-format': 2.1.6 + magic-string: 0.30.14 pathe: 1.1.2 - '@vitest/spy@2.1.5': + '@vitest/spy@2.1.6': dependencies: tinyspy: 3.0.2 - '@vitest/utils@2.1.5': + '@vitest/utils@2.1.6': dependencies: - '@vitest/pretty-format': 2.1.5 + '@vitest/pretty-format': 2.1.6 loupe: 3.1.2 tinyrainbow: 1.2.0 - '@wyw-in-js/processor-utils@0.5.5': - dependencies: - '@babel/generator': 7.26.2 - '@wyw-in-js/shared': 0.5.5 - transitivePeerDependencies: - - supports-color - - '@wyw-in-js/shared@0.5.5': - dependencies: - debug: 4.3.7 - find-up: 5.0.0 - minimatch: 9.0.5 - transitivePeerDependencies: - - supports-color - - '@wyw-in-js/transform@0.5.5(typescript@5.6.3)': - dependencies: - '@babel/core': 7.26.0 - '@babel/generator': 7.26.2 - '@babel/helper-module-imports': 7.25.9 - '@babel/plugin-transform-modules-commonjs': 7.25.9(@babel/core@7.26.0) - '@babel/template': 7.25.9 - '@babel/traverse': 7.25.9 - '@babel/types': 7.26.0 - '@wyw-in-js/processor-utils': 0.5.5 - '@wyw-in-js/shared': 0.5.5 - babel-merge: 3.0.0(@babel/core@7.26.0) - cosmiconfig: 8.3.6(typescript@5.6.3) - happy-dom: 15.11.6 - source-map: 0.7.4 - stylis: 4.3.4 - ts-invariant: 0.10.3 - transitivePeerDependencies: - - supports-color - - typescript - - '@wyw-in-js/vite@0.5.5(typescript@5.6.3)(vite@5.4.11(@types/node@22.9.0)(terser@5.36.0))': - dependencies: - '@wyw-in-js/shared': 0.5.5 - '@wyw-in-js/transform': 0.5.5(typescript@5.6.3) - vite: 5.4.11(@types/node@22.9.0)(terser@5.36.0) - transitivePeerDependencies: - - supports-color - - typescript - '@xml-tools/parser@1.0.11': dependencies: chevrotain: 7.1.1 @@ -8419,6 +8511,11 @@ snapshots: ansi-styles@6.2.1: {} + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + arg@4.1.3: {} argparse@2.0.1: {} @@ -8510,15 +8607,19 @@ snapshots: stubborn-fs: 1.2.5 when-exit: 2.1.3 - available-typed-arrays@1.0.7: + autoprefixer@10.4.20(postcss@8.4.49): dependencies: - possible-typed-array-names: 1.0.0 + browserslist: 4.24.2 + caniuse-lite: 1.0.30001684 + fraction.js: 4.3.7 + normalize-range: 0.1.2 + picocolors: 1.1.1 + postcss: 8.4.49 + postcss-value-parser: 4.2.0 - babel-merge@3.0.0(@babel/core@7.26.0): + available-typed-arrays@1.0.7: dependencies: - '@babel/core': 7.26.0 - deepmerge: 2.2.1 - object.omit: 3.0.0 + possible-typed-array-names: 1.0.0 babel-plugin-polyfill-corejs2@0.4.12(@babel/core@7.26.0): dependencies: @@ -8544,7 +8645,7 @@ snapshots: transitivePeerDependencies: - supports-color - babel-plugin-react-compiler@0.0.0-experimental-19c7e06-20241113: + babel-plugin-react-compiler@0.0.0-experimental-df7b47d-20241124: dependencies: '@babel/types': 7.26.0 @@ -8560,6 +8661,8 @@ snapshots: big-integer@1.6.52: {} + binary-extensions@2.3.0: {} + bl@4.1.0: dependencies: buffer: 5.7.1 @@ -8575,7 +8678,7 @@ snapshots: chalk: 5.3.0 cli-boxes: 3.0.0 string-width: 7.2.0 - type-fest: 4.26.1 + type-fest: 4.29.0 widest-line: 5.0.0 wrap-ansi: 9.0.0 @@ -8611,8 +8714,8 @@ snapshots: browserslist@4.24.2: dependencies: - caniuse-lite: 1.0.30001680 - electron-to-chromium: 1.5.59 + caniuse-lite: 1.0.30001684 + electron-to-chromium: 1.5.67 node-releases: 2.0.18 update-browserslist-db: 1.1.1(browserslist@4.24.2) @@ -8653,39 +8756,39 @@ snapshots: camelcase@8.0.0: {} - caniuse-lite@1.0.30001680: {} + caniuse-lite@1.0.30001684: {} - capacitor-android-nav-mode@1.0.0(@capacitor/core@6.1.2): + capacitor-android-nav-mode@1.0.0(@capacitor/core@6.2.0): dependencies: - '@capacitor/core': 6.1.2 + '@capacitor/core': 6.2.0 - capacitor-application-context@1.0.0(@capacitor/core@6.1.2): + capacitor-application-context@1.0.0(@capacitor/core@6.2.0): dependencies: - '@capacitor/core': 6.1.2 + '@capacitor/core': 6.2.0 - capacitor-biometric-lock@1.0.0(@capacitor/core@6.1.2): + capacitor-biometric-lock@1.0.0(@capacitor/core@6.2.0): dependencies: - '@capacitor/core': 6.1.2 + '@capacitor/core': 6.2.0 - capacitor-clear-cache@1.0.1(@capacitor/core@6.1.2): + capacitor-clear-cache@1.0.1(@capacitor/core@6.2.0): dependencies: - '@capacitor/core': 6.1.2 + '@capacitor/core': 6.2.0 - capacitor-launch-native@1.0.0(@capacitor/core@6.1.2): + capacitor-launch-native@1.0.0(@capacitor/core@6.2.0): dependencies: - '@capacitor/core': 6.1.2 + '@capacitor/core': 6.2.0 - capacitor-plugin-safe-area@3.0.3(@capacitor/core@6.1.2): + capacitor-plugin-safe-area@3.0.3(@capacitor/core@6.2.0): dependencies: - '@capacitor/core': 6.1.2 + '@capacitor/core': 6.2.0 - capacitor-reader@0.1.0(@capacitor/core@6.1.2): + capacitor-reader@0.2.0(@capacitor/core@6.2.0): dependencies: - '@capacitor/core': 6.1.2 + '@capacitor/core': 6.2.0 - capacitor-stash-media@2.0.1(@capacitor/core@6.1.2): + capacitor-stash-media@2.0.1(@capacitor/core@6.2.0): dependencies: - '@capacitor/core': 6.1.2 + '@capacitor/core': 6.2.0 ccount@2.0.1: {} @@ -8745,13 +8848,30 @@ snapshots: dependencies: regexp-to-ast: 0.5.0 + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + chokidar@4.0.1: + dependencies: + readdirp: 4.0.2 + optional: true + chownr@1.1.4: {} chownr@2.0.0: {} chrome-launcher@0.15.2: dependencies: - '@types/node': 22.9.0 + '@types/node': 22.10.1 escape-string-regexp: 4.0.0 is-wsl: 2.2.0 lighthouse-logger: 1.4.2 @@ -8962,6 +9082,11 @@ snapshots: cookiejar@2.1.4: {} + copy-anything@2.0.6: + dependencies: + is-what: 3.14.1 + optional: true + core-js-compat@3.39.0: dependencies: browserslist: 4.24.2 @@ -8970,23 +9095,23 @@ snapshots: core-util-is@1.0.3: {} - cosmiconfig@8.3.6(typescript@5.6.3): + cosmiconfig@8.3.6(typescript@5.7.2): dependencies: import-fresh: 3.3.0 js-yaml: 4.1.0 parse-json: 5.2.0 path-type: 4.0.0 optionalDependencies: - typescript: 5.6.3 + typescript: 5.7.2 - cosmiconfig@9.0.0(typescript@5.6.3): + cosmiconfig@9.0.0(typescript@5.7.2): dependencies: env-paths: 2.2.1 import-fresh: 3.3.0 js-yaml: 4.1.0 parse-json: 5.2.0 optionalDependencies: - typescript: 5.6.3 + typescript: 5.7.2 create-require@1.1.1: {} @@ -8996,7 +9121,7 @@ snapshots: transitivePeerDependencies: - encoding - cross-spawn@7.0.5: + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 @@ -9014,6 +9139,8 @@ snapshots: css-what@6.1.0: {} + cssesc@3.0.0: {} + cssstyle@4.1.0: dependencies: rrweb-cssom: 0.7.1 @@ -9082,8 +9209,6 @@ snapshots: deep-is@0.1.4: {} - deepmerge@2.2.1: {} - deepmerge@4.3.1: {} default-browser-id@5.0.0: {} @@ -9101,7 +9226,7 @@ snapshots: dependencies: es-define-property: 1.0.0 es-errors: 1.3.0 - gopd: 1.0.1 + gopd: 1.1.0 define-lazy-prop@2.0.0: {} @@ -9136,17 +9261,22 @@ snapshots: dequal@2.0.3: {} + detect-europe-js@0.1.2: {} + + detect-libc@1.0.3: + optional: true + devlop@1.1.0: dependencies: dequal: 2.0.3 devtools-protocol@0.0.981744: {} - dexie-export-import@4.1.3(dexie@4.0.9): + dexie-export-import@4.1.4(dexie@4.0.10): dependencies: - dexie: 4.0.9 + dexie: 4.0.10 - dexie@4.0.9: {} + dexie@4.0.10: {} dezalgo@1.0.4: dependencies: @@ -9196,7 +9326,7 @@ snapshots: dot-prop@9.0.0: dependencies: - type-fest: 4.26.1 + type-fest: 4.29.0 duplexer2@0.1.4: dependencies: @@ -9215,7 +9345,7 @@ snapshots: dependencies: jake: 10.9.2 - electron-to-chromium@1.5.59: {} + electron-to-chromium@1.5.67: {} elementtree@0.1.7: dependencies: @@ -9237,6 +9367,11 @@ snapshots: env-paths@3.0.0: {} + errno@0.1.8: + dependencies: + prr: 1.0.1 + optional: true + error-ex@1.3.2: dependencies: is-arrayish: 0.2.1 @@ -9254,12 +9389,12 @@ snapshots: es-errors: 1.3.0 es-object-atoms: 1.0.0 es-set-tostringtag: 2.0.3 - es-to-primitive: 1.2.1 + es-to-primitive: 1.3.0 function.prototype.name: 1.1.6 get-intrinsic: 1.2.4 get-symbol-description: 1.0.2 globalthis: 1.0.4 - gopd: 1.0.1 + gopd: 1.1.0 has-property-descriptors: 1.0.2 has-proto: 1.0.3 has-symbols: 1.0.3 @@ -9269,7 +9404,7 @@ snapshots: is-callable: 1.2.7 is-data-view: 1.0.1 is-negative-zero: 2.0.3 - is-regex: 1.1.4 + is-regex: 1.2.0 is-shared-array-buffer: 1.0.3 is-string: 1.0.7 is-typed-array: 1.1.13 @@ -9285,10 +9420,10 @@ snapshots: string.prototype.trimstart: 1.0.8 typed-array-buffer: 1.0.2 typed-array-byte-length: 1.0.1 - typed-array-byte-offset: 1.0.2 - typed-array-length: 1.0.6 + typed-array-byte-offset: 1.0.3 + typed-array-length: 1.0.7 unbox-primitive: 1.0.2 - which-typed-array: 1.1.15 + which-typed-array: 1.1.16 es-define-property@1.0.0: dependencies: @@ -9306,7 +9441,7 @@ snapshots: function-bind: 1.1.2 get-intrinsic: 1.2.4 globalthis: 1.0.4 - gopd: 1.0.1 + gopd: 1.1.0 has-property-descriptors: 1.0.2 has-proto: 1.0.3 has-symbols: 1.0.3 @@ -9330,39 +9465,40 @@ snapshots: dependencies: hasown: 2.0.2 - es-to-primitive@1.2.1: + es-to-primitive@1.3.0: dependencies: is-callable: 1.2.7 is-date-object: 1.0.5 is-symbol: 1.0.4 - es-toolkit@1.27.0: {} + es-toolkit@1.28.0: {} - esbuild@0.21.5: + esbuild@0.24.0: optionalDependencies: - '@esbuild/aix-ppc64': 0.21.5 - '@esbuild/android-arm': 0.21.5 - '@esbuild/android-arm64': 0.21.5 - '@esbuild/android-x64': 0.21.5 - '@esbuild/darwin-arm64': 0.21.5 - '@esbuild/darwin-x64': 0.21.5 - '@esbuild/freebsd-arm64': 0.21.5 - '@esbuild/freebsd-x64': 0.21.5 - '@esbuild/linux-arm': 0.21.5 - '@esbuild/linux-arm64': 0.21.5 - '@esbuild/linux-ia32': 0.21.5 - '@esbuild/linux-loong64': 0.21.5 - '@esbuild/linux-mips64el': 0.21.5 - '@esbuild/linux-ppc64': 0.21.5 - '@esbuild/linux-riscv64': 0.21.5 - '@esbuild/linux-s390x': 0.21.5 - '@esbuild/linux-x64': 0.21.5 - '@esbuild/netbsd-x64': 0.21.5 - '@esbuild/openbsd-x64': 0.21.5 - '@esbuild/sunos-x64': 0.21.5 - '@esbuild/win32-arm64': 0.21.5 - '@esbuild/win32-ia32': 0.21.5 - '@esbuild/win32-x64': 0.21.5 + '@esbuild/aix-ppc64': 0.24.0 + '@esbuild/android-arm': 0.24.0 + '@esbuild/android-arm64': 0.24.0 + '@esbuild/android-x64': 0.24.0 + '@esbuild/darwin-arm64': 0.24.0 + '@esbuild/darwin-x64': 0.24.0 + '@esbuild/freebsd-arm64': 0.24.0 + '@esbuild/freebsd-x64': 0.24.0 + '@esbuild/linux-arm': 0.24.0 + '@esbuild/linux-arm64': 0.24.0 + '@esbuild/linux-ia32': 0.24.0 + '@esbuild/linux-loong64': 0.24.0 + '@esbuild/linux-mips64el': 0.24.0 + '@esbuild/linux-ppc64': 0.24.0 + '@esbuild/linux-riscv64': 0.24.0 + '@esbuild/linux-s390x': 0.24.0 + '@esbuild/linux-x64': 0.24.0 + '@esbuild/netbsd-x64': 0.24.0 + '@esbuild/openbsd-arm64': 0.24.0 + '@esbuild/openbsd-x64': 0.24.0 + '@esbuild/sunos-x64': 0.24.0 + '@esbuild/win32-arm64': 0.24.0 + '@esbuild/win32-ia32': 0.24.0 + '@esbuild/win32-x64': 0.24.0 escalade@3.2.0: {} @@ -9382,38 +9518,37 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-config-prettier@9.1.0(eslint@9.14.0): + eslint-config-prettier@9.1.0(eslint@9.16.0): dependencies: - eslint: 9.14.0 + eslint: 9.16.0 - eslint-plugin-perfectionist@3.9.1(eslint@9.14.0)(typescript@5.6.3): + eslint-plugin-perfectionist@4.1.2(eslint@9.16.0)(typescript@5.7.2): dependencies: - '@typescript-eslint/types': 8.14.0 - '@typescript-eslint/utils': 8.14.0(eslint@9.14.0)(typescript@5.6.3) - eslint: 9.14.0 - minimatch: 9.0.5 - natural-compare-lite: 1.4.0 + '@typescript-eslint/types': 8.16.0 + '@typescript-eslint/utils': 8.16.0(eslint@9.16.0)(typescript@5.7.2) + eslint: 9.16.0 + natural-orderby: 5.0.0 transitivePeerDependencies: - supports-color - typescript - eslint-plugin-react-compiler@0.0.0-experimental-19c7e06-20241113(eslint@9.14.0): + eslint-plugin-react-compiler@0.0.0-experimental-df7b47d-20241124(eslint@9.16.0): dependencies: '@babel/core': 7.26.0 '@babel/parser': 7.26.2 - '@babel/plugin-proposal-private-methods': 7.18.6(@babel/core@7.26.0) - eslint: 9.14.0 - hermes-parser: 0.20.1 + '@babel/plugin-transform-private-methods': 7.25.9(@babel/core@7.26.0) + eslint: 9.16.0 + hermes-parser: 0.25.1 zod: 3.23.8 zod-validation-error: 3.4.0(zod@3.23.8) transitivePeerDependencies: - supports-color - eslint-plugin-react-hooks@0.0.0-experimental-b01722d5-20241114(eslint@9.14.0): + eslint-plugin-react-hooks@0.0.0-experimental-7670501b-20241124(eslint@9.16.0): dependencies: - eslint: 9.14.0 + eslint: 9.16.0 - eslint-plugin-react@7.37.2(eslint@9.14.0): + eslint-plugin-react@7.37.2(eslint@9.16.0): dependencies: array-includes: 3.1.8 array.prototype.findlast: 1.2.5 @@ -9421,7 +9556,7 @@ snapshots: array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 es-iterator-helpers: 1.2.0 - eslint: 9.14.0 + eslint: 9.16.0 estraverse: 5.3.0 hasown: 2.0.2 jsx-ast-utils: 3.3.5 @@ -9435,12 +9570,12 @@ snapshots: string.prototype.matchall: 4.0.11 string.prototype.repeat: 1.0.0 - eslint-plugin-vitest@0.5.4(eslint@9.14.0)(typescript@5.6.3)(vitest@2.1.5(@types/node@22.9.0)(happy-dom@15.11.6)(jsdom@25.0.1)(terser@5.36.0)): + eslint-plugin-vitest@0.5.4(eslint@9.16.0)(typescript@5.7.2)(vitest@2.1.6(@types/node@22.10.1)(happy-dom@15.11.6)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.28.1)(sass@1.81.0)(stylus@0.62.0)(terser@5.36.0)): dependencies: - '@typescript-eslint/utils': 7.18.0(eslint@9.14.0)(typescript@5.6.3) - eslint: 9.14.0 + '@typescript-eslint/utils': 7.18.0(eslint@9.16.0)(typescript@5.7.2) + eslint: 9.16.0 optionalDependencies: - vitest: 2.1.5(@types/node@22.9.0)(happy-dom@15.11.6)(jsdom@25.0.1)(terser@5.36.0) + vitest: 2.1.6(@types/node@22.10.1)(happy-dom@15.11.6)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.28.1)(sass@1.81.0)(stylus@0.62.0)(terser@5.36.0) transitivePeerDependencies: - supports-color - typescript @@ -9454,14 +9589,14 @@ snapshots: eslint-visitor-keys@4.2.0: {} - eslint@9.14.0: + eslint@9.16.0: dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@9.14.0) + '@eslint-community/eslint-utils': 4.4.1(eslint@9.16.0) '@eslint-community/regexpp': 4.12.1 - '@eslint/config-array': 0.18.0 - '@eslint/core': 0.7.0 - '@eslint/eslintrc': 3.1.0 - '@eslint/js': 9.14.0 + '@eslint/config-array': 0.19.0 + '@eslint/core': 0.9.0 + '@eslint/eslintrc': 3.2.0 + '@eslint/js': 9.16.0 '@eslint/plugin-kit': 0.2.3 '@humanfs/node': 0.16.6 '@humanwhocodes/module-importer': 1.0.1 @@ -9470,7 +9605,7 @@ snapshots: '@types/json-schema': 7.0.15 ajv: 6.12.6 chalk: 4.1.2 - cross-spawn: 7.0.5 + cross-spawn: 7.0.6 debug: 4.3.7 escape-string-regexp: 4.0.0 eslint-scope: 8.2.0 @@ -9490,7 +9625,6 @@ snapshots: minimatch: 3.1.2 natural-compare: 1.4.0 optionator: 0.9.4 - text-table: 0.2.0 transitivePeerDependencies: - supports-color @@ -9526,7 +9660,7 @@ snapshots: execa@4.1.0: dependencies: - cross-spawn: 7.0.5 + cross-spawn: 7.0.6 get-stream: 5.2.0 human-signals: 1.1.1 is-stream: 2.0.1 @@ -9538,7 +9672,7 @@ snapshots: execa@5.1.1: dependencies: - cross-spawn: 7.0.5 + cross-spawn: 7.0.6 get-stream: 6.0.1 human-signals: 2.1.0 is-stream: 2.0.1 @@ -9550,7 +9684,7 @@ snapshots: execa@8.0.0: dependencies: - cross-spawn: 7.0.5 + cross-spawn: 7.0.6 get-stream: 8.0.1 human-signals: 5.0.0 is-stream: 3.0.0 @@ -9658,10 +9792,10 @@ snapshots: flat-cache@4.0.1: dependencies: - flatted: 3.3.1 + flatted: 3.3.2 keyv: 4.5.4 - flatted@3.3.1: {} + flatted@3.3.2: {} for-each@0.3.3: dependencies: @@ -9669,7 +9803,7 @@ snapshots: foreground-child@3.3.0: dependencies: - cross-spawn: 7.0.5 + cross-spawn: 7.0.6 signal-exit: 4.1.0 form-data@4.0.1: @@ -9685,7 +9819,7 @@ snapshots: dezalgo: 1.0.4 hexoid: 1.0.0 once: 1.4.0 - qs: 6.13.0 + qs: 6.13.1 formidable@3.5.2: dependencies: @@ -9693,6 +9827,8 @@ snapshots: hexoid: 2.0.0 once: 1.4.0 + fraction.js@4.3.7: {} + fs-constants@1.0.0: {} fs-extra@11.2.0: @@ -9852,7 +9988,7 @@ snapshots: globalthis@1.0.4: dependencies: define-properties: 1.2.1 - gopd: 1.0.1 + gopd: 1.1.0 globby@11.1.0: dependencies: @@ -9872,9 +10008,7 @@ snapshots: slash: 5.1.0 unicorn-magic: 0.1.0 - globrex@0.1.2: {} - - gopd@1.0.1: + gopd@1.1.0: dependencies: get-intrinsic: 1.2.4 @@ -9902,6 +10036,7 @@ snapshots: entities: 4.5.0 webidl-conversions: 7.0.0 whatwg-mimetype: 3.0.0 + optional: true hard-rejection@2.1.0: {} @@ -9936,17 +10071,17 @@ snapshots: dependencies: '@types/hast': 3.0.4 devlop: 1.1.0 - hast-util-from-parse5: 8.0.1 + hast-util-from-parse5: 8.0.2 parse5: 7.2.1 vfile: 6.0.3 vfile-message: 4.0.2 - hast-util-from-parse5@8.0.1: + hast-util-from-parse5@8.0.2: dependencies: '@types/hast': 3.0.4 '@types/unist': 3.0.3 devlop: 1.1.0 - hastscript: 8.0.0 + hastscript: 9.0.0 property-information: 6.5.0 vfile: 6.0.3 vfile-location: 5.0.3 @@ -10023,7 +10158,7 @@ snapshots: transitivePeerDependencies: - supports-color - hast-util-to-mdast@10.1.0: + hast-util-to-mdast@10.1.1: dependencies: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 @@ -10058,7 +10193,7 @@ snapshots: dependencies: '@types/hast': 3.0.4 - hastscript@8.0.0: + hastscript@9.0.0: dependencies: '@types/hast': 3.0.4 comma-separated-tokens: 2.0.3 @@ -10066,11 +10201,11 @@ snapshots: property-information: 6.5.0 space-separated-tokens: 2.0.2 - hermes-estree@0.20.1: {} + hermes-estree@0.25.1: {} - hermes-parser@0.20.1: + hermes-parser@0.25.1: dependencies: - hermes-estree: 0.20.1 + hermes-estree: 0.25.1 hexoid@1.0.0: {} @@ -10097,8 +10232,6 @@ snapshots: dependencies: lru-cache: 6.0.0 - html-element-attributes@1.3.1: {} - html-encoding-sniffer@4.0.0: dependencies: whatwg-encoding: 3.1.1 @@ -10149,14 +10282,26 @@ snapshots: dependencies: safer-buffer: 2.1.2 + icss-replace-symbols@1.1.0: {} + + icss-utils@5.1.0(postcss@8.4.49): + dependencies: + postcss: 8.4.49 + idb@7.1.1: {} ieee754@1.2.1: {} ignore@5.3.2: {} + image-size@0.5.5: + optional: true + immer@10.1.1: {} + immutable@5.0.3: + optional: true + import-fresh@3.3.0: dependencies: parent-module: 1.0.1 @@ -10224,7 +10369,7 @@ snapshots: ionicons@7.4.0: dependencies: - '@stencil/core': 4.22.2 + '@stencil/core': 4.22.3 ip-address@9.0.5: dependencies: @@ -10253,6 +10398,10 @@ snapshots: dependencies: has-bigints: 1.0.2 + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + is-boolean-object@1.1.2: dependencies: call-bind: 1.0.7 @@ -10284,13 +10433,9 @@ snapshots: is-extendable@0.1.1: {} - is-extendable@1.0.1: - dependencies: - is-plain-object: 2.0.4 - is-extglob@2.1.1: {} - is-finalizationregistry@1.0.2: + is-finalizationregistry@1.1.0: dependencies: call-bind: 1.0.7 @@ -10349,16 +10494,14 @@ snapshots: is-plain-obj@4.1.0: {} - is-plain-object@2.0.4: - dependencies: - isobject: 3.0.1 - is-potential-custom-element-name@1.0.1: {} - is-regex@1.1.4: + is-regex@1.2.0: dependencies: call-bind: 1.0.7 + gopd: 1.1.0 has-tostringtag: 1.0.2 + hasown: 2.0.2 is-regexp@1.0.0: {} @@ -10372,6 +10515,8 @@ snapshots: dependencies: protocols: 2.0.1 + is-standalone-pwa@0.1.1: {} + is-stream@2.0.1: {} is-stream@3.0.0: {} @@ -10388,9 +10533,11 @@ snapshots: dependencies: text-extensions: 1.9.0 + is-there@4.5.1: {} + is-typed-array@1.1.13: dependencies: - which-typed-array: 1.1.15 + which-typed-array: 1.1.16 is-typedarray@1.0.0: {} @@ -10411,6 +10558,9 @@ snapshots: call-bind: 1.0.7 get-intrinsic: 1.2.4 + is-what@3.14.1: + optional: true + is-whitespace@0.3.0: {} is-wsl@2.2.0: @@ -10429,8 +10579,6 @@ snapshots: isexe@2.0.0: {} - isobject@3.0.1: {} - issue-parser@7.0.1: dependencies: lodash.capitalize: 4.2.1 @@ -10444,7 +10592,7 @@ snapshots: define-properties: 1.2.1 get-intrinsic: 1.2.4 has-symbols: 1.0.3 - reflect.getprototypeof: 1.0.6 + reflect.getprototypeof: 1.0.7 set-function-name: 2.0.2 jackspeak@3.4.3: @@ -10504,7 +10652,7 @@ snapshots: http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.5 is-potential-custom-element-name: 1.0.1 - nwsapi: 2.2.13 + nwsapi: 2.2.16 parse5: 7.2.1 rrweb-cssom: 0.7.1 saxes: 6.0.0 @@ -10589,6 +10737,21 @@ snapshots: lemmy-js-client@0.20.0-alpha.18: {} + less@4.2.0: + dependencies: + copy-anything: 2.0.6 + parse-node-version: 1.0.1 + tslib: 2.8.1 + optionalDependencies: + errno: 0.1.8 + graceful-fs: 4.2.11 + image-size: 0.5.5 + make-dir: 2.1.0 + mime: 1.6.0 + needle: 3.3.1 + source-map: 0.6.1 + optional: true + leven@3.1.0: {} levn@0.4.1: @@ -10603,6 +10766,52 @@ snapshots: transitivePeerDependencies: - supports-color + lightningcss-darwin-arm64@1.28.1: + optional: true + + lightningcss-darwin-x64@1.28.1: + optional: true + + lightningcss-freebsd-x64@1.28.1: + optional: true + + lightningcss-linux-arm-gnueabihf@1.28.1: + optional: true + + lightningcss-linux-arm64-gnu@1.28.1: + optional: true + + lightningcss-linux-arm64-musl@1.28.1: + optional: true + + lightningcss-linux-x64-gnu@1.28.1: + optional: true + + lightningcss-linux-x64-musl@1.28.1: + optional: true + + lightningcss-win32-arm64-msvc@1.28.1: + optional: true + + lightningcss-win32-x64-msvc@1.28.1: + optional: true + + lightningcss@1.28.1: + dependencies: + detect-libc: 1.0.3 + optionalDependencies: + lightningcss-darwin-arm64: 1.28.1 + lightningcss-darwin-x64: 1.28.1 + lightningcss-freebsd-x64: 1.28.1 + lightningcss-linux-arm-gnueabihf: 1.28.1 + lightningcss-linux-arm64-gnu: 1.28.1 + lightningcss-linux-arm64-musl: 1.28.1 + lightningcss-linux-x64-gnu: 1.28.1 + lightningcss-linux-x64-musl: 1.28.1 + lightningcss-win32-arm64-msvc: 1.28.1 + lightningcss-win32-x64-msvc: 1.28.1 + optional: true + lines-and-columns@1.2.4: {} load-json-file@4.0.0: @@ -10734,10 +10943,16 @@ snapshots: dependencies: sourcemap-codec: 1.4.8 - magic-string@0.30.12: + magic-string@0.30.14: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 + make-dir@2.1.0: + dependencies: + pify: 4.0.1 + semver: 5.7.2 + optional: true + make-error@1.3.6: {} map-obj@1.0.1: {} @@ -10945,7 +11160,7 @@ snapshots: micromark-util-html-tag-name: 2.0.1 micromark-util-normalize-identifier: 2.0.1 micromark-util-resolve-all: 2.0.1 - micromark-util-subtokenize: 2.0.2 + micromark-util-subtokenize: 2.0.3 micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.1 @@ -11057,7 +11272,7 @@ snapshots: micromark-util-encode: 2.0.1 micromark-util-symbol: 2.0.1 - micromark-util-subtokenize@2.0.2: + micromark-util-subtokenize@2.0.3: dependencies: devlop: 1.1.0 micromark-util-chunked: 2.0.1 @@ -11084,7 +11299,7 @@ snapshots: micromark-util-normalize-identifier: 2.0.1 micromark-util-resolve-all: 2.0.1 micromark-util-sanitize-uri: 2.0.1 - micromark-util-subtokenize: 2.0.2 + micromark-util-subtokenize: 2.0.3 micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.1 transitivePeerDependencies: @@ -11101,6 +11316,9 @@ snapshots: dependencies: mime-db: 1.52.0 + mime@1.6.0: + optional: true + mime@2.6.0: {} mimic-fn@2.1.0: {} @@ -11162,6 +11380,8 @@ snapshots: mkdirp@1.0.4: {} + mkdirp@3.0.1: {} + modern-screenshot@4.5.4: {} modify-values@1.0.1: {} @@ -11176,7 +11396,7 @@ snapshots: mute-stream@1.0.0: {} - nanoid@3.3.7: {} + nanoid@3.3.8: {} native-run@2.0.1: dependencies: @@ -11194,10 +11414,16 @@ snapshots: transitivePeerDependencies: - supports-color - natural-compare-lite@1.4.0: {} - natural-compare@1.4.0: {} + natural-orderby@5.0.0: {} + + needle@3.3.1: + dependencies: + iconv-lite: 0.6.3 + sax: 1.4.1 + optional: true + neo-async@2.6.2: {} netmask@2.0.2: {} @@ -11211,6 +11437,9 @@ snapshots: lower-case: 2.0.2 tslib: 2.8.1 + node-addon-api@7.1.1: + optional: true + node-fetch@2.6.7: dependencies: whatwg-url: 5.0.0 @@ -11235,6 +11464,10 @@ snapshots: semver: 7.6.3 validate-npm-package-license: 3.0.4 + normalize-path@3.0.0: {} + + normalize-range@0.1.2: {} + npm-run-path@4.0.1: dependencies: path-key: 3.1.1 @@ -11247,7 +11480,7 @@ snapshots: dependencies: boolbase: 1.0.0 - nwsapi@2.2.13: {} + nwsapi@2.2.16: {} object-assign@4.1.1: {} @@ -11275,10 +11508,6 @@ snapshots: es-abstract: 1.23.5 es-object-atoms: 1.0.0 - object.omit@3.0.0: - dependencies: - is-extendable: 1.0.1 - object.values@1.2.0: dependencies: call-bind: 1.0.7 @@ -11419,7 +11648,7 @@ snapshots: package-json@10.0.1: dependencies: ky: 1.7.2 - registry-auth-token: 5.0.2 + registry-auth-token: 5.0.3 registry-url: 6.0.1 semver: 7.6.3 @@ -11450,6 +11679,9 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 + parse-node-version@1.0.1: + optional: true + parse-path@7.0.0: dependencies: protocols: 2.0.1 @@ -11514,15 +11746,18 @@ snapshots: pify@3.0.0: {} + pify@4.0.1: + optional: true + pkg-dir@4.2.0: dependencies: find-up: 4.1.0 - playwright-core@1.48.2: {} + playwright-core@1.49.0: {} - playwright@1.48.2: + playwright@1.49.0: dependencies: - playwright-core: 1.48.2 + playwright-core: 1.49.0 optionalDependencies: fsevents: 2.3.2 @@ -11534,9 +11769,37 @@ snapshots: possible-typed-array-names@1.0.0: {} + postcss-modules-extract-imports@3.1.0(postcss@8.4.49): + dependencies: + postcss: 8.4.49 + + postcss-modules-local-by-default@4.1.0(postcss@8.4.49): + dependencies: + icss-utils: 5.1.0(postcss@8.4.49) + postcss: 8.4.49 + postcss-selector-parser: 7.0.0 + postcss-value-parser: 4.2.0 + + postcss-modules-scope@3.2.1(postcss@8.4.49): + dependencies: + postcss: 8.4.49 + postcss-selector-parser: 7.0.0 + + postcss-modules-values@4.0.0(postcss@8.4.49): + dependencies: + icss-utils: 5.1.0(postcss@8.4.49) + postcss: 8.4.49 + + postcss-selector-parser@7.0.0: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-value-parser@4.2.0: {} + postcss@8.4.49: dependencies: - nanoid: 3.3.7 + nanoid: 3.3.8 picocolors: 1.1.1 source-map-js: 1.2.1 @@ -11544,7 +11807,7 @@ snapshots: prettier@2.8.8: {} - prettier@3.3.3: {} + prettier@3.4.1: {} pretty-bytes@5.6.0: {} @@ -11598,6 +11861,9 @@ snapshots: proxy-from-env@1.1.0: {} + prr@1.0.1: + optional: true + pump@3.0.2: dependencies: end-of-stream: 1.4.4 @@ -11651,7 +11917,7 @@ snapshots: q@1.5.1: {} - qs@6.13.0: + qs@6.13.1: dependencies: side-channel: 1.0.6 @@ -11670,36 +11936,32 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-animate-height@3.2.3(react-dom@0.0.0-experimental-b01722d5-20241114(react@0.0.0-experimental-b01722d5-20241114))(react@0.0.0-experimental-b01722d5-20241114): + react-animate-height@3.2.3(react-dom@0.0.0-experimental-7670501b-20241124(react@0.0.0-experimental-7670501b-20241124))(react@0.0.0-experimental-7670501b-20241124): dependencies: - react: 0.0.0-experimental-b01722d5-20241114 - react-dom: 0.0.0-experimental-b01722d5-20241114(react@0.0.0-experimental-b01722d5-20241114) + react: 0.0.0-experimental-7670501b-20241124 + react-dom: 0.0.0-experimental-7670501b-20241124(react@0.0.0-experimental-7670501b-20241124) - react-dom@0.0.0-experimental-b01722d5-20241114(react@0.0.0-experimental-b01722d5-20241114): + react-dom@0.0.0-experimental-7670501b-20241124(react@0.0.0-experimental-7670501b-20241124): dependencies: - react: 0.0.0-experimental-b01722d5-20241114 - scheduler: 0.0.0-experimental-b01722d5-20241114 + react: 0.0.0-experimental-7670501b-20241124 + scheduler: 0.0.0-experimental-7670501b-20241124 - react-error-boundary@4.1.2(react@0.0.0-experimental-b01722d5-20241114): + react-error-boundary@4.1.2(react@0.0.0-experimental-7670501b-20241124): dependencies: '@babel/runtime': 7.26.0 - react: 0.0.0-experimental-b01722d5-20241114 - - react-html-attributes@1.4.6: - dependencies: - html-element-attributes: 1.3.1 + react: 0.0.0-experimental-7670501b-20241124 - react-intersection-observer@9.13.1(react-dom@0.0.0-experimental-b01722d5-20241114(react@0.0.0-experimental-b01722d5-20241114))(react@0.0.0-experimental-b01722d5-20241114): + react-intersection-observer@9.13.1(react-dom@0.0.0-experimental-7670501b-20241124(react@0.0.0-experimental-7670501b-20241124))(react@0.0.0-experimental-7670501b-20241124): dependencies: - react: 0.0.0-experimental-b01722d5-20241114 + react: 0.0.0-experimental-7670501b-20241124 optionalDependencies: - react-dom: 0.0.0-experimental-b01722d5-20241114(react@0.0.0-experimental-b01722d5-20241114) + react-dom: 0.0.0-experimental-7670501b-20241124(react@0.0.0-experimental-7670501b-20241124) react-is@16.13.1: {} react-is@17.0.2: {} - react-markdown@9.0.1(@types/react@18.3.12)(react@0.0.0-experimental-b01722d5-20241114): + react-markdown@9.0.1(@types/react@18.3.12)(react@0.0.0-experimental-7670501b-20241124): dependencies: '@types/hast': 3.0.4 '@types/react': 18.3.12 @@ -11707,7 +11969,7 @@ snapshots: hast-util-to-jsx-runtime: 2.3.2 html-url-attributes: 3.0.1 mdast-util-to-hast: 13.2.0 - react: 0.0.0-experimental-b01722d5-20241114 + react: 0.0.0-experimental-7670501b-20241124 remark-parse: 11.0.0 remark-rehype: 11.1.1 unified: 11.0.5 @@ -11716,34 +11978,34 @@ snapshots: transitivePeerDependencies: - supports-color - react-redux@9.1.2(@types/react@18.3.12)(react@0.0.0-experimental-b01722d5-20241114)(redux@5.0.1): + react-redux@9.1.2(@types/react@18.3.12)(react@0.0.0-experimental-7670501b-20241124)(redux@5.0.1): dependencies: '@types/use-sync-external-store': 0.0.3 - react: 0.0.0-experimental-b01722d5-20241114 - use-sync-external-store: 1.2.2(react@0.0.0-experimental-b01722d5-20241114) + react: 0.0.0-experimental-7670501b-20241124 + use-sync-external-store: 1.2.2(react@0.0.0-experimental-7670501b-20241124) optionalDependencies: '@types/react': 18.3.12 redux: 5.0.1 react-refresh@0.14.2: {} - react-reverse-portal@2.1.2(react-dom@0.0.0-experimental-b01722d5-20241114(react@0.0.0-experimental-b01722d5-20241114))(react@0.0.0-experimental-b01722d5-20241114): + react-reverse-portal@2.1.2(react-dom@0.0.0-experimental-7670501b-20241124(react@0.0.0-experimental-7670501b-20241124))(react@0.0.0-experimental-7670501b-20241124): dependencies: - react: 0.0.0-experimental-b01722d5-20241114 - react-dom: 0.0.0-experimental-b01722d5-20241114(react@0.0.0-experimental-b01722d5-20241114) + react: 0.0.0-experimental-7670501b-20241124 + react-dom: 0.0.0-experimental-7670501b-20241124(react@0.0.0-experimental-7670501b-20241124) - react-router-dom@5.3.4(react@0.0.0-experimental-b01722d5-20241114): + react-router-dom@5.3.4(react@0.0.0-experimental-7670501b-20241124): dependencies: '@babel/runtime': 7.24.7 history: 4.10.1 loose-envify: 1.4.0 prop-types: 15.8.1 - react: 0.0.0-experimental-b01722d5-20241114 - react-router: 5.3.4(react@0.0.0-experimental-b01722d5-20241114) + react: 0.0.0-experimental-7670501b-20241124 + react-router: 5.3.4(react@0.0.0-experimental-7670501b-20241124) tiny-invariant: 1.3.3 tiny-warning: 1.0.3 - react-router@5.3.4(react@0.0.0-experimental-b01722d5-20241114): + react-router@5.3.4(react@0.0.0-experimental-7670501b-20241124): dependencies: '@babel/runtime': 7.25.7 history: 4.10.1 @@ -11751,26 +12013,26 @@ snapshots: loose-envify: 1.4.0 path-to-regexp: 1.8.0 prop-types: 15.8.1 - react: 0.0.0-experimental-b01722d5-20241114 + react: 0.0.0-experimental-7670501b-20241124 react-is: 16.13.1 tiny-invariant: 1.3.3 tiny-warning: 1.0.3 - react-textarea-autosize@8.5.5(@types/react@18.3.12)(react@0.0.0-experimental-b01722d5-20241114): + react-textarea-autosize@8.5.5(@types/react@18.3.12)(react@0.0.0-experimental-7670501b-20241124): dependencies: '@babel/runtime': 7.26.0 - react: 0.0.0-experimental-b01722d5-20241114 - use-composed-ref: 1.3.0(react@0.0.0-experimental-b01722d5-20241114) - use-latest: 1.2.1(@types/react@18.3.12)(react@0.0.0-experimental-b01722d5-20241114) + react: 0.0.0-experimental-7670501b-20241124 + use-composed-ref: 1.3.0(react@0.0.0-experimental-7670501b-20241124) + use-latest: 1.2.1(@types/react@18.3.12)(react@0.0.0-experimental-7670501b-20241124) transitivePeerDependencies: - '@types/react' - react-transition-state@2.2.0(react-dom@0.0.0-experimental-b01722d5-20241114(react@0.0.0-experimental-b01722d5-20241114))(react@0.0.0-experimental-b01722d5-20241114): + react-transition-state@2.2.0(react-dom@0.0.0-experimental-7670501b-20241124(react@0.0.0-experimental-7670501b-20241124))(react@0.0.0-experimental-7670501b-20241124): dependencies: - react: 0.0.0-experimental-b01722d5-20241114 - react-dom: 0.0.0-experimental-b01722d5-20241114(react@0.0.0-experimental-b01722d5-20241114) + react: 0.0.0-experimental-7670501b-20241124 + react-dom: 0.0.0-experimental-7670501b-20241124(react@0.0.0-experimental-7670501b-20241124) - react@0.0.0-experimental-b01722d5-20241114: {} + react@0.0.0-experimental-7670501b-20241124: {} read-pkg-up@3.0.0: dependencies: @@ -11812,6 +12074,13 @@ snapshots: string_decoder: 1.3.0 util-deprecate: 1.0.2 + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + + readdirp@4.0.2: + optional: true + rechoir@0.6.2: dependencies: resolve: 1.22.8 @@ -11827,15 +12096,15 @@ snapshots: redux@5.0.1: {} - reflect.getprototypeof@1.0.6: + reflect.getprototypeof@1.0.7: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.23.5 es-errors: 1.3.0 get-intrinsic: 1.2.4 - globalthis: 1.0.4 - which-builtin-type: 1.1.4 + gopd: 1.1.0 + which-builtin-type: 1.2.0 regenerate-unicode-properties@10.2.0: dependencies: @@ -11858,16 +12127,16 @@ snapshots: es-errors: 1.3.0 set-function-name: 2.0.2 - regexpu-core@6.1.1: + regexpu-core@6.2.0: dependencies: regenerate: 1.4.2 regenerate-unicode-properties: 10.2.0 regjsgen: 0.8.0 - regjsparser: 0.11.2 + regjsparser: 0.12.0 unicode-match-property-ecmascript: 2.0.0 unicode-match-property-value-ecmascript: 2.2.0 - registry-auth-token@5.0.2: + registry-auth-token@5.0.3: dependencies: '@pnpm/npm-conf': 2.3.1 @@ -11877,7 +12146,7 @@ snapshots: regjsgen@0.8.0: {} - regjsparser@0.11.2: + regjsparser@0.12.0: dependencies: jsesc: 3.0.2 @@ -11904,18 +12173,18 @@ snapshots: dependencies: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 - hast-util-to-mdast: 10.1.0 + hast-util-to-mdast: 10.1.1 unified: 11.0.5 vfile: 6.0.3 - release-it@17.10.0(typescript@5.6.3): + release-it@17.10.0(typescript@5.7.2): dependencies: '@iarna/toml': 2.2.5 '@octokit/rest': 20.1.1 async-retry: 1.3.3 chalk: 5.3.0 ci-info: 4.1.0 - cosmiconfig: 9.0.0(typescript@5.6.3) + cosmiconfig: 9.0.0(typescript@5.7.2) execa: 8.0.0 git-url-parse: 14.0.0 globby: 14.0.2 @@ -12027,28 +12296,28 @@ snapshots: optionalDependencies: fsevents: 2.3.3 - rollup@4.26.0: + rollup@4.28.0: dependencies: '@types/estree': 1.0.6 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.26.0 - '@rollup/rollup-android-arm64': 4.26.0 - '@rollup/rollup-darwin-arm64': 4.26.0 - '@rollup/rollup-darwin-x64': 4.26.0 - '@rollup/rollup-freebsd-arm64': 4.26.0 - '@rollup/rollup-freebsd-x64': 4.26.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.26.0 - '@rollup/rollup-linux-arm-musleabihf': 4.26.0 - '@rollup/rollup-linux-arm64-gnu': 4.26.0 - '@rollup/rollup-linux-arm64-musl': 4.26.0 - '@rollup/rollup-linux-powerpc64le-gnu': 4.26.0 - '@rollup/rollup-linux-riscv64-gnu': 4.26.0 - '@rollup/rollup-linux-s390x-gnu': 4.26.0 - '@rollup/rollup-linux-x64-gnu': 4.26.0 - '@rollup/rollup-linux-x64-musl': 4.26.0 - '@rollup/rollup-win32-arm64-msvc': 4.26.0 - '@rollup/rollup-win32-ia32-msvc': 4.26.0 - '@rollup/rollup-win32-x64-msvc': 4.26.0 + '@rollup/rollup-android-arm-eabi': 4.28.0 + '@rollup/rollup-android-arm64': 4.28.0 + '@rollup/rollup-darwin-arm64': 4.28.0 + '@rollup/rollup-darwin-x64': 4.28.0 + '@rollup/rollup-freebsd-arm64': 4.28.0 + '@rollup/rollup-freebsd-x64': 4.28.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.28.0 + '@rollup/rollup-linux-arm-musleabihf': 4.28.0 + '@rollup/rollup-linux-arm64-gnu': 4.28.0 + '@rollup/rollup-linux-arm64-musl': 4.28.0 + '@rollup/rollup-linux-powerpc64le-gnu': 4.28.0 + '@rollup/rollup-linux-riscv64-gnu': 4.28.0 + '@rollup/rollup-linux-s390x-gnu': 4.28.0 + '@rollup/rollup-linux-x64-gnu': 4.28.0 + '@rollup/rollup-linux-x64-musl': 4.28.0 + '@rollup/rollup-win32-arm64-msvc': 4.28.0 + '@rollup/rollup-win32-ia32-msvc': 4.28.0 + '@rollup/rollup-win32-x64-msvc': 4.28.0 fsevents: 2.3.3 rrweb-cssom@0.7.1: {} @@ -12088,19 +12357,31 @@ snapshots: dependencies: call-bind: 1.0.7 es-errors: 1.3.0 - is-regex: 1.1.4 + is-regex: 1.2.0 safer-buffer@2.1.2: {} + sass@1.81.0: + dependencies: + chokidar: 4.0.1 + immutable: 5.0.3 + source-map-js: 1.2.1 + optionalDependencies: + '@parcel/watcher': 2.5.0 + optional: true + sax@1.1.4: {} + sax@1.3.0: + optional: true + sax@1.4.1: {} saxes@6.0.0: dependencies: xmlchars: 2.2.0 - scheduler@0.0.0-experimental-b01722d5-20241114: {} + scheduler@0.0.0-experimental-7670501b-20241124: {} semver@5.7.2: {} @@ -12120,7 +12401,7 @@ snapshots: es-errors: 1.3.0 function-bind: 1.1.2 get-intrinsic: 1.2.4 - gopd: 1.0.1 + gopd: 1.1.0 has-property-descriptors: 1.0.2 set-function-name@2.0.2: @@ -12204,7 +12485,8 @@ snapshots: source-map@0.6.1: {} - source-map@0.7.4: {} + source-map@0.7.4: + optional: true source-map@0.8.0-beta.0: dependencies: @@ -12281,7 +12563,7 @@ snapshots: es-errors: 1.3.0 es-object-atoms: 1.0.0 get-intrinsic: 1.2.4 - gopd: 1.0.1 + gopd: 1.1.0 has-symbols: 1.0.3 internal-slot: 1.0.7 regexp.prototype.flags: 1.5.3 @@ -12361,7 +12643,16 @@ snapshots: dependencies: inline-style-parser: 0.2.4 - stylis@4.3.4: {} + stylus@0.62.0: + dependencies: + '@adobe/css-tools': 4.3.3 + debug: 4.3.7 + glob: 7.2.3 + sax: 1.3.0 + source-map: 0.7.4 + transitivePeerDependencies: + - supports-color + optional: true superagent@8.1.2: dependencies: @@ -12373,7 +12664,7 @@ snapshots: formidable: 2.1.2 methods: 1.1.2 mime: 2.6.0 - qs: 6.13.0 + qs: 6.13.1 semver: 7.6.3 transitivePeerDependencies: - supports-color @@ -12444,8 +12735,6 @@ snapshots: text-extensions@1.9.0: {} - text-table@0.2.0: {} - through2@2.0.5: dependencies: readable-stream: 2.3.8 @@ -12476,11 +12765,11 @@ snapshots: tinyspy@3.0.2: {} - tldts-core@6.1.61: {} + tldts-core@6.1.65: {} - tldts@6.1.61: + tldts@6.1.65: dependencies: - tldts-core: 6.1.61 + tldts-core: 6.1.65 tmp@0.0.33: dependencies: @@ -12494,7 +12783,7 @@ snapshots: tough-cookie@5.0.0: dependencies: - tldts: 6.1.61 + tldts: 6.1.65 tr46@0.0.3: {} @@ -12516,36 +12805,28 @@ snapshots: trough@2.2.0: {} - ts-api-utils@1.4.0(typescript@5.6.3): - dependencies: - typescript: 5.6.3 - - ts-invariant@0.10.3: + ts-api-utils@1.4.3(typescript@5.7.2): dependencies: - tslib: 2.8.1 + typescript: 5.7.2 - ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3): + ts-node@10.9.2(@types/node@22.10.1)(typescript@5.7.2): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 22.9.0 + '@types/node': 22.10.1 acorn: 8.14.0 acorn-walk: 8.3.4 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 5.6.3 + typescript: 5.7.2 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 - tsconfck@3.1.4(typescript@5.6.3): - optionalDependencies: - typescript: 5.6.3 - tslib@1.14.1: {} tslib@2.8.1: {} @@ -12566,7 +12847,7 @@ snapshots: type-fest@2.19.0: {} - type-fest@4.26.1: {} + type-fest@4.29.0: {} typed-array-buffer@1.0.2: dependencies: @@ -12578,46 +12859,69 @@ snapshots: dependencies: call-bind: 1.0.7 for-each: 0.3.3 - gopd: 1.0.1 + gopd: 1.1.0 has-proto: 1.0.3 is-typed-array: 1.1.13 - typed-array-byte-offset@1.0.2: + typed-array-byte-offset@1.0.3: dependencies: available-typed-arrays: 1.0.7 call-bind: 1.0.7 for-each: 0.3.3 - gopd: 1.0.1 + gopd: 1.1.0 has-proto: 1.0.3 is-typed-array: 1.1.13 + reflect.getprototypeof: 1.0.7 - typed-array-length@1.0.6: + typed-array-length@1.0.7: dependencies: call-bind: 1.0.7 for-each: 0.3.3 - gopd: 1.0.1 - has-proto: 1.0.3 + gopd: 1.1.0 is-typed-array: 1.1.13 possible-typed-array-names: 1.0.0 + reflect.getprototypeof: 1.0.7 + + typed-css-modules@0.9.1: + dependencies: + camelcase: 6.3.0 + chalk: 4.1.2 + chokidar: 3.6.0 + glob: 10.4.5 + icss-replace-symbols: 1.1.0 + is-there: 4.5.1 + mkdirp: 3.0.1 + postcss: 8.4.49 + postcss-modules-extract-imports: 3.1.0(postcss@8.4.49) + postcss-modules-local-by-default: 4.1.0(postcss@8.4.49) + postcss-modules-scope: 3.2.1(postcss@8.4.49) + postcss-modules-values: 4.0.0(postcss@8.4.49) + yargs: 17.7.2 typedarray-to-buffer@3.1.5: dependencies: is-typedarray: 1.0.0 - typescript-eslint@8.14.0(eslint@9.14.0)(typescript@5.6.3): + typescript-eslint@8.16.0(eslint@9.16.0)(typescript@5.7.2): dependencies: - '@typescript-eslint/eslint-plugin': 8.14.0(@typescript-eslint/parser@8.14.0(eslint@9.14.0)(typescript@5.6.3))(eslint@9.14.0)(typescript@5.6.3) - '@typescript-eslint/parser': 8.14.0(eslint@9.14.0)(typescript@5.6.3) - '@typescript-eslint/utils': 8.14.0(eslint@9.14.0)(typescript@5.6.3) + '@typescript-eslint/eslint-plugin': 8.16.0(@typescript-eslint/parser@8.16.0(eslint@9.16.0)(typescript@5.7.2))(eslint@9.16.0)(typescript@5.7.2) + '@typescript-eslint/parser': 8.16.0(eslint@9.16.0)(typescript@5.7.2) + '@typescript-eslint/utils': 8.16.0(eslint@9.16.0)(typescript@5.7.2) + eslint: 9.16.0 optionalDependencies: - typescript: 5.6.3 + typescript: 5.7.2 transitivePeerDependencies: - - eslint - supports-color - typescript@5.6.3: {} + typescript@5.7.2: {} - ua-parser-js@1.0.39: {} + ua-is-frozen@0.1.2: {} + + ua-parser-js@2.0.0: + dependencies: + detect-europe-js: 0.1.2 + is-standalone-pwa: 0.1.1 + ua-is-frozen: 0.1.2 uglify-js@3.19.3: optional: true @@ -12634,7 +12938,7 @@ snapshots: buffer: 5.7.1 through: 2.3.8 - undici-types@6.19.8: {} + undici-types@6.20.0: {} unicode-canonical-property-names-ecmascript@2.0.1: {} @@ -12758,30 +13062,30 @@ snapshots: url-join@5.0.0: {} - use-composed-ref@1.3.0(react@0.0.0-experimental-b01722d5-20241114): + use-composed-ref@1.3.0(react@0.0.0-experimental-7670501b-20241124): dependencies: - react: 0.0.0-experimental-b01722d5-20241114 + react: 0.0.0-experimental-7670501b-20241124 - use-isomorphic-layout-effect@1.1.2(@types/react@18.3.12)(react@0.0.0-experimental-b01722d5-20241114): + use-isomorphic-layout-effect@1.1.2(@types/react@18.3.12)(react@0.0.0-experimental-7670501b-20241124): dependencies: - react: 0.0.0-experimental-b01722d5-20241114 + react: 0.0.0-experimental-7670501b-20241124 optionalDependencies: '@types/react': 18.3.12 - use-latest@1.2.1(@types/react@18.3.12)(react@0.0.0-experimental-b01722d5-20241114): + use-latest@1.2.1(@types/react@18.3.12)(react@0.0.0-experimental-7670501b-20241124): dependencies: - react: 0.0.0-experimental-b01722d5-20241114 - use-isomorphic-layout-effect: 1.1.2(@types/react@18.3.12)(react@0.0.0-experimental-b01722d5-20241114) + react: 0.0.0-experimental-7670501b-20241124 + use-isomorphic-layout-effect: 1.1.2(@types/react@18.3.12)(react@0.0.0-experimental-7670501b-20241124) optionalDependencies: '@types/react': 18.3.12 - use-long-press@3.2.0(react@0.0.0-experimental-b01722d5-20241114): + use-long-press@3.2.0(react@0.0.0-experimental-7670501b-20241124): dependencies: - react: 0.0.0-experimental-b01722d5-20241114 + react: 0.0.0-experimental-7670501b-20241124 - use-sync-external-store@1.2.2(react@0.0.0-experimental-b01722d5-20241114): + use-sync-external-store@1.2.2(react@0.0.0-experimental-7670501b-20241124): dependencies: - react: 0.0.0-experimental-b01722d5-20241114 + react: 0.0.0-experimental-7670501b-20241124 util-deprecate@1.0.2: {} @@ -12823,20 +13127,21 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.2 - virtua@0.37.0(react-dom@0.0.0-experimental-b01722d5-20241114(react@0.0.0-experimental-b01722d5-20241114))(react@0.0.0-experimental-b01722d5-20241114): + virtua@0.38.1(react-dom@0.0.0-experimental-7670501b-20241124(react@0.0.0-experimental-7670501b-20241124))(react@0.0.0-experimental-7670501b-20241124): optionalDependencies: - react: 0.0.0-experimental-b01722d5-20241114 - react-dom: 0.0.0-experimental-b01722d5-20241114(react@0.0.0-experimental-b01722d5-20241114) + react: 0.0.0-experimental-7670501b-20241124 + react-dom: 0.0.0-experimental-7670501b-20241124(react@0.0.0-experimental-7670501b-20241124) - vite-node@2.1.5(@types/node@22.9.0)(terser@5.36.0): + vite-node@2.1.6(@types/node@22.10.1)(less@4.2.0)(lightningcss@1.28.1)(sass@1.81.0)(stylus@0.62.0)(terser@5.36.0): dependencies: cac: 6.7.14 debug: 4.3.7 es-module-lexer: 1.5.4 pathe: 1.1.2 - vite: 5.4.11(@types/node@22.9.0)(terser@5.36.0) + vite: 6.0.1(@types/node@22.10.1)(less@4.2.0)(lightningcss@1.28.1)(sass@1.81.0)(stylus@0.62.0)(terser@5.36.0) transitivePeerDependencies: - '@types/node' + - jiti - less - lightningcss - sass @@ -12845,77 +13150,73 @@ snapshots: - sugarss - supports-color - terser + - tsx + - yaml - vite-plugin-pwa@0.21.0(vite@5.4.11(@types/node@22.9.0)(terser@5.36.0))(workbox-build@7.1.1(@types/babel__core@7.20.5))(workbox-window@7.3.0): + vite-plugin-pwa@0.21.1(vite@6.0.1(@types/node@22.10.1)(less@4.2.0)(lightningcss@1.28.1)(sass@1.81.0)(stylus@0.62.0)(terser@5.36.0))(workbox-build@7.1.1(@types/babel__core@7.20.5))(workbox-window@7.3.0): dependencies: debug: 4.3.7 pretty-bytes: 6.1.1 tinyglobby: 0.2.10 - vite: 5.4.11(@types/node@22.9.0)(terser@5.36.0) + vite: 6.0.1(@types/node@22.10.1)(less@4.2.0)(lightningcss@1.28.1)(sass@1.81.0)(stylus@0.62.0)(terser@5.36.0) workbox-build: 7.1.1(@types/babel__core@7.20.5) workbox-window: 7.3.0 transitivePeerDependencies: - supports-color - vite-plugin-svgr@4.3.0(rollup@2.79.2)(typescript@5.6.3)(vite@5.4.11(@types/node@22.9.0)(terser@5.36.0)): + vite-plugin-svgr@4.3.0(rollup@2.79.2)(typescript@5.7.2)(vite@6.0.1(@types/node@22.10.1)(less@4.2.0)(lightningcss@1.28.1)(sass@1.81.0)(stylus@0.62.0)(terser@5.36.0)): dependencies: '@rollup/pluginutils': 5.1.3(rollup@2.79.2) - '@svgr/core': 8.1.0(typescript@5.6.3) - '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.6.3)) - vite: 5.4.11(@types/node@22.9.0)(terser@5.36.0) + '@svgr/core': 8.1.0(typescript@5.7.2) + '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.7.2)) + vite: 6.0.1(@types/node@22.10.1)(less@4.2.0)(lightningcss@1.28.1)(sass@1.81.0)(stylus@0.62.0)(terser@5.36.0) transitivePeerDependencies: - rollup - supports-color - typescript - vite-tsconfig-paths@5.1.2(typescript@5.6.3)(vite@5.4.11(@types/node@22.9.0)(terser@5.36.0)): - dependencies: - debug: 4.3.7 - globrex: 0.1.2 - tsconfck: 3.1.4(typescript@5.6.3) - optionalDependencies: - vite: 5.4.11(@types/node@22.9.0)(terser@5.36.0) - transitivePeerDependencies: - - supports-color - - typescript - - vite@5.4.11(@types/node@22.9.0)(terser@5.36.0): + vite@6.0.1(@types/node@22.10.1)(less@4.2.0)(lightningcss@1.28.1)(sass@1.81.0)(stylus@0.62.0)(terser@5.36.0): dependencies: - esbuild: 0.21.5 + esbuild: 0.24.0 postcss: 8.4.49 - rollup: 4.26.0 + rollup: 4.28.0 optionalDependencies: - '@types/node': 22.9.0 + '@types/node': 22.10.1 fsevents: 2.3.3 + less: 4.2.0 + lightningcss: 1.28.1 + sass: 1.81.0 + stylus: 0.62.0 terser: 5.36.0 - vitest@2.1.5(@types/node@22.9.0)(happy-dom@15.11.6)(jsdom@25.0.1)(terser@5.36.0): + vitest@2.1.6(@types/node@22.10.1)(happy-dom@15.11.6)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.28.1)(sass@1.81.0)(stylus@0.62.0)(terser@5.36.0): dependencies: - '@vitest/expect': 2.1.5 - '@vitest/mocker': 2.1.5(vite@5.4.11(@types/node@22.9.0)(terser@5.36.0)) - '@vitest/pretty-format': 2.1.5 - '@vitest/runner': 2.1.5 - '@vitest/snapshot': 2.1.5 - '@vitest/spy': 2.1.5 - '@vitest/utils': 2.1.5 + '@vitest/expect': 2.1.6 + '@vitest/mocker': 2.1.6(vite@6.0.1(@types/node@22.10.1)(less@4.2.0)(lightningcss@1.28.1)(sass@1.81.0)(stylus@0.62.0)(terser@5.36.0)) + '@vitest/pretty-format': 2.1.6 + '@vitest/runner': 2.1.6 + '@vitest/snapshot': 2.1.6 + '@vitest/spy': 2.1.6 + '@vitest/utils': 2.1.6 chai: 5.1.2 debug: 4.3.7 expect-type: 1.1.0 - magic-string: 0.30.12 + magic-string: 0.30.14 pathe: 1.1.2 std-env: 3.8.0 tinybench: 2.9.0 tinyexec: 0.3.1 tinypool: 1.0.2 tinyrainbow: 1.2.0 - vite: 5.4.11(@types/node@22.9.0)(terser@5.36.0) - vite-node: 2.1.5(@types/node@22.9.0)(terser@5.36.0) + vite: 6.0.1(@types/node@22.10.1)(less@4.2.0)(lightningcss@1.28.1)(sass@1.81.0)(stylus@0.62.0)(terser@5.36.0) + vite-node: 2.1.6(@types/node@22.10.1)(less@4.2.0)(lightningcss@1.28.1)(sass@1.81.0)(stylus@0.62.0)(terser@5.36.0) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 22.9.0 + '@types/node': 22.10.1 happy-dom: 15.11.6 jsdom: 25.0.1 transitivePeerDependencies: + - jiti - less - lightningcss - msw @@ -12925,8 +13226,10 @@ snapshots: - sugarss - supports-color - terser + - tsx + - yaml - voyager-ionic-core@8.4.0: + voyager-ionic-core@8.4.1: dependencies: '@stencil/core': 4.20.0 ionicons: 7.4.0 @@ -12952,7 +13255,8 @@ snapshots: dependencies: iconv-lite: 0.6.3 - whatwg-mimetype@3.0.0: {} + whatwg-mimetype@3.0.0: + optional: true whatwg-mimetype@4.0.0: {} @@ -12982,20 +13286,21 @@ snapshots: is-string: 1.0.7 is-symbol: 1.0.4 - which-builtin-type@1.1.4: + which-builtin-type@1.2.0: dependencies: + call-bind: 1.0.7 function.prototype.name: 1.1.6 has-tostringtag: 1.0.2 is-async-function: 2.0.0 is-date-object: 1.0.5 - is-finalizationregistry: 1.0.2 + is-finalizationregistry: 1.1.0 is-generator-function: 1.0.10 - is-regex: 1.1.4 + is-regex: 1.2.0 is-weakref: 1.0.2 isarray: 2.0.5 which-boxed-primitive: 1.0.2 which-collection: 1.0.2 - which-typed-array: 1.1.15 + which-typed-array: 1.1.16 which-collection@1.0.2: dependencies: @@ -13006,12 +13311,12 @@ snapshots: which-module@2.0.1: {} - which-typed-array@1.1.15: + which-typed-array@1.1.16: dependencies: available-typed-arrays: 1.0.7 call-bind: 1.0.7 for-each: 0.3.3 - gopd: 1.0.1 + gopd: 1.1.0 has-tostringtag: 1.0.2 which@2.0.2: diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000000..7738160ab9 --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,5 @@ +export default { + plugins: { + autoprefixer: {}, + }, +}; diff --git a/scripts/prerelease.sh b/scripts/prerelease.sh new file mode 100755 index 0000000000..a1cceb9180 --- /dev/null +++ b/scripts/prerelease.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# Use Node.js to read the version from package.json +version=$(node -p "require('./package.json').version") + +# Check if the git tag exists on the remote (origin) without 'v' prefix +if git ls-remote --tags origin "$version" | grep -q "refs/tags/$version"; then + echo "Tag $version exists on origin (was released), proceeding with bump..." + pnpm exec release-it + echo 'Version successfully bumped, but release not yet cut!' +else + echo "Tag $version does not exist on origin." + echo "This means $version hasn't been released yet." +fi + +./scripts/release.sh \ No newline at end of file diff --git a/scripts/postrelease.sh b/scripts/release.sh similarity index 100% rename from scripts/postrelease.sh rename to scripts/release.sh diff --git a/src/core/App.tsx b/src/core/App.tsx index ab99185090..86af8b39e6 100644 --- a/src/core/App.tsx +++ b/src/core/App.tsx @@ -1,3 +1,41 @@ +// Core CSS required for Ionic components to work properly +import "@ionic/react/css/core.css"; + +// Basic CSS for apps built with Ionic */ +import "@ionic/react/css/normalize.css"; +import "@ionic/react/css/structure.css"; +import "@ionic/react/css/typography.css"; + +// Optional CSS utils that can be commented out +import "@ionic/react/css/display.css"; +import "@ionic/react/css/flex-utils.css"; +import "@ionic/react/css/float-elements.css"; +import "@ionic/react/css/padding.css"; +import "@ionic/react/css/text-alignment.css"; +import "@ionic/react/css/text-transformation.css"; + +// Override Ionic variables +import "./theme/variables.css"; +// Light mode +import "./theme/lightVariables.css"; +// Dark mode +import "./theme/darkVariables.css"; +// Dark mode modifier +import "./theme/darkModifierVariables.css"; + +// Define after ./theme/variables to override it +import "@ionic/react/css/palettes/dark.class.css"; + +// CSS imports +import "./syntaxHighlights.css"; + +// PhotoSwipe (before global overrides) +import "photoswipe/style.css"; + +// Global CSS overrides +import "./globalCssOverrides.css"; + +// Rest of imports after css import { IonApp, setupIonicReact } from "@ionic/react"; import { NavModes } from "capacitor-android-nav-mode"; import { ErrorBoundary } from "react-error-boundary"; @@ -28,28 +66,6 @@ import Listeners from "./listeners"; // Setup global app lifecycle listeners import "./listeners"; -// Core CSS required for Ionic components to work properly -import "@ionic/react/css/core.css"; - -// Basic CSS for apps built with Ionic */ -import "@ionic/react/css/normalize.css"; -import "@ionic/react/css/structure.css"; -import "@ionic/react/css/typography.css"; - -// Optional CSS utils that can be commented out -import "@ionic/react/css/display.css"; -import "@ionic/react/css/flex-utils.css"; -import "@ionic/react/css/float-elements.css"; -import "@ionic/react/css/padding.css"; -import "@ionic/react/css/text-alignment.css"; -import "@ionic/react/css/text-transformation.css"; - -// Allow Ionic palette to override custom styles -import "./theme/variables"; - -// Define after ./theme/variables to override it -import "@ionic/react/css/palettes/dark.class.css"; - // index.tsx ensures android nav mode resolves before app is rendered (async () => { let navMode; diff --git a/src/core/AppCrash.module.css b/src/core/AppCrash.module.css new file mode 100644 index 0000000000..708093b1a2 --- /dev/null +++ b/src/core/AppCrash.module.css @@ -0,0 +1,20 @@ +.container { + display: flex; + flex-direction: column; + align-items: center; + gap: 16px; + text-align: center; + padding: 8px; + + position: absolute; + inset: 0; + + overflow: auto; + + padding-top: max(env(safe-area-inset-top), 8px); + padding-right: max(env(safe-area-inset-right), 8px); + padding-bottom: max(env(safe-area-inset-bottom), 8px); + padding-left: max(env(safe-area-inset-left), 8px); + + color: var(--ion-text-color); +} diff --git a/src/core/AppCrash.tsx b/src/core/AppCrash.tsx index b50905ad85..df442d4cca 100644 --- a/src/core/AppCrash.tsx +++ b/src/core/AppCrash.tsx @@ -1,5 +1,4 @@ import { IonButton, IonIcon, IonLabel } from "@ionic/react"; -import { styled } from "@linaria/react"; import { logoGithub } from "ionicons/icons"; import { FallbackProps } from "react-error-boundary"; @@ -9,30 +8,7 @@ import { unloadServiceWorkerAndRefresh } from "#/helpers/serviceWorker"; import { memoryHistory } from "#/routes/common/Router"; import store from "#/store"; -const Container = styled.div` - display: flex; - flex-direction: column; - align-items: center; - gap: 16px; - text-align: center; - padding: 8px; - - position: absolute; - inset: 0; - - overflow: auto; - - padding-top: max(env(safe-area-inset-top), 8px); - padding-right: max(env(safe-area-inset-right), 8px); - padding-bottom: max(env(safe-area-inset-bottom), 8px); - padding-left: max(env(safe-area-inset-left), 8px); - - color: var(--ion-text-color); -`; - -const Title = styled.h2``; - -const Description = styled.div``; +import styles from "./AppCrash.module.css"; export default function AppCrash({ error }: FallbackProps) { // Don't use useLocation/useAppSelector, because they are not available @@ -90,12 +66,12 @@ Error: \`\`${error}\`\` } return ( - - 🫣 Gah! Voyager crashed! - +
+

🫣 Gah! Voyager crashed!

+
Voyager does not collect any data, so we would appreciate you voluntarily submitting this crash for us to investigate. - +
- +
You can also try reloading the app to see if that solves the issue. {isNative() ? " Check the app store for an update, too." : ""} - +
Reload app
- +
If this crash is affecting many people, you can probably learn more{" "} . - +
- As a last resort, try clearing all app data. +
As a last resort, try clearing all app data.
Clear app data - +
); } diff --git a/src/core/GlobalStyles.module.css b/src/core/GlobalStyles.module.css new file mode 100644 index 0000000000..b322be35b3 --- /dev/null +++ b/src/core/GlobalStyles.module.css @@ -0,0 +1,3 @@ +.fixedDeviceFont { + --ion-dynamic-font: initial; +} diff --git a/src/core/GlobalStyles.tsx b/src/core/GlobalStyles.tsx index 441073d0d5..ef2ced3632 100644 --- a/src/core/GlobalStyles.tsx +++ b/src/core/GlobalStyles.tsx @@ -1,6 +1,5 @@ import { Keyboard, KeyboardStyle } from "@capacitor/keyboard"; import { StatusBar, Style } from "@capacitor/status-bar"; -import { css } from "@linaria/core"; import React, { createContext, useContext, @@ -18,6 +17,8 @@ import { useAppSelector } from "#/store"; import { getThemeByStyle } from "./theme/AppThemes"; +import styles from "./GlobalStyles.module.css"; + export const DARK_CLASSNAME = "ion-palette-dark"; export const PURE_BLACK_CLASSNAME = "theme-pure-black"; export const THEME_HAS_CUSTOM_BACKGROUND = "theme-has-custom-background"; @@ -74,10 +75,6 @@ updateDocumentTheme( initialSettingsState.appearance.theme, ); -const fixedDeviceFontCss = css` - --ion-dynamic-font: initial; -`; - export default function GlobalStyles({ children }: React.PropsWithChildren) { const isDark = useComputeIsDark(); const { fontSizeMultiplier, useSystemFontSize } = useAppSelector( @@ -97,10 +94,10 @@ export default function GlobalStyles({ children }: React.PropsWithChildren) { useLayoutEffect(() => { if (useSystemFontSize) { - document.documentElement.classList.remove(fixedDeviceFontCss); + document.documentElement.classList.remove(styles.fixedDeviceFont!); document.documentElement.style.fontSize = ""; } else { - document.documentElement.classList.add(fixedDeviceFontCss); + document.documentElement.classList.add(styles.fixedDeviceFont!); document.documentElement.style.fontSize = `${fontSizeMultiplier}rem`; } }, [useSystemFontSize, fontSizeMultiplier]); diff --git a/src/core/TabContext.tsx b/src/core/TabContext.tsx index 706f286638..64130b2a32 100644 --- a/src/core/TabContext.tsx +++ b/src/core/TabContext.tsx @@ -1,6 +1,6 @@ import React, { - MutableRefObject, createContext, + MutableRefObject, useEffect, useRef, } from "react"; diff --git a/src/core/globalCssOverrides.css b/src/core/globalCssOverrides.css new file mode 100644 index 0000000000..a592497a54 --- /dev/null +++ b/src/core/globalCssOverrides.css @@ -0,0 +1,322 @@ +:root { + --sat: env(safe-area-inset-top); + --sar: env(safe-area-inset-right); + --sab: env(safe-area-inset-bottom); + --sal: env(safe-area-inset-left); +} + +html { + -webkit-text-size-adjust: 100%; /* Prevent font scaling in landscape while allowing user zoom */ +} + +.ReactCollapse--collapse { + transition: height 200ms; +} + +ion-tab-button { + opacity: 1 !important; +} + +ion-router-outlet > .ion-page > ion-header { + /* Header doesn't support dynamic font size */ + ion-button, + ion-back-button, + ion-title { + font-size: 17px; + } + + /* Ionic's default font size for icons in header is a bit too large */ + ion-button.in-toolbar ion-icon { + font-size: 1.35em !important; + } + + ion-back-button.md::part(text) { + display: none; + } +} + +ion-router-outlet ion-list.list-inset ion-item { + --background: var( + --ion-tab-bar-background, + var(--ion-background-color-step-50, #fff) + ); +} + +.left-align-buttons + .action-sheet-button:not(.action-sheet-cancel) + .action-sheet-button-inner.sc-ion-action-sheet-ios:not( + .action-sheet-group-cancel + ) { + justify-content: flex-start; +} + +.mod .action-sheet-button:not(.action-sheet-destructive), +.mod .action-sheet-button:hover:not(.action-sheet-destructive), +.mod.action-sheet-button:not(.action-sheet-destructive), +.mod.action-sheet-button:hover:not(.action-sheet-destructive) { + --color: var(--ion-color-success-shade); + color: var(--color); +} + +.mod.alert-button { + color: var(--ion-color-success-shade); +} + +.admin-local .action-sheet-button, +.admin-local .action-sheet-button:hover, +.admin-local.action-sheet-button, +.admin-local.action-sheet-button:hover, +.admin-remote .action-sheet-button, +.admin-remote .action-sheet-button:hover, +.admin-remote.action-sheet-button, +.admin-remote.action-sheet-button:hover { + --color: var(--ion-color-danger-shade); + color: var(--color); +} + +.report-reasons .action-sheet-title { + white-space: pre; +} + +/* https://github.com/ionic-team/ionic-framework/issues/27777#issuecomment-1631522283 */ +.action-sheet-height-fix { + --height: 100%; +} + +ion-modal.small { + --height: 50%; + --width: 85%; + --max-width: 400px; + --max-height: 500px; + --border-radius: 16px; + --box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), + 0 4px 6px -4px rgb(0 0 0 / 0.1); +} +ion-modal.small ion-header ion-toolbar:first-of-type { + padding-top: 0px; +} + +ion-modal.transparent-scroll { + --background: none; + --height: auto; + --box-shadow: none; + + &.show-modal { + display: flex; + flex-direction: column; + } +} + +ion-modal.transparent-scroll .ion-page { + overflow: auto; +} + +ion-alert.preserve-newlines { + white-space: pre-line; +} + +.pswp__img { + -webkit-touch-callout: default; +} + +/* gets in the way of non-post preview more actions button */ +.pswp__preloader { + display: none; +} + +.pswp__hide-on-close { + /* Photoswipe `will-change: opacity` breaks alt text backdrop-filter (when opened) */ + will-change: auto !important; +} + +ion-action-sheet .detail::before { + content: ""; + z-index: 1; + position: absolute; + right: 12px; + top: 50%; + transform: translateY(-50%); + + /* Ion chevron right icon */ + background-image: url('data:image/svg+xml,'); + width: 24px; + height: 24px; +} + +ion-action-sheet .action-sheet-selected { + font-weight: normal !important; +} + +ion-action-sheet .action-sheet-selected.action-sheet-selected:after { + background: none; +} + +/* Double class to override ionic specificity */ +ion-action-sheet .action-sheet-selected .action-sheet-button-inner::after { + content: ""; + z-index: 1; + position: absolute; + right: 14px; + top: 50%; + transform: translateY(-50%); + + /* Ion check icon */ + background-image: url('data:image/svg+xml,'); + + width: 24px; + height: 24px; +} + +ion-action-sheet + .action-sheet-selected.detail + .action-sheet-button-inner::after { + right: 40px; +} + +ion-action-sheet ion-icon { + flex-shrink: 0; + margin-inline-end: 16px !important; +} + +.ios .action-sheet-button:not(.action-sheet-cancel) { + padding-inline-end: 0 !important; + padding-inline-start: 0; +} + +.ios .left-align-buttons .action-sheet-button:not(.action-sheet-cancel) { + padding-inline-start: 14px; +} + +.action-sheet-button-inner { + mask-image: linear-gradient( + 90deg, + rgba(0, 0, 0, 1) 0%, + rgba(0, 0, 0, 1) calc(100% - 16px), + transparent 100% + ); +} + +/* photoswipe */ + +.pswp__top-bar { + top: env(safe-area-inset-top, 0); +} + +/* Let IonActionSheet be on top */ +.pswp { + --pswp-root-z-index: 100; +} + +.ion-content-scroll-host { + overflow-y: auto; +} + +.virtual-scroller { + overflow-x: hidden !important; +} + +.ios { + .ion-content-scroll-host::before, + .ion-content-scroll-host::after { + position: absolute; + width: 1px; + height: 1px; + content: ""; + } + + .ion-content-scroll-host::before { + top: -1px; + } + + .ion-content-scroll-host::after { + bottom: -1px; + } +} + +ion-fab-button { + --background-focused: var(--ion-color-primary); + --background-activated: var(--ion-color-primary); + --background-hover: var(--ion-color-primary); +} + +ion-fab.fab-vertical-top { + top: 15vh; +} + +/** + * This patch reverts the following Ionic change: + * https://github.com/ionic-team/ionic-framework/pull/28246/files#diff-8371750710eecf6a609337a240b7db295073f746f1cda13248f9780cc6f6ff24L159 + * + * Private discord discussion: https://discord.com/channels/520266681499779082/1128001453676568637/1162812415054983198 + * + * Fixes #780 + */ +.ion-page { + overflow: hidden; +} + +ion-toast { + font-weight: 600; + --height: 45px; +} + +/* Center toast message and icon */ +ion-toast.center::part(container) { + display: inline-flex; + transform: translateX(-50%); + left: 50%; + position: relative; +} + +/* Make header buttons closer together (room for mod button) */ +.sc-ion-buttons-ios-s ion-button { + margin: 0; +} + +/* Add minimum padding for top dismiss area of action sheet */ +.action-sheet-group.sc-ion-action-sheet-ios:first-child { + margin-top: min(15vh, 70px); +} + +#share-as-image-root { + font-size: 16px; + + --width: 330px; + color: var(--ion-text-color); + + position: absolute; + width: var(--width); + right: calc(var(--width) * -1); + + a { + /* Hack for long links breaking */ + word-break: break-word; + } +} + +#share-as-image-root ion-item { + font-size: 16px; +} + +ion-modal.save-as-image-modal { + --height: auto; + --max-width: 470px; +} + +#share-as-image-root video { + display: none; +} + +.collapse-md-margins { + > *:first-child, + > *:first-child > *:first-child, + > *:first-child > *:first-child > *:first-child { + margin-top: 0; + } + + > *:last-child, + > *:last-child > *:last-child, + > *:last-child > *:last-child > *:last-child { + margin-bottom: 0; + } +} diff --git a/src/core/globalCssOverrides.ts b/src/core/globalCssOverrides.ts deleted file mode 100644 index 534bd4cf83..0000000000 --- a/src/core/globalCssOverrides.ts +++ /dev/null @@ -1,325 +0,0 @@ -import { css } from "@linaria/core"; - -import "./syntaxHighlightCss"; - -export default css` - :global() { - :root { - --sat: env(safe-area-inset-top); - --sar: env(safe-area-inset-right); - --sab: env(safe-area-inset-bottom); - --sal: env(safe-area-inset-left); - } - - html { - -webkit-text-size-adjust: 100%; /* Prevent font scaling in landscape while allowing user zoom */ - } - - .ReactCollapse--collapse { - transition: height 200ms; - } - - ion-tab-button { - opacity: 1 !important; - } - - ion-router-outlet > .ion-page > ion-header { - // Header doesn't support dynamic font size - ion-button, - ion-back-button, - ion-title { - font-size: 17px; - } - - // Ionic's default font size for icons in header is a bit too large - ion-button.in-toolbar ion-icon { - font-size: 1.35em !important; - } - - ion-back-button.md::part(text) { - display: none; - } - } - - ion-router-outlet ion-list.list-inset ion-item { - --background: var( - --ion-tab-bar-background, - var(--ion-background-color-step-50, #fff) - ); - } - - .left-align-buttons - .action-sheet-button:not(.action-sheet-cancel) - .action-sheet-button-inner.sc-ion-action-sheet-ios:not( - .action-sheet-group-cancel - ) { - justify-content: flex-start; - } - - .mod .action-sheet-button:not(.action-sheet-destructive), - .mod .action-sheet-button:hover:not(.action-sheet-destructive), - .mod.action-sheet-button:not(.action-sheet-destructive), - .mod.action-sheet-button:hover:not(.action-sheet-destructive) { - --color: var(--ion-color-success-shade); - color: var(--color); - } - - .mod.alert-button { - color: var(--ion-color-success-shade); - } - - .admin-local .action-sheet-button, - .admin-local .action-sheet-button:hover, - .admin-local.action-sheet-button, - .admin-local.action-sheet-button:hover, - .admin-remote .action-sheet-button, - .admin-remote .action-sheet-button:hover, - .admin-remote.action-sheet-button, - .admin-remote.action-sheet-button:hover { - --color: var(--ion-color-danger-shade); - color: var(--color); - } - - .report-reasons .action-sheet-title { - white-space: pre; - } - - /* https://github.com/ionic-team/ionic-framework/issues/27777#issuecomment-1631522283 */ - .action-sheet-height-fix { - --height: 100%; - } - - ion-modal.small { - --height: 50%; - --width: 85%; - --max-width: 400px; - --max-height: 500px; - --border-radius: 16px; - --box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), - 0 4px 6px -4px rgb(0 0 0 / 0.1); - } - ion-modal.small ion-header ion-toolbar:first-of-type { - padding-top: 0px; - } - - ion-modal.transparent-scroll { - --background: none; - --height: auto; - --box-shadow: none; - - &.show-modal { - display: flex; - flex-direction: column; - } - } - - ion-modal.transparent-scroll .ion-page { - overflow: auto; - } - - ion-alert.preserve-newlines { - white-space: pre-line; - } - - .pswp__img { - -webkit-touch-callout: default; - } - - // gets in the way of non-post preview more actions button - .pswp__preloader { - display: none; - } - - ion-action-sheet .detail::before { - content: ""; - z-index: 1; - position: absolute; - right: 12px; - top: 50%; - transform: translateY(-50%); - - /* Ion chevron right icon */ - background-image: url('data:image/svg+xml,'); - width: 24px; - height: 24px; - } - - ion-action-sheet .action-sheet-selected { - font-weight: normal !important; - } - - ion-action-sheet .action-sheet-selected.action-sheet-selected:after { - background: none; - } - - /* Double class to override ionic specificity */ - ion-action-sheet .action-sheet-selected .action-sheet-button-inner::after { - content: ""; - z-index: 1; - position: absolute; - right: 14px; - top: 50%; - transform: translateY(-50%); - - /* Ion check icon */ - background-image: url('data:image/svg+xml,'); - - width: 24px; - height: 24px; - } - - ion-action-sheet - .action-sheet-selected.detail - .action-sheet-button-inner::after { - right: 40px; - } - - ion-action-sheet ion-icon { - flex-shrink: 0; - margin-inline-end: 16px !important; - } - - .ios .action-sheet-button:not(.action-sheet-cancel) { - padding-inline-end: 0 !important; - padding-inline-start: 0; - } - - .ios .left-align-buttons .action-sheet-button:not(.action-sheet-cancel) { - padding-inline-start: 14px; - } - - .action-sheet-button-inner { - mask-image: linear-gradient( - 90deg, - rgba(0, 0, 0, 1) 0%, - rgba(0, 0, 0, 1) calc(100% - 16px), - transparent 100% - ); - } - - /* photoswipe */ - - .pswp__top-bar { - top: env(safe-area-inset-top, 0); - } - - /* Let IonActionSheet be on top */ - .pswp { - --pswp-root-z-index: 100; - } - - .ion-content-scroll-host { - overflow-y: auto; - } - - .virtual-scroller { - overflow-x: hidden !important; - } - - .ios { - .ion-content-scroll-host::before, - .ion-content-scroll-host::after { - position: absolute; - width: 1px; - height: 1px; - content: ""; - } - - .ion-content-scroll-host::before { - top: -1px; - } - - .ion-content-scroll-host::after { - bottom: -1px; - } - } - - ion-fab-button { - --background-focused: var(--ion-color-primary); - --background-activated: var(--ion-color-primary); - --background-hover: var(--ion-color-primary); - } - - ion-fab.fab-vertical-top { - top: 15vh; - } - - /** - * This patch reverts the following Ionic change: - * https://github.com/ionic-team/ionic-framework/pull/28246/files#diff-8371750710eecf6a609337a240b7db295073f746f1cda13248f9780cc6f6ff24L159 - * - * Private discord discussion: https://discord.com/channels/520266681499779082/1128001453676568637/1162812415054983198 - * - * Fixes #780 - */ - .ion-page { - overflow: hidden; - } - - ion-toast { - font-weight: 600; - --height: 45px; - } - - /* Center toast message and icon */ - ion-toast.center::part(container) { - display: inline-flex; - transform: translateX(-50%); - left: 50%; - position: relative; - } - - /* Make header buttons closer together (room for mod button) */ - .sc-ion-buttons-ios-s ion-button { - margin: 0; - } - - /* Add minimum padding for top dismiss area of action sheet */ - .action-sheet-group.sc-ion-action-sheet-ios:first-child { - margin-top: min(15vh, 70px); - } - - #share-as-image-root { - font-size: 16px; - - --width: 330px; - color: var(--ion-text-color); - - position: absolute; - width: var(--width); - right: calc(var(--width) * -1); - - a { - /* Hack for long links breaking */ - word-break: break-word; - } - } - - #share-as-image-root ion-item { - font-size: 16px; - } - - ion-modal.save-as-image-modal { - --height: auto; - --max-width: 470px; - } - - #share-as-image-root video { - display: none; - } - - .collapse-md-margins { - > *:first-child, - > *:first-child > *:first-child, - > *:first-child > *:first-child > *:first-child { - margin-top: 0; - } - - > *:last-child, - > *:last-child > *:last-child, - > *:last-child > *:last-child > *:last-child { - margin-bottom: 0; - } - } - } -`; diff --git a/src/core/listeners/index.tsx b/src/core/listeners/index.tsx index 62dc6944a8..f8142fd461 100644 --- a/src/core/listeners/index.tsx +++ b/src/core/listeners/index.tsx @@ -4,6 +4,8 @@ import AndroidBackButton from "./AndroidBackButton"; import AppUrlListener from "./AppUrlListener"; import DatabaseErrorListener from "./DatabaseErrorListener"; import HapticsListener from "./HapticsListener"; + +// Listeners import "./androidSafeArea"; import "./ionActivatable"; import "./network/listener"; diff --git a/src/core/listeners/network/networkSlice.ts b/src/core/listeners/network/networkSlice.ts index 57a877288b..3606eacd9e 100644 --- a/src/core/listeners/network/networkSlice.ts +++ b/src/core/listeners/network/networkSlice.ts @@ -1,5 +1,5 @@ import { ConnectionType, Network } from "@capacitor/network"; -import { PayloadAction, createAsyncThunk, createSlice } from "@reduxjs/toolkit"; +import { createAsyncThunk, createSlice, PayloadAction } from "@reduxjs/toolkit"; interface NetworkState { connectionType: ConnectionType; diff --git a/src/core/syntaxHighlightCss.ts b/src/core/syntaxHighlightCss.ts deleted file mode 100644 index 7392b7d23b..0000000000 --- a/src/core/syntaxHighlightCss.ts +++ /dev/null @@ -1,170 +0,0 @@ -import { css } from "@linaria/core"; - -export default css` - :global() { - html.ion-palette-dark { - .hljs-doctag, - .hljs-keyword, - .hljs-meta .hljs-keyword, - .hljs-template-tag, - .hljs-template-variable, - .hljs-type, - .hljs-variable.language_ { - color: #ff7b72; - } - .hljs-title, - .hljs-title.class_, - .hljs-title.class_.inherited__, - .hljs-title.function_ { - color: #d2a8ff; - } - .hljs-attr, - .hljs-attribute, - .hljs-literal, - .hljs-meta, - .hljs-number, - .hljs-operator, - .hljs-variable, - .hljs-selector-attr, - .hljs-selector-class, - .hljs-selector-id { - color: #79c0ff; - } - .hljs-regexp, - .hljs-string, - .hljs-meta .hljs-string { - color: #a5d6ff; - } - .hljs-built_in, - .hljs-symbol { - color: #ffa657; - } - .hljs-comment, - .hljs-code, - .hljs-formula { - color: #8b949e; - } - .hljs-name, - .hljs-quote, - .hljs-selector-tag, - .hljs-selector-pseudo { - color: #7ee787; - } - .hljs-subst { - color: #c9d1d9; - } - .hljs-section { - color: #1f6feb; - font-weight: bold; - } - .hljs-bullet { - color: #f2cc60; - } - .hljs-emphasis { - color: #c9d1d9; - font-style: italic; - } - .hljs-strong { - color: #c9d1d9; - font-weight: bold; - } - .hljs-addition { - color: #aff5b4; - background-color: #033a16; - } - .hljs-deletion { - color: #ffdcd7; - background-color: #67060c; - } - } - - html:not(.ion-palette-dark) { - .hljs-doctag, - .hljs-keyword, - .hljs-meta .hljs-keyword, - .hljs-template-tag, - .hljs-template-variable, - .hljs-type, - .hljs-variable.language_ { - color: #d73a49; - } - - .hljs-title, - .hljs-title.class_, - .hljs-title.class_.inherited__, - .hljs-title.function_ { - color: #6f42c1; - } - - .hljs-attr, - .hljs-attribute, - .hljs-literal, - .hljs-meta, - .hljs-number, - .hljs-operator, - .hljs-variable, - .hljs-selector-attr, - .hljs-selector-class, - .hljs-selector-id { - color: #005cc5; - } - - .hljs-regexp, - .hljs-string, - .hljs-meta .hljs-string { - color: #032f62; - } - - .hljs-built_in, - .hljs-symbol { - color: #e36209; - } - - .hljs-comment, - .hljs-code, - .hljs-formula { - color: #6a737d; - } - - .hljs-name, - .hljs-quote, - .hljs-selector-tag, - .hljs-selector-pseudo { - color: #22863a; - } - - .hljs-subst { - color: #24292e; - } - - .hljs-section { - color: #005cc5; - font-weight: bold; - } - - .hljs-bullet { - color: #735c0f; - } - - .hljs-emphasis { - color: #24292e; - font-style: italic; - } - - .hljs-strong { - color: #24292e; - font-weight: bold; - } - - .hljs-addition { - color: #22863a; - background-color: #f0fff4; - } - - .hljs-deletion { - color: #b31d28; - background-color: #ffeef0; - } - } - } -`; diff --git a/src/core/syntaxHighlights.css b/src/core/syntaxHighlights.css new file mode 100644 index 0000000000..ad599e52b1 --- /dev/null +++ b/src/core/syntaxHighlights.css @@ -0,0 +1,164 @@ +html.ion-palette-dark { + .hljs-doctag, + .hljs-keyword, + .hljs-meta .hljs-keyword, + .hljs-template-tag, + .hljs-template-variable, + .hljs-type, + .hljs-variable.language_ { + color: #ff7b72; + } + .hljs-title, + .hljs-title.class_, + .hljs-title.class_.inherited__, + .hljs-title.function_ { + color: #d2a8ff; + } + .hljs-attr, + .hljs-attribute, + .hljs-literal, + .hljs-meta, + .hljs-number, + .hljs-operator, + .hljs-variable, + .hljs-selector-attr, + .hljs-selector-class, + .hljs-selector-id { + color: #79c0ff; + } + .hljs-regexp, + .hljs-string, + .hljs-meta .hljs-string { + color: #a5d6ff; + } + .hljs-built_in, + .hljs-symbol { + color: #ffa657; + } + .hljs-comment, + .hljs-code, + .hljs-formula { + color: #8b949e; + } + .hljs-name, + .hljs-quote, + .hljs-selector-tag, + .hljs-selector-pseudo { + color: #7ee787; + } + .hljs-subst { + color: #c9d1d9; + } + .hljs-section { + color: #1f6feb; + font-weight: bold; + } + .hljs-bullet { + color: #f2cc60; + } + .hljs-emphasis { + color: #c9d1d9; + font-style: italic; + } + .hljs-strong { + color: #c9d1d9; + font-weight: bold; + } + .hljs-addition { + color: #aff5b4; + background-color: #033a16; + } + .hljs-deletion { + color: #ffdcd7; + background-color: #67060c; + } +} + +html:not(.ion-palette-dark) { + .hljs-doctag, + .hljs-keyword, + .hljs-meta .hljs-keyword, + .hljs-template-tag, + .hljs-template-variable, + .hljs-type, + .hljs-variable.language_ { + color: #d73a49; + } + + .hljs-title, + .hljs-title.class_, + .hljs-title.class_.inherited__, + .hljs-title.function_ { + color: #6f42c1; + } + + .hljs-attr, + .hljs-attribute, + .hljs-literal, + .hljs-meta, + .hljs-number, + .hljs-operator, + .hljs-variable, + .hljs-selector-attr, + .hljs-selector-class, + .hljs-selector-id { + color: #005cc5; + } + + .hljs-regexp, + .hljs-string, + .hljs-meta .hljs-string { + color: #032f62; + } + + .hljs-built_in, + .hljs-symbol { + color: #e36209; + } + + .hljs-comment, + .hljs-code, + .hljs-formula { + color: #6a737d; + } + + .hljs-name, + .hljs-quote, + .hljs-selector-tag, + .hljs-selector-pseudo { + color: #22863a; + } + + .hljs-subst { + color: #24292e; + } + + .hljs-section { + color: #005cc5; + font-weight: bold; + } + + .hljs-bullet { + color: #735c0f; + } + + .hljs-emphasis { + color: #24292e; + font-style: italic; + } + + .hljs-strong { + color: #24292e; + font-weight: bold; + } + + .hljs-addition { + color: #22863a; + background-color: #f0fff4; + } + + .hljs-deletion { + color: #b31d28; + background-color: #ffeef0; + } +} diff --git a/src/core/theme/darkModifierVariables.css b/src/core/theme/darkModifierVariables.css new file mode 100644 index 0000000000..3a3b22d07e --- /dev/null +++ b/src/core/theme/darkModifierVariables.css @@ -0,0 +1,70 @@ +html.ion-palette-dark { + &:not(.theme-pure-black) { + &.ios { + body { + --ion-background-color: #22252f; + --ion-background-color-rgb: 34, 37, 47; + --ion-tab-bar-background: rgba(0, 0, 0, 0.2); + --ion-toolbar-border-color: #444; + + ion-tab-bar { + --ion-tab-bar-background: var(--ion-background-color); + --ion-tab-bar-border-color: #444; + } + } + } + + &.md { + body { + --ion-background-color: #1e1e1e; + --ion-background-color-rgb: 18, 18, 18; + + --ion-text-color: #ffffff; + --ion-text-color-rgb: 255, 255, 255; + + --ion-border-color: #222222; + + --ion-item-background: #1e1e1e; + + --ion-toolbar-background: #1f1f1f; + + --ion-tab-bar-background: #1f1f1f; + + --ion-card-background: #1e1e1e; + } + } + } + + &.theme-pure-black { + &.ios { + body { + --ion-background-color: #000000; + --ion-background-color-rgb: 0, 0, 0; + } + } + + &:not(.theme-has-custom-background) { + &.md { + body { + --ion-item-background: black; + --ion-toolbar-background: #121212; + --ion-tab-bar-background: #121212; + } + } + } + + &.md { + body { + --ion-background-color: black; + --ion-background-color-rgb: 18, 18, 18; + + --ion-text-color: #ffffff; + --ion-text-color-rgb: 255, 255, 255; + + --ion-border-color: #222222; + + --ion-card-background: black; + } + } + } +} diff --git a/src/core/theme/darkVariables.css b/src/core/theme/darkVariables.css new file mode 100644 index 0000000000..b21055ab39 --- /dev/null +++ b/src/core/theme/darkVariables.css @@ -0,0 +1,118 @@ +html.ion-palette-dark { + /* Dark Colors */ + &:root { + --ion-color-primary-fixed: #428cff; /* always blue always blue! */ + + --lightroom-bg: rgba(255, 255, 255, 0.08); + + --ion-item-border-color: #333; + } + + body { + --ion-color-primary: var(--app-primary); + --ion-color-primary-rgb: 66, 140, 255; + --ion-color-primary-contrast: #ffffff; + --ion-color-primary-contrast-rgb: 255, 255, 255; + --ion-color-primary-shade: #3a7be0; + --ion-color-primary-tint: #5598ff; + + --ion-color-secondary: #50c8ff; + --ion-color-secondary-rgb: 80, 200, 255; + --ion-color-secondary-contrast: #ffffff; + --ion-color-secondary-contrast-rgb: 255, 255, 255; + --ion-color-secondary-shade: #46b0e0; + --ion-color-secondary-tint: #62ceff; + + --ion-color-tertiary: #6a64ff; + --ion-color-tertiary-rgb: 106, 100, 255; + --ion-color-tertiary-contrast: #ffffff; + --ion-color-tertiary-contrast-rgb: 255, 255, 255; + --ion-color-tertiary-shade: #5d58e0; + --ion-color-tertiary-tint: #7974ff; + + --ion-color-success: #00940c; + --ion-color-success-rgb: 0, 148, 12; + --ion-color-success-contrast: #ffffff; + --ion-color-success-contrast-rgb: 255, 255, 255; + --ion-color-success-shade: #00820b; + --ion-color-success-tint: #1a9f24; + + --ion-color-warning: #eac200; + --ion-color-warning-rgb: 234, 194, 0; + --ion-color-warning-contrast: #000000; + --ion-color-warning-contrast-rgb: 0, 0, 0; + --ion-color-warning-shade: #ceab00; + --ion-color-warning-tint: #ecc81a; + + --ion-color-danger: #ff4961; + --ion-color-danger-rgb: 255, 73, 97; + --ion-color-danger-contrast: #ffffff; + --ion-color-danger-contrast-rgb: 255, 255, 255; + --ion-color-danger-shade: #e04055; + --ion-color-danger-tint: #ff5b71; + + --ion-color-dark: #f4f5f8; + --ion-color-dark-rgb: 244, 245, 248; + --ion-color-dark-contrast: #000000; + --ion-color-dark-contrast-rgb: 0, 0, 0; + --ion-color-dark-shade: #d7d8da; + --ion-color-dark-tint: #f5f6f9; + + --ion-color-medium: #989aa2; + --ion-color-medium-rgb: 152, 154, 162; + --ion-color-medium-contrast: #000000; + --ion-color-medium-contrast-rgb: 0, 0, 0; + --ion-color-medium-shade: #86888f; + --ion-color-medium-tint: #a2a4ab; + + --ion-color-medium2: rgb(112, 113, 120); + + --thick-separator-color: rgba(255, 255, 255, 0.08); + + --unread-item-background-color: #162f4a; + + --ion-color-text-aside: rgba(255, 255, 255, 0.65); + + --read-color: rgba(255, 255, 255, 0.6); + --read-color-medium: rgba(255, 255, 255, 0.4); + + --share-img-drop-shadow: drop-shadow(0 0 8px black); + + --ion-color-reddit-upvote: #f26700; + } + + /* iOS Dark Theme */ + + &.ios body { + /* --ion-text-color: #ddd; + --ion-text-color-rgb: 255, 255, 255; */ + + --ion-item-background: var(--ion-background-color); + + --ion-card-background: #1c1c1d; + + --ion-toolbar-background: var(--ion-background-color); + } + + &.ios ion-modal { + --ion-background-color: var(--ion-background-color-step-100); + --ion-toolbar-background: var(--ion-background-color-step-150); + --ion-toolbar-border-color: var(--ion-background-color-step-250); + --ion-item-background: var(--ion-background-color-step-50); + } + + /* Material Design Dark Theme */ + + @media (max-width: 767px) { + &.ios ion-modal:not(.small, .transparent-scroll) { + --ion-background-color: #000; + --ion-toolbar-background: var(--ion-background-color); + --ion-toolbar-border-color: var(--ion-background-color-step-150); + } + } + + /* TODO test other themes */ + ion-modal.transparent-scroll.dark { + --ion-background-color: inherit; + } +} diff --git a/src/core/theme/lightVariables.css b/src/core/theme/lightVariables.css new file mode 100644 index 0000000000..79ec5a2461 --- /dev/null +++ b/src/core/theme/lightVariables.css @@ -0,0 +1,34 @@ +html:not(.ion-palette-dark) { + &:root { + --ion-color-primary: var(--app-primary); + --ion-color-primary-fixed: #3880ff; /* always blue always blue! */ + + ion-item { + /* default ionic light mode opacity is too harsh */ + --background-activated-opacity: 0.06; + } + + &.ios .grey-bg { + --ion-background-color: var(--ion-background-color-step-50, #f2f2f7); + + ion-header { + --opacity: 0; + } + ion-modal ion-content { + --background: #fff; + } + ion-item { + --ion-background-color: #fff; + } + ion-item-sliding { + background: #fff; + } + } + + &.theme-has-custom-background { + ion-router-outlet .grey-bg ion-list.list-inset ion-item { + --background: var(--app-background); + } + } + } +} diff --git a/src/core/theme/variables.css b/src/core/theme/variables.css new file mode 100644 index 0000000000..f272b51758 --- /dev/null +++ b/src/core/theme/variables.css @@ -0,0 +1,137 @@ +:root { + --ion-text-color: #000; + + /** primary **/ + --ion-color-primary: #3880ff; + --ion-color-primary-rgb: 56, 128, 255; + --ion-color-primary-contrast: #ffffff; + --ion-color-primary-contrast-rgb: 255, 255, 255; + --ion-color-primary-shade: #3171e0; + --ion-color-primary-tint: #4c8dff; + + /** secondary **/ + --ion-color-secondary: #3dc2ff; + --ion-color-secondary-rgb: 61, 194, 255; + --ion-color-secondary-contrast: #ffffff; + --ion-color-secondary-contrast-rgb: 255, 255, 255; + --ion-color-secondary-shade: #36abe0; + --ion-color-secondary-tint: #50c8ff; + + /** tertiary **/ + --ion-color-tertiary: #5260ff; + --ion-color-tertiary-rgb: 82, 96, 255; + --ion-color-tertiary-contrast: #ffffff; + --ion-color-tertiary-contrast-rgb: 255, 255, 255; + --ion-color-tertiary-shade: #4854e0; + --ion-color-tertiary-tint: #6370ff; + + /** success **/ + --ion-color-success: #07be02; + --ion-color-success-rgb: 7, 190, 2; + --ion-color-success-contrast: #ffffff; + --ion-color-success-contrast-rgb: 255, 255, 255; + --ion-color-success-shade: #06a702; + --ion-color-success-tint: #20c51b; + + /** warning **/ + --ion-color-warning: #ffc409; + --ion-color-warning-rgb: 255, 196, 9; + --ion-color-warning-contrast: #000000; + --ion-color-warning-contrast-rgb: 0, 0, 0; + --ion-color-warning-shade: #e0ac08; + --ion-color-warning-tint: #ffca22; + + /** danger **/ + --ion-color-danger: #eb445a; + --ion-color-danger-rgb: 235, 68, 90; + --ion-color-danger-contrast: #ffffff; + --ion-color-danger-contrast-rgb: 255, 255, 255; + --ion-color-danger-shade: #cf3c4f; + --ion-color-danger-tint: #ed576b; + + /** dark **/ + --ion-color-dark: #222428; + --ion-color-dark-rgb: 34, 36, 40; + --ion-color-dark-contrast: #ffffff; + --ion-color-dark-contrast-rgb: 255, 255, 255; + --ion-color-dark-shade: #1e2023; + --ion-color-dark-tint: #383a3e; + + /** medium **/ + --ion-color-medium: #92949c; + --ion-color-medium-rgb: 146, 148, 156; + --ion-color-medium-contrast: #ffffff; + --ion-color-medium-contrast-rgb: 255, 255, 255; + --ion-color-medium-shade: #808289; + --ion-color-medium-tint: #9d9fa6; + + /** light **/ + --ion-color-light: #f4f5f8; + --ion-color-light-rgb: 244, 245, 248; + --ion-color-light-contrast: #000000; + --ion-color-light-contrast-rgb: 0, 0, 0; + --ion-color-light-shade: #d7d8da; + --ion-color-light-tint: #f5f6f9; + + --ion-color-medium2: var(--ion-color-medium); + + --lightroom-bg: rgba(0, 0, 0, 0.047); + + --thick-separator-color: var(--ion-background-color-step-50, #f2f2f7); + + --ion-background-color-step-100: #f3f3f3; + + --unread-item-background-color: #e3f1ff; + + --ion-color-text-aside: rgba(0, 0, 0, 0.55); + + --read-color: rgba(0, 0, 0, 0.45); + --read-color-medium: rgba(0, 0, 0, 0.4); + + --share-img-drop-shadow: none; + + --ion-color-reddit-upvote: #ff5c01; + + --markdown-toolbar-height: 50px; + + &.theme-has-custom-background { + &.ios body, + &.md body { + --ion-background-color: var(--app-background) !important; + --ion-item-background: var(--app-background); + --ion-background-color-step-50: var(--app-inset-item-background); + --ion-background-color-step-100: var(--app-tab-bar-background); + --ion-tab-bar-background: var(--app-tab-bar-background); + --ion-toolbar-background: var(--app-tab-bar-background); + --thick-separator-color: var(--app-inset-item-background); + } + + ion-router-outlet ion-list.list-inset ion-item { + --background: var(--app-inset-item-background); + } + + &.ios ion-modal:not(.transparent-scroll) { + --ion-background-color: var(--app-background); + --ion-toolbar-background: var(--app-tab-bar-background); + --ion-toolbar-border-color: var(--ion-background-color-step-150); + + --ion-item-background: var(--ion-background-color); + } + } +} + +.ios body { + --ion-background-color: #fff; +} + +.ios ion-modal { + --ion-background-color: var(--ion-background-color-step-50, #f2f2f7); + --ion-item-background: var(--app-background, #fff); +} + +.ion-color-primary-fixed { + --ion-color-base: var(--ion-color-primary-fixed); +} +.ion-color-reddit-upvote { + --ion-color-base: var(--ion-color-reddit-upvote); +} diff --git a/src/core/theme/variables.ts b/src/core/theme/variables.ts deleted file mode 100644 index 6351f778e1..0000000000 --- a/src/core/theme/variables.ts +++ /dev/null @@ -1,378 +0,0 @@ -import { css } from "@linaria/core"; - -export const baseVariables = css` - :global() { - :root { - --ion-text-color: #000; - - /** primary **/ - --ion-color-primary: #3880ff; - --ion-color-primary-rgb: 56, 128, 255; - --ion-color-primary-contrast: #ffffff; - --ion-color-primary-contrast-rgb: 255, 255, 255; - --ion-color-primary-shade: #3171e0; - --ion-color-primary-tint: #4c8dff; - - /** secondary **/ - --ion-color-secondary: #3dc2ff; - --ion-color-secondary-rgb: 61, 194, 255; - --ion-color-secondary-contrast: #ffffff; - --ion-color-secondary-contrast-rgb: 255, 255, 255; - --ion-color-secondary-shade: #36abe0; - --ion-color-secondary-tint: #50c8ff; - - /** tertiary **/ - --ion-color-tertiary: #5260ff; - --ion-color-tertiary-rgb: 82, 96, 255; - --ion-color-tertiary-contrast: #ffffff; - --ion-color-tertiary-contrast-rgb: 255, 255, 255; - --ion-color-tertiary-shade: #4854e0; - --ion-color-tertiary-tint: #6370ff; - - /** success **/ - --ion-color-success: #07be02; - --ion-color-success-rgb: 7, 190, 2; - --ion-color-success-contrast: #ffffff; - --ion-color-success-contrast-rgb: 255, 255, 255; - --ion-color-success-shade: #06a702; - --ion-color-success-tint: #20c51b; - - /** warning **/ - --ion-color-warning: #ffc409; - --ion-color-warning-rgb: 255, 196, 9; - --ion-color-warning-contrast: #000000; - --ion-color-warning-contrast-rgb: 0, 0, 0; - --ion-color-warning-shade: #e0ac08; - --ion-color-warning-tint: #ffca22; - - /** danger **/ - --ion-color-danger: #eb445a; - --ion-color-danger-rgb: 235, 68, 90; - --ion-color-danger-contrast: #ffffff; - --ion-color-danger-contrast-rgb: 255, 255, 255; - --ion-color-danger-shade: #cf3c4f; - --ion-color-danger-tint: #ed576b; - - /** dark **/ - --ion-color-dark: #222428; - --ion-color-dark-rgb: 34, 36, 40; - --ion-color-dark-contrast: #ffffff; - --ion-color-dark-contrast-rgb: 255, 255, 255; - --ion-color-dark-shade: #1e2023; - --ion-color-dark-tint: #383a3e; - - /** medium **/ - --ion-color-medium: #92949c; - --ion-color-medium-rgb: 146, 148, 156; - --ion-color-medium-contrast: #ffffff; - --ion-color-medium-contrast-rgb: 255, 255, 255; - --ion-color-medium-shade: #808289; - --ion-color-medium-tint: #9d9fa6; - - /** light **/ - --ion-color-light: #f4f5f8; - --ion-color-light-rgb: 244, 245, 248; - --ion-color-light-contrast: #000000; - --ion-color-light-contrast-rgb: 0, 0, 0; - --ion-color-light-shade: #d7d8da; - --ion-color-light-tint: #f5f6f9; - - --ion-color-medium2: var(--ion-color-medium); - - --lightroom-bg: rgba(0, 0, 0, 0.047); - - --thick-separator-color: var(--ion-background-color-step-50, #f2f2f7); - - --ion-background-color-step-100: #f3f3f3; - - --unread-item-background-color: #e3f1ff; - - --ion-color-text-aside: rgba(0, 0, 0, 0.55); - - --read-color: rgba(0, 0, 0, 0.45); - --read-color-medium: rgba(0, 0, 0, 0.4); - - --share-img-drop-shadow: none; - - --ion-color-reddit-upvote: #ff5c01; - - &.theme-has-custom-background { - &.ios body, - &.md body { - --ion-background-color: var(--app-background) !important; - --ion-item-background: var(--app-background); - --ion-background-color-step-50: var(--app-inset-item-background); - --ion-background-color-step-100: var(--app-tab-bar-background); - --ion-tab-bar-background: var(--app-tab-bar-background); - --ion-toolbar-background: var(--app-tab-bar-background); - --thick-separator-color: var(--app-inset-item-background); - } - - ion-router-outlet ion-list.list-inset ion-item { - --background: var(--app-inset-item-background); - } - - &.ios ion-modal:not(.transparent-scroll) { - --ion-background-color: var(--app-background); - --ion-toolbar-background: var(--app-tab-bar-background); - --ion-toolbar-border-color: var(--ion-background-color-step-150); - - --ion-item-background: var(--ion-background-color); - } - } - } - - .ios body { - --ion-background-color: #fff; - } - - .ios ion-modal { - --ion-background-color: var(--ion-background-color-step-50, #f2f2f7); - --ion-item-background: var(--app-background, #fff); - } - - .ion-color-primary-fixed { - --ion-color-base: var(--ion-color-primary-fixed); - } - .ion-color-reddit-upvote { - --ion-color-base: var(--ion-color-reddit-upvote); - } - } -`; - -export const lightVariables = css` - :global() { - html:not(.ion-palette-dark) { - &:root { - --ion-color-primary: var(--app-primary); - --ion-color-primary-fixed: #3880ff; // always blue always blue! - - ion-item { - // default ionic light mode opacity is too harsh - --background-activated-opacity: 0.06; - } - - &.ios .grey-bg { - --ion-background-color: var(--ion-background-color-step-50, #f2f2f7); - - ion-header { - --opacity: 0; - } - ion-modal ion-content { - --background: #fff; - } - ion-item { - --ion-background-color: #fff; - } - ion-item-sliding { - background: #fff; - } - } - - &.theme-has-custom-background { - ion-router-outlet .grey-bg ion-list.list-inset ion-item { - --background: var(--app-background); - } - } - } - } - } -`; - -export const darkVariables = css` - :global() { - html.ion-palette-dark { - // Dark Colors - &:root { - --ion-color-primary-fixed: #428cff; // always blue always blue! - - --lightroom-bg: rgba(255, 255, 255, 0.08); - - --ion-item-border-color: #333; - } - - body { - --ion-color-primary: var(--app-primary); - --ion-color-primary-rgb: 66, 140, 255; - --ion-color-primary-contrast: #ffffff; - --ion-color-primary-contrast-rgb: 255, 255, 255; - --ion-color-primary-shade: #3a7be0; - --ion-color-primary-tint: #5598ff; - - --ion-color-secondary: #50c8ff; - --ion-color-secondary-rgb: 80, 200, 255; - --ion-color-secondary-contrast: #ffffff; - --ion-color-secondary-contrast-rgb: 255, 255, 255; - --ion-color-secondary-shade: #46b0e0; - --ion-color-secondary-tint: #62ceff; - - --ion-color-tertiary: #6a64ff; - --ion-color-tertiary-rgb: 106, 100, 255; - --ion-color-tertiary-contrast: #ffffff; - --ion-color-tertiary-contrast-rgb: 255, 255, 255; - --ion-color-tertiary-shade: #5d58e0; - --ion-color-tertiary-tint: #7974ff; - - --ion-color-success: #00940c; - --ion-color-success-rgb: 0, 148, 12; - --ion-color-success-contrast: #ffffff; - --ion-color-success-contrast-rgb: 255, 255, 255; - --ion-color-success-shade: #00820b; - --ion-color-success-tint: #1a9f24; - - --ion-color-warning: #eac200; - --ion-color-warning-rgb: 234, 194, 0; - --ion-color-warning-contrast: #000000; - --ion-color-warning-contrast-rgb: 0, 0, 0; - --ion-color-warning-shade: #ceab00; - --ion-color-warning-tint: #ecc81a; - - --ion-color-danger: #ff4961; - --ion-color-danger-rgb: 255, 73, 97; - --ion-color-danger-contrast: #ffffff; - --ion-color-danger-contrast-rgb: 255, 255, 255; - --ion-color-danger-shade: #e04055; - --ion-color-danger-tint: #ff5b71; - - --ion-color-dark: #f4f5f8; - --ion-color-dark-rgb: 244, 245, 248; - --ion-color-dark-contrast: #000000; - --ion-color-dark-contrast-rgb: 0, 0, 0; - --ion-color-dark-shade: #d7d8da; - --ion-color-dark-tint: #f5f6f9; - - --ion-color-medium: #989aa2; - --ion-color-medium-rgb: 152, 154, 162; - --ion-color-medium-contrast: #000000; - --ion-color-medium-contrast-rgb: 0, 0, 0; - --ion-color-medium-shade: #86888f; - --ion-color-medium-tint: #a2a4ab; - - --ion-color-medium2: rgb(112, 113, 120); - - --thick-separator-color: rgba(255, 255, 255, 0.08); - - --unread-item-background-color: #162f4a; - - --ion-color-text-aside: rgba(255, 255, 255, 0.65); - - --read-color: rgba(255, 255, 255, 0.6); - --read-color-medium: rgba(255, 255, 255, 0.4); - - --share-img-drop-shadow: drop-shadow(0 0 8px black); - - --ion-color-reddit-upvote: #f26700; - } - - // iOS Dark Theme - - &.ios body { - /* --ion-text-color: #ddd; - --ion-text-color-rgb: 255, 255, 255; */ - - --ion-item-background: var(--ion-background-color); - - --ion-card-background: #1c1c1d; - - --ion-toolbar-background: var(--ion-background-color); - } - - &.ios ion-modal { - --ion-background-color: var(--ion-background-color-step-100); - --ion-toolbar-background: var(--ion-background-color-step-150); - --ion-toolbar-border-color: var(--ion-background-color-step-250); - --ion-item-background: var(--ion-background-color-step-50); - } - - // Material Design Dark Theme - - @media (max-width: 767px) { - &.ios ion-modal:not(.small, .transparent-scroll) { - --ion-background-color: #000; - --ion-toolbar-background: var(--ion-background-color); - --ion-toolbar-border-color: var(--ion-background-color-step-150); - } - } - - // TODO test other themes - ion-modal.transparent-scroll.dark { - --ion-background-color: inherit; - } - } - } -`; - -export const darkBlackModifierVariables = css` - :global() { - html.ion-palette-dark { - &:not(.theme-pure-black) { - &.ios { - body { - --ion-background-color: #22252f; - --ion-background-color-rgb: 34, 37, 47; - --ion-tab-bar-background: rgba(0, 0, 0, 0.2); - --ion-toolbar-border-color: #444; - - ion-tab-bar { - --ion-tab-bar-background: var(--ion-background-color); - --ion-tab-bar-border-color: #444; - } - } - } - - &.md { - body { - --ion-background-color: #1e1e1e; - --ion-background-color-rgb: 18, 18, 18; - - --ion-text-color: #ffffff; - --ion-text-color-rgb: 255, 255, 255; - - --ion-border-color: #222222; - - --ion-item-background: #1e1e1e; - - --ion-toolbar-background: #1f1f1f; - - --ion-tab-bar-background: #1f1f1f; - - --ion-card-background: #1e1e1e; - } - } - } - - &.theme-pure-black { - &.ios { - body { - --ion-background-color: #000000; - --ion-background-color-rgb: 0, 0, 0; - } - } - - &:not(.theme-has-custom-background) { - &.md { - body { - --ion-item-background: black; - --ion-toolbar-background: #121212; - --ion-tab-bar-background: #121212; - } - } - } - - &.md { - body { - --ion-background-color: black; - --ion-background-color-rgb: 18, 18, 18; - - --ion-text-color: #ffffff; - --ion-text-color-rgb: 255, 255, 255; - - --ion-border-color: #222222; - - --ion-card-background: black; - } - } - } - } - } -`; diff --git a/src/features/auth/AppContext.tsx b/src/features/auth/AppContext.tsx index b4b29fc819..6e41b458fd 100644 --- a/src/features/auth/AppContext.tsx +++ b/src/features/auth/AppContext.tsx @@ -1,8 +1,8 @@ import { useIonViewDidEnter } from "@ionic/react"; import { noop } from "es-toolkit"; import React, { - RefObject, createContext, + RefObject, useContext, useEffect, useRef, diff --git a/src/features/auth/PageContext.module.css b/src/features/auth/PageContext.module.css new file mode 100644 index 0000000000..d3e3caf71d --- /dev/null +++ b/src/features/auth/PageContext.module.css @@ -0,0 +1,3 @@ +.autoHeight { + --height: auto; +} diff --git a/src/features/auth/PageContext.tsx b/src/features/auth/PageContext.tsx index f6c8987e9e..b0571e0e0a 100644 --- a/src/features/auth/PageContext.tsx +++ b/src/features/auth/PageContext.tsx @@ -1,5 +1,4 @@ import { useIonModal } from "@ionic/react"; -import { css } from "@linaria/core"; import { noop } from "es-toolkit"; import { Comment, @@ -10,8 +9,8 @@ import { PrivateMessageView, } from "lemmy-js-client"; import React, { - RefObject, createContext, + RefObject, useEffect, useRef, useState, @@ -21,17 +20,17 @@ import { changeAccount } from "#/features/auth/authSlice"; import BanUserModal from "#/features/moderation/ban/BanUserModal"; import CreateCrosspostDialog from "#/features/post/crosspost/create/CreateCrosspostDialog"; import PostEditorModal from "#/features/post/new/PostEditorModal"; -import Report, { ReportHandle, ReportableItem } from "#/features/report/Report"; +import Report, { ReportableItem, ReportHandle } from "#/features/report/Report"; import DatabaseErrorModal from "#/features/settings/root/DatabaseErrorModal"; import ShareAsImageModal, { ShareAsImageData, } from "#/features/share/asImage/ShareAsImageModal"; -import SelectTextModal from "#/features/shared/SelectTextModal"; +import { CommentReplyItem } from "#/features/shared/markdown/editing/modal/contents/CommentReplyPage"; +import { NewPrivateMessage } from "#/features/shared/markdown/editing/modal/contents/PrivateMessagePage"; import GenericMarkdownEditorModal, { MarkdownEditorData, } from "#/features/shared/markdown/editing/modal/GenericMarkdownEditorModal"; -import { CommentReplyItem } from "#/features/shared/markdown/editing/modal/contents/CommentReplyPage"; -import { NewPrivateMessage } from "#/features/shared/markdown/editing/modal/contents/PrivateMessagePage"; +import SelectTextModal from "#/features/shared/SelectTextModal"; import UserTagModal from "#/features/tags/UserTagModal"; import { useAppDispatch, useAppSelector } from "#/store"; @@ -39,6 +38,8 @@ import AccountSwitcher from "./AccountSwitcher"; import { jwtSelector } from "./authSelectors"; import LoginModal from "./login/LoginModal"; +import styles from "./PageContext.module.css"; + export interface BanUserPayload { user: Person; community: Community; @@ -145,9 +146,7 @@ export function PageContextProvider({ value, children }: PageContextProvider) { _presentDatabaseErrorModal({ initialBreakpoint: 1, breakpoints: [0, 1], - cssClass: css` - --height: auto; - `, + cssClass: styles.autoHeight, }); }; diff --git a/src/features/auth/authSlice.ts b/src/features/auth/authSlice.ts index b74aa4f1fc..d0e8bec055 100644 --- a/src/features/auth/authSlice.ts +++ b/src/features/auth/authSlice.ts @@ -1,4 +1,4 @@ -import { PayloadAction, createSlice } from "@reduxjs/toolkit"; +import { createSlice, PayloadAction } from "@reduxjs/toolkit"; import { ApplicationContext } from "capacitor-application-context"; import { uniqBy } from "es-toolkit"; import { Register } from "lemmy-js-client"; @@ -304,7 +304,7 @@ updateApplicationContextIfNeeded(getCredentialsFromStorage()); function updateApplicationContextIfNeeded( accounts: CredentialStoragePayload | undefined, ) { - const DEFAULT_INSTANCE = "lemmy.world"; + const DEFAULT_INSTANCE = "lemm.ee"; const connectedInstance = (() => { if (!accounts) return DEFAULT_INSTANCE; diff --git a/src/features/auth/login/LearnMore.module.css b/src/features/auth/login/LearnMore.module.css new file mode 100644 index 0000000000..b24b24ef91 --- /dev/null +++ b/src/features/auth/login/LearnMore.module.css @@ -0,0 +1,25 @@ +.content { + line-height: 1.4; +} + +.list { + li:not(:last-of-type) { + margin-bottom: 1rem; + } +} + +.compare { + display: flex; + text-align: center; + align-items: center; + justify-content: space-around; + + line-height: 1.5; + + margin: 1rem 0; + + > div { + display: flex; + flex-direction: column; + } +} diff --git a/src/features/auth/login/LearnMore.tsx b/src/features/auth/login/LearnMore.tsx index d4c5b9aeb3..66e859a103 100644 --- a/src/features/auth/login/LearnMore.tsx +++ b/src/features/auth/login/LearnMore.tsx @@ -5,35 +5,11 @@ import { IonText, IonToolbar, } from "@ionic/react"; -import { styled } from "@linaria/react"; import AppHeader from "#/features/shared/AppHeader"; +import { cx } from "#/helpers/css"; -const HelpIonContent = styled(IonContent)` - line-height: 1.4; -`; - -const List = styled.ul` - li:not(:last-of-type) { - margin-bottom: 1rem; - } -`; - -const Compare = styled.div` - display: flex; - text-align: center; - align-items: center; - justify-content: space-around; - - line-height: 1.5; - - margin: 1rem 0; - - > div { - display: flex; - flex-direction: column; - } -`; +import styles from "./LearnMore.module.css"; export default function LearnMore() { return ( @@ -45,7 +21,7 @@ export default function LearnMore() { - +

How does this app work?

Lemmy is a decentralized network of communities where @@ -69,7 +45,7 @@ export default function LearnMore() { .

- +
  • Lemmy @@ -79,7 +55,7 @@ export default function LearnMore() { E-Mail , has a common set of features. - +
    Create posts @@ -97,7 +73,7 @@ export default function LearnMore() { Receive mail
    - +
  • Your{" "} @@ -109,7 +85,7 @@ export default function LearnMore() { E-Mail account : it’s hosted by a particular provider. - +
    lemmy.world @@ -127,7 +103,7 @@ export default function LearnMore() { hotmail.com
    - +
    Like{" "} @@ -150,8 +126,8 @@ export default function LearnMore() { .
  • - - +
+
); } diff --git a/src/features/auth/login/LoginModal.module.css b/src/features/auth/login/LoginModal.module.css new file mode 100644 index 0000000000..0465911563 --- /dev/null +++ b/src/features/auth/login/LoginModal.module.css @@ -0,0 +1,7 @@ +.modal { + --max-width: 500px; + + @media (min-width: 600px) { + --max-height: 750px; + } +} diff --git a/src/features/auth/login/LoginModal.tsx b/src/features/auth/login/LoginModal.tsx index 52e7975662..c062726625 100644 --- a/src/features/auth/login/LoginModal.tsx +++ b/src/features/auth/login/LoginModal.tsx @@ -1,16 +1,8 @@ -import { styled } from "@linaria/react"; - import { DynamicDismissableModal } from "#/features/shared/DynamicDismissableModal"; import LoginNav from "./LoginNav"; -const StyledDynamicDismissableModal = styled(DynamicDismissableModal)` - --max-width: 500px; - - @media (min-width: 600px) { - --max-height: 750px; - } -`; +import styles from "./LoginModal.module.css"; interface LoginModalProps { isOpen: boolean; @@ -22,8 +14,12 @@ export default function LoginModal({ setIsOpen, }: Readonly) { return ( - + - + ); } diff --git a/src/features/auth/login/LoginNav.tsx b/src/features/auth/login/LoginNav.tsx index a545a6bd7e..97d90aa085 100644 --- a/src/features/auth/login/LoginNav.tsx +++ b/src/features/auth/login/LoginNav.tsx @@ -1,31 +1,11 @@ import { IonNavCustomEvent } from "@ionic/core"; -import { IonNav, IonSpinner } from "@ionic/react"; -import { styled } from "@linaria/react"; +import { IonNav } from "@ionic/react"; import { useContext, useState } from "react"; import { DynamicDismissableModalContext } from "#/features/shared/DynamicDismissableModal"; import Welcome from "./welcome/Welcome"; -export const Spinner = styled(IonSpinner)` - width: 1.5rem; -`; - -export const Centered = styled.div` - display: flex; - align-items: center; - gap: 0.5rem; - line-height: 1; - - .ios & { - justify-content: center; - } - - ion-spinner { - flex-shrink: 0; - } -`; - function blurDocument() { (document.activeElement as HTMLElement)?.blur(); } diff --git a/src/features/auth/login/data/servers.ts b/src/features/auth/login/data/servers.ts index 2fe37fe4eb..abf9dada31 100644 --- a/src/features/auth/login/data/servers.ts +++ b/src/features/auth/login/data/servers.ts @@ -39,18 +39,14 @@ export const SERVERS_BY_CATEGORY = { "feddit.nu", "feddit.cl", "lemmy.pt", - "dmv.social", "suppo.fi", "yall.theatl.social", - "feddit.ro", "baraza.africa", "tucson.social", "real.lemmy.fan", "lemy.nl", "lemmy.eus", "dubvee.org", - "lemmy.id", - "lemmy.bleh.au", "feddit.uk", ], games: [ @@ -60,7 +56,6 @@ export const SERVERS_BY_CATEGORY = { "dormi.zone", "eviltoast.org", "preserve.games", - "derpzilla.net", ], tech: [ "futurology.today", @@ -70,10 +65,8 @@ export const SERVERS_BY_CATEGORY = { "eviltoast.org", "lemmy.kde.social", "lemmy.sdf.org", - "lemmyhub.com", "linux.community", "infosec.pub", - "derpzilla.net", "lemdro.id", ], niche: [ @@ -85,14 +78,12 @@ export const SERVERS_BY_CATEGORY = { "lemmy.radio", "futurology.today", "adultswim.fan", - "lemmy.radio", - "psychedelia.ink", "ani.social", "vegantheoryclub.org", "lemmy.vg", ], activism: ["rblind.com", "badatbeing.social", "slrpnk.net"], - lgbt: ["femboys.bar", "lemmy.blahaj.zone"], + lgbt: ["lemmy.blahaj.zone"], academia: ["mander.xyz", "literature.cafe", "futurology.today"], furry: ["pawb.social", "yiffit.net"], }; diff --git a/src/features/auth/login/join/Captcha.module.css b/src/features/auth/login/join/Captcha.module.css new file mode 100644 index 0000000000..bd80f9d1a8 --- /dev/null +++ b/src/features/auth/login/join/Captcha.module.css @@ -0,0 +1,57 @@ +.list { + position: relative; + + height: 100px; +} + +.item { + --background: none; +} + +.img { + margin: 0 auto; + height: 100px; +} + +.bg { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + filter: blur(20px); +} + +.actions { + position: absolute; + top: 0; + right: 0; + font-size: 1.3rem; + padding: 12px; + + z-index: 1; + + display: flex; + gap: 12px; + + background: rgba(0, 0, 0, 0.4); + border-bottom-left-radius: 12px; +} + +.spinnerContainer { + position: absolute; + inset: 0; + background: rgba(0, 0, 0, 0.3); + + z-index: 1; +} + +.spinner { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} + +.button { + composes: plainButton from "#/features/shared/shared.module.css"; +} diff --git a/src/features/auth/login/join/Captcha.tsx b/src/features/auth/login/join/Captcha.tsx index e24104b36c..9b18e37c05 100644 --- a/src/features/auth/login/join/Captcha.tsx +++ b/src/features/auth/login/join/Captcha.tsx @@ -6,68 +6,14 @@ import { IonSpinner, IonText, } from "@ionic/react"; -import { styled } from "@linaria/react"; import { refresh, volumeHigh, volumeHighOutline } from "ionicons/icons"; import { GetCaptchaResponse, Register } from "lemmy-js-client"; import { useCallback, useEffect, useImperativeHandle, useState } from "react"; -import { PlainButton } from "#/features/shared/PlainButton"; import { b64ToBlob } from "#/helpers/blob"; import { getClient } from "#/services/lemmy"; -const CaptchaIonList = styled(IonList)` - position: relative; - - height: 100px; -`; - -const CaptchaIonItem = styled(IonItem)` - --background: none; -`; - -const CaptchaImg = styled.img` - margin: 0 auto; - height: 100px; -`; - -const CaptchaBg = styled.img` - position: absolute; - inset: 0; - width: 100%; - height: 100%; - filter: blur(20px); -`; - -const Actions = styled.div` - position: absolute; - top: 0; - right: 0; - font-size: 1.3rem; - padding: 12px; - - z-index: 1; - - display: flex; - gap: 12px; - - background: rgba(0, 0, 0, 0.4); - border-bottom-left-radius: 12px; -`; - -const SpinnerContainer = styled.div` - position: absolute; - inset: 0; - background: rgba(0, 0, 0, 0.3); - - z-index: 1; -`; - -const Spinner = styled(IonSpinner)` - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); -`; +import styles from "./Captcha.module.css"; export interface CaptchaHandle { getResult: () => Pick; @@ -145,21 +91,26 @@ export default function Captcha({ url, ref }: CaptchaProps) { return ( <> - + {captcha?.ok && ( <> - - - + + Captcha image - + )} - - + + + {loading && ( - - - +
+ +
)} -
+ - + {url} diff --git a/src/features/auth/login/login/LoginAvatarImg.module.css b/src/features/auth/login/login/LoginAvatarImg.module.css new file mode 100644 index 0000000000..bd558043be --- /dev/null +++ b/src/features/auth/login/login/LoginAvatarImg.module.css @@ -0,0 +1,7 @@ +.img { + object-fit: contain; +} + +.loading { + background-color: rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.07); +} diff --git a/src/features/auth/login/login/LoginAvatarImg.tsx b/src/features/auth/login/login/LoginAvatarImg.tsx new file mode 100644 index 0000000000..8c360d035d --- /dev/null +++ b/src/features/auth/login/login/LoginAvatarImg.tsx @@ -0,0 +1,30 @@ +import { useState } from "react"; + +import { cx } from "#/helpers/css"; +import { getImageSrc } from "#/services/lemmy"; + +import lemmyLogo from "../lemmyLogo.svg"; + +import styles from "./LoginAvatarImg.module.css"; + +interface LoginAvatarImgProps { + src: string | undefined; +} + +export default function LoginAvatarImg({ src }: LoginAvatarImgProps) { + const [loaded, setLoaded] = useState(false); + + return ( + setLoaded(true)} + /> + ); +} diff --git a/src/features/auth/login/login/PickLoginServer.module.css b/src/features/auth/login/login/PickLoginServer.module.css new file mode 100644 index 0000000000..8eebb28a13 --- /dev/null +++ b/src/features/auth/login/login/PickLoginServer.module.css @@ -0,0 +1,12 @@ +.container { + height: 100%; + + display: flex; + flex-direction: column; +} + +.list { + flex: 1; + + --ion-item-background: none; +} diff --git a/src/features/auth/login/login/PickLoginServer.tsx b/src/features/auth/login/login/PickLoginServer.tsx index 977c52efe5..70c0795610 100644 --- a/src/features/auth/login/login/PickLoginServer.tsx +++ b/src/features/auth/login/login/PickLoginServer.tsx @@ -11,7 +11,6 @@ import { IonTitle, IonToolbar, } from "@ionic/react"; -import { styled } from "@linaria/react"; import { uniq } from "es-toolkit"; import { GetSiteResponse } from "lemmy-js-client"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; @@ -20,8 +19,8 @@ import { VList, VListHandle } from "virtua"; import { LOGIN_SERVERS } from "#/features/auth/login/data/servers"; import AppHeader from "#/features/shared/AppHeader"; import { - MINIMUM_LEMMY_VERSION, isMinimumSupportedLemmyVersion, + MINIMUM_LEMMY_VERSION, } from "#/helpers/lemmy"; import { isValidHostname, stripProtocol } from "#/helpers/url"; import useAppToast from "#/helpers/useAppToast"; @@ -30,18 +29,7 @@ import { getClient } from "#/services/lemmy"; import Login from "./Login"; -const Container = styled.div` - height: 100%; - - display: flex; - flex-direction: column; -`; - -const StyledIonList = styled(IonList)` - flex: 1; - - --ion-item-background: none; -`; +import styles from "./PickLoginServer.module.css"; export default function PickLoginServer() { const presentToast = useAppToast(); @@ -155,7 +143,7 @@ export default function PickLoginServer() { - +
Pick the server you created your account on @@ -206,7 +194,7 @@ export default function PickLoginServer() { }} /> - + - - + +
); diff --git a/src/features/auth/login/pickJoinServer/Filters.module.css b/src/features/auth/login/pickJoinServer/Filters.module.css new file mode 100644 index 0000000000..3c36a4fb1a --- /dev/null +++ b/src/features/auth/login/pickJoinServer/Filters.module.css @@ -0,0 +1,21 @@ +.container { + display: flex; + + overflow: auto; + + padding-left: 8px; + padding-right: 8px; + + > * { + flex-shrink: 0; + } + + &::-webkit-scrollbar { + display: none; + } +} + +.selectedChip { + --background: var(--ion-color-primary); + --color: var(--ion-color-primary-contrast); +} diff --git a/src/features/auth/login/pickJoinServer/Filters.tsx b/src/features/auth/login/pickJoinServer/Filters.tsx index ca3d1092cb..01dc58c994 100644 --- a/src/features/auth/login/pickJoinServer/Filters.tsx +++ b/src/features/auth/login/pickJoinServer/Filters.tsx @@ -1,33 +1,12 @@ import { IonChip } from "@ionic/react"; -import { css } from "@linaria/core"; -import { styled } from "@linaria/react"; import { - SERVERS_BY_CATEGORY, ServerCategory, + SERVERS_BY_CATEGORY, } from "#/features/auth/login/data/servers"; -const Container = styled.div` - display: flex; - - overflow: auto; - - padding-left: 8px; - padding-right: 8px; - - > * { - flex-shrink: 0; - } - - &::-webkit-scrollbar { - display: none; - } -`; +import styles from "./Filters.module.css"; -const selectedChipStyles = css` - --background: var(--ion-color-primary); - --color: var(--ion-color-primary-contrast); -`; const CATEGORIES = Object.keys(SERVERS_BY_CATEGORY) as ServerCategory[]; interface FiltersProps { @@ -42,7 +21,8 @@ export default function Filters({ setCategory, }: FiltersProps) { return ( - { // Prevent page swipes e.stopPropagation(); @@ -52,7 +32,7 @@ export default function Filters({ {hasRecommended && ( setCategory("recommended")} @@ -62,7 +42,7 @@ export default function Filters({ )} {CATEGORIES.map((c) => ( setCategory(c)} @@ -70,6 +50,6 @@ export default function Filters({ {c} ))} - +
); } diff --git a/src/features/auth/login/pickJoinServer/PickJoinServer.module.css b/src/features/auth/login/pickJoinServer/PickJoinServer.module.css new file mode 100644 index 0000000000..6793f54a46 --- /dev/null +++ b/src/features/auth/login/pickJoinServer/PickJoinServer.module.css @@ -0,0 +1,46 @@ +.spacing { + margin: 2.5rem 0; + width: 100%; +} + +.empty { + composes: spacing; + + color: var(--ion-color-medium); + text-align: center; +} + +.serverThumbnail { + --size: 32px; + --border-radius: 6px; + margin: 16px 16px 16px 0; + pointer-events: none; +} + +.serverItem { + --background: none; +} + +.serverImg { + object-fit: contain; +} + +.nextMessage { + font-size: 0.8em; +} + +.searchbar { + padding-bottom: 5px !important; + min-height: 40px !important; +} + +.filtersToolbar { + --ion-safe-area-left: -8px; + --ion-safe-area-right: -8px; + --padding-start: 0; + --padding-end: 0; +} + +.optionsButton { + font-size: 16px; +} diff --git a/src/features/auth/login/pickJoinServer/PickJoinServer.tsx b/src/features/auth/login/pickJoinServer/PickJoinServer.tsx index 0a16846f52..6a722134e5 100644 --- a/src/features/auth/login/pickJoinServer/PickJoinServer.tsx +++ b/src/features/auth/login/pickJoinServer/PickJoinServer.tsx @@ -17,8 +17,6 @@ import { IonToolbar, useIonActionSheet, } from "@ionic/react"; -import { css } from "@linaria/core"; -import { styled } from "@linaria/react"; import { compact, uniqBy } from "es-toolkit"; import { ellipsisHorizontalCircleOutline, @@ -36,8 +34,8 @@ import { import { VList } from "virtua"; import { - SERVERS_BY_CATEGORY, ServerCategory, + SERVERS_BY_CATEGORY, } from "#/features/auth/login/data/servers"; import Login from "#/features/auth/login/login/Login"; import AppHeader from "#/features/shared/AppHeader"; @@ -58,52 +56,7 @@ import Filters from "./Filters"; import { getInstances } from "./pickJoinServerSlice"; import useStartJoinFlow from "./useStartJoinFlow"; -const spacing = ` - margin: 2.5rem 0; - width: 100%; -`; - -const SpacedSpinner = styled(IonSpinner)` - ${spacing} -`; - -const Empty = styled.div` - ${spacing} - - color: var(--ion-color-medium); - text-align: center; -`; - -const ServerThumbnail = styled(IonThumbnail)` - --size: 32px; - --border-radius: 6px; - margin: 16px 16px 16px 0; - pointer-events: none; -`; - -const ServerItem = styled(IonItem)` - --background: none; -`; - -const NextMessage = styled.p` - font-size: 0.8em; -`; - -const ServerImg = styled.img` - object-fit: contain; -`; - -const StyledIonSearchbar = styled(IonSearchbar)` - padding-bottom: 5px !important; - min-height: 40px !important; -`; - -const FiltersToolbar = styled(IonToolbar)` - --ion-safe-area-left: -8px; - --ion-safe-area-right: -8px; - --padding-start: 0; - --padding-end: 0; -`; +import styles from "./PickJoinServer.module.css"; export default function PickJoinServer() { const [presentActionSheet] = useIonActionSheet(); @@ -295,28 +248,30 @@ export default function PickJoinServer() { const { url, icon, description } = allInstances[i]!; return ( - - - + + - +

{url}

{description}

-
+
); }} ); } - if (loading || loadingInstances) return ; + if (loading || loadingInstances) + return ; - return No results; + return
No results
; })(); return ( @@ -331,9 +286,7 @@ export default function PickJoinServer() { - - + setSearch(e.detail.value || "")} onKeyDown={blurOnEnter} @@ -359,7 +313,7 @@ export default function PickJoinServer() { category={category} setCategory={setCategory} /> - + : "Next"} - +

We‘ll pick a server for you if you don‘t make a selection. - +

diff --git a/src/features/auth/login/pickJoinServer/pickJoinServerSlice.ts b/src/features/auth/login/pickJoinServer/pickJoinServerSlice.ts index 8578cd25da..0b85dbd62c 100644 --- a/src/features/auth/login/pickJoinServer/pickJoinServerSlice.ts +++ b/src/features/auth/login/pickJoinServer/pickJoinServerSlice.ts @@ -1,4 +1,4 @@ -import { PayloadAction, createSlice } from "@reduxjs/toolkit"; +import { createSlice, PayloadAction } from "@reduxjs/toolkit"; import { WHITELISTED_SERVERS } from "#/features/auth/login/data/servers"; import { buildPrioritizeAndSortFn } from "#/helpers/array"; diff --git a/src/features/auth/login/pickJoinServer/useStartJoinFlow.tsx b/src/features/auth/login/pickJoinServer/useStartJoinFlow.tsx index 0a15852e2f..24f3815cf6 100644 --- a/src/features/auth/login/pickJoinServer/useStartJoinFlow.tsx +++ b/src/features/auth/login/pickJoinServer/useStartJoinFlow.tsx @@ -2,8 +2,8 @@ import { useIonAlert } from "@ionic/react"; import { GetSiteResponse } from "lemmy-js-client"; import { MutableRefObject } from "react"; -import Legal from "#/features/auth/login/join/Legal"; import { requestJoinSiteData } from "#/features/auth/login/join/joinSlice"; +import Legal from "#/features/auth/login/join/Legal"; import useAppToast from "#/helpers/useAppToast"; import { useAppDispatch } from "#/store"; diff --git a/src/features/auth/login/welcome/AndroidClose.module.css b/src/features/auth/login/welcome/AndroidClose.module.css new file mode 100644 index 0000000000..47728e7e60 --- /dev/null +++ b/src/features/auth/login/welcome/AndroidClose.module.css @@ -0,0 +1,5 @@ +.androidIonButtons { + :global(.ios) & { + display: none; + } +} diff --git a/src/features/auth/login/welcome/AndroidClose.tsx b/src/features/auth/login/welcome/AndroidClose.tsx index 5f637cb9fd..fed6c70d52 100644 --- a/src/features/auth/login/welcome/AndroidClose.tsx +++ b/src/features/auth/login/welcome/AndroidClose.tsx @@ -1,24 +1,19 @@ import { IonButton, IonButtons, IonIcon } from "@ionic/react"; -import { styled } from "@linaria/react"; import { arrowBackSharp } from "ionicons/icons"; import { useContext } from "react"; import { DynamicDismissableModalContext } from "#/features/shared/DynamicDismissableModal"; -const AndroidIonButtons = styled(IonButtons)` - .ios & { - display: none; - } -`; +import styles from "./AndroidClose.module.css"; export default function AndroidClose() { const { dismiss } = useContext(DynamicDismissableModalContext); return ( - + - + ); } diff --git a/src/features/auth/login/welcome/Buttons.module.css b/src/features/auth/login/welcome/Buttons.module.css new file mode 100644 index 0000000000..6f47aac604 --- /dev/null +++ b/src/features/auth/login/welcome/Buttons.module.css @@ -0,0 +1,41 @@ +.topSpacer { + flex: 10; +} + +.bottomSpacer { + flex: 7; +} + +.container { + display: flex; + flex-direction: column; + + gap: 0.5rem; + margin: 2rem; + + margin-top: auto; +} + +.or { + font-size: 0.8em; + position: relative; + + display: flex; + gap: 6px; + + margin: 6px 0 -6px; + + hr { + flex: 1; + background: var(--ion-color-medium); + opacity: 0.6; + } +} + +.buttonLine { + display: flex; + + > * { + flex: 1; + } +} diff --git a/src/features/auth/login/welcome/Buttons.tsx b/src/features/auth/login/welcome/Buttons.tsx index 2205c5dd45..70e76c44ae 100644 --- a/src/features/auth/login/welcome/Buttons.tsx +++ b/src/features/auth/login/welcome/Buttons.tsx @@ -1,5 +1,4 @@ import { IonButton, IonNavLink, IonSpinner } from "@ionic/react"; -import { styled } from "@linaria/react"; import { useRef } from "react"; import PickLoginServer from "#/features/auth/login/login/PickLoginServer"; @@ -9,47 +8,7 @@ import { useAppSelector } from "#/store"; import LearnMore from "../LearnMore"; -const TopSpacer = styled.div` - flex: 10; -`; - -const BottomSpacer = styled.div` - flex: 7; -`; - -const Container = styled.div` - display: flex; - flex-direction: column; - - gap: 0.5rem; - margin: 2rem; - - margin-top: auto; -`; - -const Or = styled.div` - font-size: 0.8em; - position: relative; - - display: flex; - gap: 6px; - - margin: 6px 0 -6px; - - hr { - flex: 1; - background: var(--ion-color-medium); - opacity: 0.6; - } -`; - -const ButtonLine = styled.div` - display: flex; - - > * { - flex: 1; - } -`; +import styles from "./Buttons.module.css"; export default function Buttons() { const loadingJoin = useAppSelector((state) => state.join.loading); @@ -61,8 +20,8 @@ export default function Buttons() { return ( <> - - +
+
startJoinFlow(connectedInstance)} @@ -75,13 +34,13 @@ export default function Buttons() { Pick another server - +

OR
- +
- +
}> Learn More @@ -92,9 +51,9 @@ export default function Buttons() { Log In - - - +
+
+
); } diff --git a/src/features/auth/login/welcome/Welcome.module.css b/src/features/auth/login/welcome/Welcome.module.css new file mode 100644 index 0000000000..72e7fbe6db --- /dev/null +++ b/src/features/auth/login/welcome/Welcome.module.css @@ -0,0 +1,29 @@ +.content { + &::part(scroll) { + z-index: 1; + + display: flex; + flex-direction: column; + } + + --background: linear-gradient(0deg, #bfd5ff, #e3edff 33%, #ffff); + + :global(.ion-palette-dark) & { + --background: linear-gradient(0deg, #001233ff, #000a1c 33%, #0000); + } +} + +.baseSvg { + opacity: 0.4; + margin: 0 -2rem; + position: absolute; + bottom: 0; + + pointer-events: none; + + filter: brightness(2.7); + + :global(.ion-palette-dark) & { + filter: none; + } +} diff --git a/src/features/auth/login/welcome/Welcome.tsx b/src/features/auth/login/welcome/Welcome.tsx index 68c092a296..8c2b10d587 100644 --- a/src/features/auth/login/welcome/Welcome.tsx +++ b/src/features/auth/login/welcome/Welcome.tsx @@ -1,45 +1,12 @@ import { IonContent, IonTitle, IonToolbar } from "@ionic/react"; -import { styled } from "@linaria/react"; import AppHeader from "#/features/shared/AppHeader"; import AndroidClose from "./AndroidClose"; -import Buttons from "./Buttons"; import BaseSvg from "./assets/base.svg?react"; +import Buttons from "./Buttons"; -// slot attribute not allowed for some reason?? -// eslint-disable-next-line @typescript-eslint/no-explicit-any -type AnyComponent = any; - -const StyledIonContent = styled(IonContent)` - &::part(scroll) { - z-index: 1; - - display: flex; - flex-direction: column; - } - - --background: linear-gradient(0deg, #bfd5ff, #e3edff 33%, #ffff); - - .ion-palette-dark & { - --background: linear-gradient(0deg, #001233ff, #000a1c 33%, #0000); - } -`; - -const StyledBaseSvg = styled(BaseSvg)` - opacity: 0.4; - margin: 0 -2rem; - position: absolute; - bottom: 0; - - pointer-events: none; - - filter: brightness(2.7); - - .ion-palette-dark & { - filter: none; - } -` as AnyComponent; +import styles from "./Welcome.module.css"; export default function Welcome() { return ( @@ -51,17 +18,17 @@ export default function Welcome() { - + Welcome. - + - + ); } diff --git a/src/features/auth/siteSlice.ts b/src/features/auth/siteSlice.ts index 1e1f789457..e2b5bef358 100644 --- a/src/features/auth/siteSlice.ts +++ b/src/features/auth/siteSlice.ts @@ -1,4 +1,4 @@ -import { PayloadAction, createSelector, createSlice } from "@reduxjs/toolkit"; +import { createSelector, createSlice, PayloadAction } from "@reduxjs/toolkit"; import { GetSiteResponse } from "lemmy-js-client"; import { getRemoteHandle } from "#/helpers/lemmy"; diff --git a/src/features/comment/Comment.module.css b/src/features/comment/Comment.module.css new file mode 100644 index 0000000000..fb64c0944d --- /dev/null +++ b/src/features/comment/Comment.module.css @@ -0,0 +1,22 @@ +.commentItem { + scroll-margin-bottom: 35vh; + + --padding-start: 0; + --inner-padding-end: 0; + --border-style: none; + --min-height: 0; +} + +.content { + padding-top: 0.35em; + + display: flex; + flex-direction: column; + gap: 1em; + + @media (hover: none) { + padding-top: 0.45em; + } + + line-height: 1.25; +} diff --git a/src/features/comment/Comment.tsx b/src/features/comment/Comment.tsx index 5663f0d7d6..b0d19eec50 100644 --- a/src/features/comment/Comment.tsx +++ b/src/features/comment/Comment.tsx @@ -1,6 +1,4 @@ import { IonItem } from "@ionic/react"; -import { cx } from "@linaria/core"; -import { styled } from "@linaria/react"; import { CommentView } from "lemmy-js-client"; import React, { MouseEvent, useRef } from "react"; import AnimateHeight from "react-animate-height"; @@ -11,6 +9,7 @@ import { ModeratableItemBannerOutlet } from "#/features/moderation/ModeratableIt import ModeratableItem from "#/features/moderation/ModeratableItem"; import useCanModerate from "#/features/moderation/useCanModerate"; import SlidingNestedCommentVote from "#/features/shared/sliding/SlidingNestedCommentVote"; +import { cx } from "#/helpers/css"; import { isTouchDevice } from "#/helpers/device"; import { preventOnClickNavigationBug, @@ -25,28 +24,7 @@ import CommentHeader, { isStubComment } from "./CommentHeader"; import CommentContainer from "./elements/CommentContainer"; import { PositionedContainer } from "./elements/PositionedContainer"; -export const CustomIonItem = styled(IonItem)` - scroll-margin-bottom: 35vh; - - --padding-start: 0; - --inner-padding-end: 0; - --border-style: none; - --min-height: 0; -`; - -const Content = styled.div` - padding-top: 0.35em; - - display: flex; - flex-direction: column; - gap: 1em; - - @media (hover: none) { - padding-top: 0.45em; - } - - line-height: 1.25; -`; +import styles from "./Comment.module.css"; interface CommentProps { comment: CommentView; @@ -116,9 +94,10 @@ export default function Comment({ rootIndex={rootIndex} collapsed={!!collapsed} > - {!stub || context ? ( - { if (!(e.target instanceof HTMLElement)) return; if (e.target.nodeName === "A") e.stopPropagation(); @@ -167,10 +147,11 @@ export default function Comment({ item={comment} showTouchFriendlyLinks={!context} mdClassName="collapse-md-margins" + canModerate={canModerate} /> )} {context} - +
) : undefined}
@@ -178,7 +159,7 @@ export default function Comment({ - + ); } diff --git a/src/features/comment/CommentContent.tsx b/src/features/comment/CommentContent.tsx index d7dd45a950..de9758b8e7 100644 --- a/src/features/comment/CommentContent.tsx +++ b/src/features/comment/CommentContent.tsx @@ -1,34 +1,65 @@ +import { IonText } from "@ionic/react"; import { Comment, Post } from "lemmy-js-client"; +import { useEffect } from "react"; -import { useAppSelector } from "#/store"; +import { ModeratorRole } from "#/features/moderation/useCanModerate"; +import { useAppDispatch, useAppSelector } from "#/store"; import CommentLinks from "./CommentLinks"; import CommentMarkdown from "./CommentMarkdown"; +import { getCommentContent, LOADING_CONTENT } from "./commentSlice"; interface CommentContentProps { item: Comment | Post; showTouchFriendlyLinks?: boolean; mdClassName?: string; + canModerate?: ModeratorRole | undefined; } export default function CommentContent({ item, showTouchFriendlyLinks = true, mdClassName, + canModerate, }: CommentContentProps) { + const dispatch = useAppDispatch(); const touchFriendlyLinks = useAppSelector( (state) => state.settings.general.comments.touchFriendlyLinks, ); + const removedCommentContent = useAppSelector( + (state) => state.comment.commentContentById[item.id], + ); + + const content = (() => { + // is post + if (!("content" in item)) return item.body ?? item.name; + + if (item.content === "") { + return removedCommentContent ?? ""; + } + + return item.content; + })(); + + useEffect(() => { + if (!item.removed) return; + if (!("content" in item)) return; // only comments + if (content) return; + if (!canModerate) return; + + dispatch(getCommentContent(item.id)); + }, [item, content, dispatch, canModerate]); + + if (content === LOADING_CONTENT) + return Loading comment...; return ( <> - {"content" in item ? item.content : (item.body ?? item.name)} + {content} {showTouchFriendlyLinks && touchFriendlyLinks && ( - + )} ); diff --git a/src/features/comment/CommentEllipsis.module.css b/src/features/comment/CommentEllipsis.module.css new file mode 100644 index 0000000000..047c2988a7 --- /dev/null +++ b/src/features/comment/CommentEllipsis.module.css @@ -0,0 +1,3 @@ +.icon { + font-size: 1.2em; +} diff --git a/src/features/comment/CommentEllipsis.tsx b/src/features/comment/CommentEllipsis.tsx index c19bd25257..2e67f021ff 100644 --- a/src/features/comment/CommentEllipsis.tsx +++ b/src/features/comment/CommentEllipsis.tsx @@ -1,5 +1,4 @@ import { IonIcon, IonLoading } from "@ionic/react"; -import { styled } from "@linaria/react"; import { ellipsisHorizontal } from "ionicons/icons"; import { useContext, useImperativeHandle } from "react"; @@ -7,9 +6,7 @@ import { ShareImageContext } from "#/features/share/asImage/ShareAsImage"; import useCommentActions, { CommentActionsProps } from "./useCommentActions"; -const StyledIonIcon = styled(IonIcon)` - font-size: 1.2em; -`; +import styles from "./CommentEllipsis.module.css"; export type CommentEllipsisHandle = Pick< ReturnType, @@ -40,7 +37,8 @@ export default function CommentEllipsis({ return ( <> - { present(); diff --git a/src/features/comment/CommentHeader.module.css b/src/features/comment/CommentHeader.module.css new file mode 100644 index 0000000000..6b556ffb7b --- /dev/null +++ b/src/features/comment/CommentHeader.module.css @@ -0,0 +1,53 @@ +.header { + display: flex; + align-items: center; + + font-size: 0.875em; + + gap: 0.5em; + + color: var(--ion-color-medium2); +} + +.personLink { + &.personLink { + color: var(--ion-text-color); + } + + min-width: 0; + overflow: hidden; +} + +.commentVote { + /* Increase tap target */ + padding: 6px 3px; + margin: -6px -3px; +} + +.collapsedIcon { + font-size: 1.2em; +} + +.amountCollapsed { + font-size: 0.875em; + padding: 2px 8px; + margin: -4px 0; + border-radius: 16px; + color: var(--ion-color-medium); + background: var(--lightroom-bg); +} + +.deletedLabel { + font-style: italic; + color: var(--ion-color-medium); + + min-width: 0; + overflow: hidden; +} + +.spacer { + flex: 1; + min-width: 0; + overflow: hidden; + display: flex; +} diff --git a/src/features/comment/CommentHeader.tsx b/src/features/comment/CommentHeader.tsx index 53e2335d6e..bafbba0d69 100644 --- a/src/features/comment/CommentHeader.tsx +++ b/src/features/comment/CommentHeader.tsx @@ -1,17 +1,16 @@ import { IonIcon } from "@ionic/react"; -import { styled } from "@linaria/react"; import { chevronDownOutline } from "ionicons/icons"; import { Comment, CommentView } from "lemmy-js-client"; import { RefObject } from "react"; import Ago from "#/features/labels/Ago"; import Edited from "#/features/labels/Edited"; -import Vote from "#/features/labels/Vote"; import PersonLink from "#/features/labels/links/PersonLink"; +import Vote from "#/features/labels/Vote"; import ModqueueItemActions from "#/features/moderation/ModqueueItemActions"; import { ModeratorRole } from "#/features/moderation/useCanModerate"; import { ActionButton } from "#/features/post/actions/ActionButton"; -import { ActionsContainer } from "#/features/post/inFeed/compact/CompactPost"; +import ActionsContainer from "#/features/post/actions/ActionsContainer"; import UserScore from "#/features/tags/UserScore"; import UserTag from "#/features/tags/UserTag"; import { useInModqueue } from "#/routes/pages/shared/ModqueuePage"; @@ -20,59 +19,7 @@ import { useAppSelector } from "#/store"; import CommentEllipsis, { CommentEllipsisHandle } from "./CommentEllipsis"; import ModActions from "./ModActions"; -const Header = styled.div` - display: flex; - align-items: center; - - font-size: 0.875em; - - gap: 0.5em; - - color: var(--ion-color-medium2); -`; - -const StyledPersonLink = styled(PersonLink)` - && { - color: var(--ion-text-color); - } - - min-width: 0; - overflow: hidden; -`; - -const CommentVote = styled(Vote)` - // Increase tap target - padding: 6px 3px; - margin: -6px -3px; -`; - -const CollapsedIcon = styled(IonIcon)` - font-size: 1.2em; -`; - -const AmountCollapsed = styled.div` - font-size: 0.875em; - padding: 2px 8px; - margin: -4px 0; - border-radius: 16px; - color: var(--ion-color-medium); - background: var(--lightroom-bg); -`; - -const DeletedLabel = styled.div` - font-style: italic; - color: var(--ion-color-medium); - - min-width: 0; - overflow: hidden; -`; - -const Spacer = styled.div` - flex: 1; - min-width: 0; - overflow: hidden; - display: flex; -`; +import styles from "./CommentHeader.module.css"; interface CommentHeaderProps { canModerate: ModeratorRole | undefined; @@ -103,7 +50,7 @@ export default function CommentHeader({ ); function renderActions() { - if (inModqueue) return ; + if (inModqueue) return ; if (canModerate) return ; @@ -127,11 +74,14 @@ export default function CommentHeader({ {collapsed && ( <> - +
{commentView.counts.child_count + (showCollapsedComment || stub ? 0 : 1)} - - +
+ )} @@ -143,7 +93,7 @@ export default function CommentHeader({ case StubType.Deleted: return ( <> - +
{" "} deleted their comment :( - - +
+
{renderAside(comment.updated || comment.published)} ); case StubType.ModRemoved: return ( <> - +
mod removed{" "} 's comment - - +
+
{renderAside(comment.updated || comment.published)} ); default: return ( <> - )} - + - +
{tagsEnabled && } - +
{renderAside(comment.published)} ); } })(); - return
{content}
; + return
{content}
; } const StubType = { diff --git a/src/features/comment/CommentLinks.module.css b/src/features/comment/CommentLinks.module.css new file mode 100644 index 0000000000..37802debe7 --- /dev/null +++ b/src/features/comment/CommentLinks.module.css @@ -0,0 +1,5 @@ +.container { + display: flex; + flex-direction: column; + gap: 12px; +} diff --git a/src/features/comment/CommentLinks.tsx b/src/features/comment/CommentLinks.tsx index d776f42069..b6041272a4 100644 --- a/src/features/comment/CommentLinks.tsx +++ b/src/features/comment/CommentLinks.tsx @@ -1,5 +1,4 @@ import spoiler from "@aeharding/remark-lemmy-spoiler"; -import { styled } from "@linaria/react"; import { uniqBy } from "es-toolkit"; import { Text } from "mdast"; import { defaultUrlTransform } from "react-markdown"; @@ -12,11 +11,7 @@ import customRemarkGfm from "#/features/shared/markdown/customRemarkGfm"; import { buildBaseLemmyUrl } from "#/services/lemmy"; import { useAppSelector } from "#/store"; -const Container = styled.div` - display: flex; - flex-direction: column; - gap: 12px; -`; +import styles from "./CommentLinks.module.css"; export interface LinkData { type: "link" | "image"; @@ -79,5 +74,5 @@ export default function CommentLinks({ markdown }: CommentLinksProps) { if (!links.length) return; - return {links}; + return
{links}
; } diff --git a/src/features/comment/ModActions.tsx b/src/features/comment/ModActions.tsx index f1ac0af407..270f91050a 100644 --- a/src/features/comment/ModActions.tsx +++ b/src/features/comment/ModActions.tsx @@ -2,9 +2,9 @@ import { IonIcon, IonLoading } from "@ionic/react"; import { CommentView } from "lemmy-js-client"; import { - ModeratorRole, getModColor, getModIcon, + ModeratorRole, } from "#/features/moderation/useCanModerate"; import useCommentModActions from "#/features/moderation/useCommentModActions"; import { ActionButton } from "#/features/post/actions/ActionButton"; diff --git a/src/features/comment/commentSlice.ts b/src/features/comment/commentSlice.ts index 71c6b96846..b5a4a883b6 100644 --- a/src/features/comment/commentSlice.ts +++ b/src/features/comment/commentSlice.ts @@ -1,4 +1,4 @@ -import { PayloadAction, createSlice } from "@reduxjs/toolkit"; +import { createAsyncThunk, createSlice, PayloadAction } from "@reduxjs/toolkit"; import { Comment, CommentView } from "lemmy-js-client"; import { clientSelector } from "#/features/auth/authSelectors"; @@ -10,11 +10,14 @@ import { import { getRemoteHandle } from "#/helpers/lemmy"; import { AppDispatch, RootState } from "#/store"; +export const LOADING_CONTENT = -1; + interface CommentState { commentCollapsedById: Record; commentVotesById: Record; commentSavedById: Record; commentById: Record; + commentContentById: Record; } const initialState: CommentState = { @@ -25,6 +28,9 @@ const initialState: CommentState = { * surgical changes received after user edits or deletes comment */ commentById: {}, + + // https://github.com/LemmyNet/lemmy/issues/5230 + commentContentById: {}, }; export const commentSlice = createSlice({ @@ -76,8 +82,23 @@ export const commentSlice = createSlice({ ) => { state.commentSavedById[action.payload.commentId] = action.payload.saved; }, + setCommentContent: (state, action: PayloadAction) => { + state.commentContentById[action.payload.id] = action.payload.content; + }, resetComments: () => initialState, }, + extraReducers: (builder) => { + builder + .addCase(getCommentContent.fulfilled, (state, action) => { + state.commentContentById[action.meta.arg] = action.payload ?? ""; + }) + .addCase(getCommentContent.pending, (state, action) => { + state.commentContentById[action.meta.arg] = LOADING_CONTENT; + }) + .addCase(getCommentContent.rejected, (state, action) => { + state.commentContentById[action.meta.arg] = ""; + }); + }, }); // Action creators are generated for each case reducer function @@ -87,6 +108,7 @@ export const { updateCommentVote, updateCommentSaved, resetComments, + setCommentContent, } = commentSlice.actions; export default commentSlice.reducer; @@ -172,16 +194,17 @@ export const editComment = }; export const modRemoveComment = - (commentId: number, removed: boolean, reason?: string) => + (comment: Comment, removed: boolean, reason?: string) => async (dispatch: AppDispatch, getState: () => RootState) => { const response = await clientSelector(getState())?.removeComment({ - comment_id: commentId, + comment_id: comment.id, removed, reason, }); + dispatch(setCommentContent(comment)); dispatch(mutatedComment(response.comment_view)); - await dispatch(resolveCommentReport(commentId)); + await dispatch(resolveCommentReport(comment.id)); }; export const modNukeCommentChain = @@ -232,3 +255,25 @@ export const receivedComments = fetchTagsForHandles(comments.map((c) => getRemoteHandle(c.creator))), ); }; + +export const getCommentContent = createAsyncThunk( + "comment/getCommentContent", + async (commentId: number, thunkAPI) => { + const rootState = thunkAPI.getState() as RootState; + const client = clientSelector(rootState); + + const log = await client.getModlog({ comment_id: commentId }); + + return log.removed_comments[0]?.comment.content; + }, + { + condition: (commentId, { getState }) => { + const state = getState() as RootState; + + if (state.comment.commentContentById[commentId] === undefined) + return true; + + return false; + }, + }, +); diff --git a/src/features/comment/elements/CommentContainer.module.css b/src/features/comment/elements/CommentContainer.module.css new file mode 100644 index 0000000000..165306655e --- /dev/null +++ b/src/features/comment/elements/CommentContainer.module.css @@ -0,0 +1,38 @@ +.container { + display: flex; + + position: relative; + width: 100%; + + gap: 12px; + + font-size: 0.9375em; + + display: flex; + flex-direction: column; + + padding-left: var(--sv-depth); + + &:before { + content: ""; + position: absolute; + left: 0; + top: 0; + bottom: 0; + width: 2px; + filter: none; + + background: var(--sv-background); + + opacity: var(--sv-opacity); + } + + /* + * CSS footgun: + * https://stackoverflow.com/q/79206240/1319878 + * https://github.com/microsoft/TypeScript/issues/49753 + */ + :global(.ion-palette-dark) &:before { + filter: brightness(0.7); + } +} diff --git a/src/features/comment/elements/CommentContainer.tsx b/src/features/comment/elements/CommentContainer.tsx index 4ea2bd9f4a..0dea7aeef1 100644 --- a/src/features/comment/elements/CommentContainer.tsx +++ b/src/features/comment/elements/CommentContainer.tsx @@ -1,61 +1,32 @@ -import { styled } from "@linaria/react"; -import { ComponentProps } from "react"; - import COMMENT_THEMES from "#/features/settings/appearance/themes/commentsTheme/values"; -import { CommentsThemeType } from "#/services/db"; +import { sv } from "#/helpers/css"; import { useAppSelector } from "#/store"; -interface ContainerProps { +import styles from "./CommentContainer.module.css"; + +interface ContainerProps extends React.PropsWithChildren { depth: number; hidden?: boolean; - themeName: CommentsThemeType; } -const Container = styled.div` - display: flex; - - position: relative; - width: 100%; - - gap: 12px; - - font-size: 0.9375em; - - display: flex; - flex-direction: column; - - padding-left: ${({ depth }) => (depth > 0 ? "1em" : 0)}; - - &:before { - content: ""; - position: absolute; - left: 0; - top: 0; - bottom: 0; - width: 2px; - filter: none; - - .ion-palette-dark & { - filter: brightness(0.7); - } - - background: ${({ themeName, depth }) => - depth - ? COMMENT_THEMES[themeName][ - (depth - 1) % COMMENT_THEMES[themeName].length - ]! - : "none"}; - - opacity: ${({ hidden }) => (hidden ? 0 : 1)}; - } -`; - -export default function CommentContainer( - props: Omit, "themeName">, -) { +export default function CommentContainer(props: ContainerProps) { const commentsTheme = useAppSelector( (state) => state.settings.appearance.commentsTheme, ); - return ; + return ( +
0 ? "1em" : 0, + background: props.depth + ? COMMENT_THEMES[commentsTheme][ + (props.depth - 1) % COMMENT_THEMES[commentsTheme].length + ]! + : "none", + opacity: props.hidden ? 0 : 1, + })} + /> + ); } diff --git a/src/features/comment/elements/PositionedContainer.module.css b/src/features/comment/elements/PositionedContainer.module.css new file mode 100644 index 0000000000..6f8552884a --- /dev/null +++ b/src/features/comment/elements/PositionedContainer.module.css @@ -0,0 +1,14 @@ +.positionedContainer { + composes: maxWidth from "#/features/shared/shared.module.css"; + + position: relative; + + padding: 8px 12px; + + @media (hover: none) { + padding-top: 0.65em; + padding-bottom: 0.65em; + } + + padding-left: calc(12px + max(0px, calc(calc(var(--sv-depth) - 1) * 10px))); +} diff --git a/src/features/comment/elements/PositionedContainer.tsx b/src/features/comment/elements/PositionedContainer.tsx index 5c042c7961..51bffa6c1f 100644 --- a/src/features/comment/elements/PositionedContainer.tsx +++ b/src/features/comment/elements/PositionedContainer.tsx @@ -1,22 +1,22 @@ -import { styled } from "@linaria/react"; +import React from "react"; -import { maxWidthCss } from "#/features/shared/AppContent"; +import { sv } from "#/helpers/css"; -export const PositionedContainer = styled.div<{ - depth: number; -}>` - position: relative; - - ${maxWidthCss} +import styles from "./PositionedContainer.module.css"; - padding: 8px 12px; - - @media (hover: none) { - padding-top: 0.65em; - padding-bottom: 0.65em; - } +interface PositionedContainerProps extends React.PropsWithChildren { + depth: number; +} - padding-left: calc( - 12px + max(0px, calc(calc(${({ depth }) => depth} - 1) * 10px)) +export function PositionedContainer({ + depth, + ...props +}: PositionedContainerProps) { + return ( +
); -`; +} diff --git a/src/features/comment/inTree/CommentExpander.module.css b/src/features/comment/inTree/CommentExpander.module.css new file mode 100644 index 0000000000..73682b3fd8 --- /dev/null +++ b/src/features/comment/inTree/CommentExpander.module.css @@ -0,0 +1,28 @@ +.moreRepliesBlock { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + + color: var(--ion-color-primary); + + opacity: 1; +} + +.hidden { + opacity: 0; +} + +.chevronIcon { + font-size: 1rem; +} + +.spinner { + width: 1.25rem; + opacity: 0.6; + + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} diff --git a/src/features/comment/inTree/CommentExpander.tsx b/src/features/comment/inTree/CommentExpander.tsx index a837b0bbd7..bd20a52d69 100644 --- a/src/features/comment/inTree/CommentExpander.tsx +++ b/src/features/comment/inTree/CommentExpander.tsx @@ -1,5 +1,4 @@ -import { IonIcon, IonSpinner } from "@ionic/react"; -import { styled } from "@linaria/react"; +import { IonIcon, IonItem, IonSpinner } from "@ionic/react"; import { chevronDown } from "ionicons/icons"; import { CommentView } from "lemmy-js-client"; import { useContext, useState } from "react"; @@ -8,43 +7,21 @@ import AnimateHeight from "react-animate-height"; import CommentContainer from "#/features/comment/elements/CommentContainer"; import { PositionedContainer } from "#/features/comment/elements/PositionedContainer"; import { - OCommentThreadCollapse, defaultThreadCollapse, + OCommentThreadCollapse, } from "#/features/settings/settingsSlice"; +import { cx } from "#/helpers/css"; import { MAX_DEFAULT_COMMENT_DEPTH } from "#/helpers/lemmy"; import useAppToast from "#/helpers/useAppToast"; import useClient from "#/helpers/useClient"; import { useAppDispatch, useAppSelector } from "#/store"; -import { CustomIonItem } from "../Comment"; import { receivedComments } from "../commentSlice"; import CommentHr from "./CommentHr"; import { CommentsContext } from "./CommentsContext"; -const MoreRepliesBlock = styled.div<{ hidden: boolean }>` - display: flex; - align-items: center; - justify-content: space-between; - width: 100%; - - color: var(--ion-color-primary); - - opacity: ${({ hidden }) => (hidden ? 0 : 1)}; -`; - -const ChevronIcon = styled(IonIcon)` - font-size: 1rem; -`; - -const StyledIonSpinner = styled(IonSpinner)` - width: 1.25rem; - opacity: 0.6; - - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); -`; +import commentStyles from "../Comment.module.css"; +import styles from "./CommentExpander.module.css"; interface CommentExpanderProps { depth: number; @@ -109,19 +86,25 @@ export default function CommentExpander({ return ( - + - + ); } diff --git a/src/features/comment/inTree/CommentHr.module.css b/src/features/comment/inTree/CommentHr.module.css new file mode 100644 index 0000000000..970f7f0ba6 --- /dev/null +++ b/src/features/comment/inTree/CommentHr.module.css @@ -0,0 +1,21 @@ +.hrContainer { + composes: maxWidth from "#/features/shared/shared.module.css"; + + position: absolute; + left: 50%; + transform: translateX(-50%); + z-index: 100; + + padding-left: calc(0.5rem + calc(calc(var(--sv-depth) - 1) * 10px)); +} + +.hr { + flex: 1; + height: 1px; + background-color: var( + --ion-item-border-color, + var(--ion-border-color, var(--ion-background-color-step-250, #c8c7cc)) + ); + width: 100%; + margin: 0; +} diff --git a/src/features/comment/inTree/CommentHr.tsx b/src/features/comment/inTree/CommentHr.tsx index 698620aa0c..480f57a67d 100644 --- a/src/features/comment/inTree/CommentHr.tsx +++ b/src/features/comment/inTree/CommentHr.tsx @@ -1,27 +1,6 @@ -import { styled } from "@linaria/react"; +import { sv } from "#/helpers/css"; -import { maxWidthCss } from "#/features/shared/AppContent"; - -const HrContainer = styled.div<{ depth: number }>` - position: absolute; - left: 50%; - transform: translateX(-50%); - ${maxWidthCss} - z-index: 100; - - padding-left: calc(0.5rem + calc(calc(${({ depth }) => depth} - 1) * 10px)); -`; - -const Hr = styled.hr` - flex: 1; - height: 1px; - background-color: var( - --ion-item-border-color, - var(--ion-border-color, var(--ion-background-color-step-250, #c8c7cc)) - ); - width: 100%; - margin: 0; -`; +import styles from "./CommentHr.module.css"; interface CommentHrProps { depth: number; @@ -29,8 +8,8 @@ interface CommentHrProps { export default function CommentHr({ depth }: CommentHrProps) { return ( - -
-
+
+
+
); } diff --git a/src/features/comment/inTree/Comments.module.css b/src/features/comment/inTree/Comments.module.css new file mode 100644 index 0000000000..e29a8e4486 --- /dev/null +++ b/src/features/comment/inTree/Comments.module.css @@ -0,0 +1,31 @@ +.scrollViewContainer { + width: 100%; + height: 100%; +} + +.center { + position: relative; + padding: 4rem 0 4rem; + left: 50%; + transform: translateX(-50%); +} + +.spinner { + composes: center; + + opacity: 0.7; +} + +.empty { + composes: center; + + display: flex; + flex-direction: column; + gap: 0.5rem; + text-align: center; + + aside { + color: var(--ion-color-medium); + font-size: 0.8em; + } +} diff --git a/src/features/comment/inTree/Comments.tsx b/src/features/comment/inTree/Comments.tsx index 7582da02ae..d7b5e5445b 100644 --- a/src/features/comment/inTree/Comments.tsx +++ b/src/features/comment/inTree/Comments.tsx @@ -1,6 +1,5 @@ import { RefresherCustomEvent } from "@ionic/core"; import { IonRefresher, IonRefresherContent, IonSpinner } from "@ionic/react"; -import { styled } from "@linaria/react"; import { compact, differenceBy, sortBy, uniqBy } from "es-toolkit"; import { CommentSortType, CommentView } from "lemmy-js-client"; import React, { @@ -33,40 +32,11 @@ import { isSafariFeedHackEnabled } from "#/routes/pages/shared/FeedContent"; import { useAppDispatch, useAppSelector } from "#/store"; import { receivedComments } from "../commentSlice"; -import CommentTree, { MAX_COMMENT_DEPTH } from "./CommentTree"; import { CommentsContext } from "./CommentsContext"; +import CommentTree, { MAX_COMMENT_DEPTH } from "./CommentTree"; import LoadParentComments from "./LoadParentComments"; -const ScrollViewContainer = styled.div` - width: 100%; - height: 100%; -`; - -const centerCss = ` - position: relative; - padding: 4rem 0 4rem; - left: 50%; - transform: translateX(-50%); -`; - -const StyledIonSpinner = styled(IonSpinner)` - ${centerCss} - opacity: 0.7; -`; - -const Empty = styled.div` - ${centerCss} - - display: flex; - flex-direction: column; - gap: 0.5rem; - text-align: center; - - aside { - color: var(--ion-color-medium); - font-size: 0.8em; - } -`; +import styles from "./Comments.module.css"; const MAX_COMMENT_PATH_CONTEXT_DEPTH = 2; @@ -453,14 +423,15 @@ export default function Comments({ /> ); - if (loading && !comments.length) return ; + if (loading && !comments.length) + return ; if (!comments.length) return ( - +
No Comments
- +
); }, [comments.length, fetchComments, loadFailed, loading]); @@ -506,7 +477,7 @@ export default function Comments({ > - +
{virtualEnabled ? ( {...content} )} - +
); } diff --git a/src/features/comment/inTree/ContinueThread.module.css b/src/features/comment/inTree/ContinueThread.module.css new file mode 100644 index 0000000000..5902fefea9 --- /dev/null +++ b/src/features/comment/inTree/ContinueThread.module.css @@ -0,0 +1,12 @@ +.moreRepliesBlock { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + + color: var(--ion-color-primary); +} + +.chevronIcon { + font-size: 1rem; +} diff --git a/src/features/comment/inTree/ContinueThread.tsx b/src/features/comment/inTree/ContinueThread.tsx index ce455b30e7..369aea0e60 100644 --- a/src/features/comment/inTree/ContinueThread.tsx +++ b/src/features/comment/inTree/ContinueThread.tsx @@ -1,5 +1,4 @@ -import { IonIcon } from "@ionic/react"; -import { styled } from "@linaria/react"; +import { IonIcon, IonItem } from "@ionic/react"; import { chevronForward } from "ionicons/icons"; import AnimateHeight from "react-animate-height"; import { useParams } from "react-router"; @@ -9,21 +8,10 @@ import { PositionedContainer } from "#/features/comment/elements/PositionedConta import { CommentNodeI } from "#/helpers/lemmy"; import { useBuildGeneralBrowseLink } from "#/helpers/routes"; -import { CustomIonItem } from "../Comment"; import CommentHr from "./CommentHr"; -const MoreRepliesBlock = styled.div` - display: flex; - align-items: center; - justify-content: space-between; - width: 100%; - - color: var(--ion-color-primary); -`; - -const ChevronIcon = styled(IonIcon)` - font-size: 1rem; -`; +import commentStyles from "../Comment.module.css"; +import styles from "./ContinueThread.module.css"; interface CommentExpanderProps { depth: number; @@ -47,7 +35,8 @@ export default function ContinueThread({ return ( - - +
Continue Thread... - - + +
-
+
); } diff --git a/src/features/comment/inTree/LoadParentComments.module.css b/src/features/comment/inTree/LoadParentComments.module.css new file mode 100644 index 0000000000..0aa93b98af --- /dev/null +++ b/src/features/comment/inTree/LoadParentComments.module.css @@ -0,0 +1,12 @@ +.moreRepliesBlock { + display: flex; + align-items: center; + gap: 8px; + width: 100%; + + color: var(--ion-color-primary); +} + +.chevronIcon { + font-size: 1rem; +} diff --git a/src/features/comment/inTree/LoadParentComments.tsx b/src/features/comment/inTree/LoadParentComments.tsx index ff3502c217..8224110f08 100644 --- a/src/features/comment/inTree/LoadParentComments.tsx +++ b/src/features/comment/inTree/LoadParentComments.tsx @@ -1,25 +1,13 @@ -import { IonIcon } from "@ionic/react"; -import { styled } from "@linaria/react"; +import { IonIcon, IonItem } from "@ionic/react"; import { chevronUp } from "ionicons/icons"; import CommentContainer from "#/features/comment/elements/CommentContainer"; import { PositionedContainer } from "#/features/comment/elements/PositionedContainer"; -import { CustomIonItem } from "../Comment"; import CommentHr from "./CommentHr"; -const MoreRepliesBlock = styled.div` - display: flex; - align-items: center; - gap: 8px; - width: 100%; - - color: var(--ion-color-primary); -`; - -const ChevronIcon = styled(IonIcon)` - font-size: 1rem; -`; +import commentStyles from "../Comment.module.css"; +import styles from "./LoadParentComments.module.css"; interface LoadParentCommentsProps { setMaxContext: React.Dispatch>; @@ -30,20 +18,21 @@ export default function LoadParentComments({ }: LoadParentCommentsProps) { return ( <> - { setMaxContext((maxContext) => maxContext - 5); }} > - - +
+ Load parent comments... - +
-
+ ); diff --git a/src/features/comment/useCommentActions.ts b/src/features/comment/useCommentActions.ts index 74ae2f0b13..86012f6e8a 100644 --- a/src/features/comment/useCommentActions.ts +++ b/src/features/comment/useCommentActions.ts @@ -20,8 +20,8 @@ import { } from "lemmy-js-client"; import { useCallback, useContext, useMemo } from "react"; -import { PageContext } from "#/features/auth/PageContext"; import { userHandleSelector } from "#/features/auth/authSelectors"; +import { PageContext } from "#/features/auth/PageContext"; import { isDownvoteEnabledSelector } from "#/features/auth/siteSlice"; import { getCanModerate, @@ -38,8 +38,8 @@ import { import { getVoteErrorMessage } from "#/helpers/lemmyErrors"; import { useBuildGeneralBrowseLink } from "#/helpers/routes"; import { - commentDeleteFailed, commentDeleted, + commentDeleteFailed, postLocked, saveError, saveSuccess, diff --git a/src/features/community/CommunitySummary.module.css b/src/features/community/CommunitySummary.module.css new file mode 100644 index 0000000000..97f9279474 --- /dev/null +++ b/src/features/community/CommunitySummary.module.css @@ -0,0 +1,45 @@ +.item { + --padding-start: 0; + --inner-padding-end: 0; +} + +.rightContainer { + display: flex; + align-items: center; + gap: 0.5rem; +} + +.title { + display: flex; + justify-content: space-between; + align-items: center; +} + +.communityLink { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; +} + +.contents { + composes: maxWidth from "#/features/shared/shared.module.css"; + + display: flex; + flex-direction: column; + gap: 0.5rem; + padding: 1rem; +} + +.stats { + font-size: 0.9rem; + color: var(--ion-color-medium); +} + +.description { + font-size: 0.875em; + + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + overflow: hidden; +} diff --git a/src/features/community/CommunitySummary.tsx b/src/features/community/CommunitySummary.tsx index 3ab445de46..9eca1c1b73 100644 --- a/src/features/community/CommunitySummary.tsx +++ b/src/features/community/CommunitySummary.tsx @@ -1,65 +1,20 @@ import { IonItem } from "@ionic/react"; -import { styled } from "@linaria/react"; import { heart } from "ionicons/icons"; import { CommunityView } from "lemmy-js-client"; import Ago from "#/features/labels/Ago"; import CommunityLink from "#/features/labels/links/CommunityLink"; import { ActionButton } from "#/features/post/actions/ActionButton"; -import { maxWidthCss } from "#/features/shared/AppContent"; import InlineMarkdown from "#/features/shared/markdown/InlineMarkdown"; import { buildCommunityLink } from "#/helpers/appLinkBuilder"; +import { cx } from "#/helpers/css"; import { formatNumber } from "#/helpers/number"; import { useBuildGeneralBrowseLink } from "#/helpers/routes"; import { ToggleIcon } from "./ToggleIcon"; import useCommunityActions from "./useCommunityActions"; -const CustomIonItem = styled(IonItem)` - --padding-start: 0; - --inner-padding-end: 0; -`; - -const RightContainer = styled.div` - display: flex; - align-items: center; - gap: 0.5rem; -`; - -const Title = styled.div` - display: flex; - justify-content: space-between; - align-items: center; -`; - -const StyledCommunityLink = styled(CommunityLink)` - min-width: 0; - overflow: hidden; - text-overflow: ellipsis; -`; - -const Contents = styled.div` - display: flex; - flex-direction: column; - gap: 0.5rem; - padding: 1rem; - - ${maxWidthCss} -`; - -const Stats = styled.div` - font-size: 0.9rem; - color: var(--ion-color-medium); -`; - -const Description = styled.div` - font-size: 0.875em; - - display: -webkit-box; - -webkit-line-clamp: 3; - -webkit-box-orient: vertical; - overflow: hidden; -`; +import styles from "./CommunitySummary.module.css"; interface CommunitySummaryProps { community: CommunityView; @@ -73,21 +28,23 @@ export default function CommunitySummary({ community }: CommunitySummaryProps) { ); return ( - - - - <StyledCommunityLink + <div className={cx(styles.contents)}> + <div className={styles.title}> + <CommunityLink + className={styles.communityLink} community={community.community} showInstanceWhenRemote subscribed={community.subscribed} hideSubscribed /> - <RightContainer> + <div className={styles.rightContainer}> <ActionButton onClick={(e) => { e.stopPropagation(); @@ -98,19 +55,19 @@ export default function CommunitySummary({ community }: CommunitySummaryProps) { > <ToggleIcon icon={heart} selected={isSubscribed} /> </ActionButton> - </RightContainer> - - +
+
+
{formatNumber(community.counts.subscribers)} Subscriber {community.counts.subscribers !== 1 ? "s" : ""} ·{" "} Old{" "} - +
{community.community.description && ( - +
{community.community.description} - +
)} - - +
+ ); } diff --git a/src/features/community/ToggleIcon.module.css b/src/features/community/ToggleIcon.module.css new file mode 100644 index 0000000000..9f7b359dff --- /dev/null +++ b/src/features/community/ToggleIcon.module.css @@ -0,0 +1,11 @@ +.base { + font-size: 24px; +} + +.selected { + color: var(--ion-color-primary); +} + +.unselected { + opacity: 0.08; +} diff --git a/src/features/community/ToggleIcon.tsx b/src/features/community/ToggleIcon.tsx index 94a3ad54a2..838eec4a39 100644 --- a/src/features/community/ToggleIcon.tsx +++ b/src/features/community/ToggleIcon.tsx @@ -1,19 +1,9 @@ import { IonIcon } from "@ionic/react"; -import { css, cx } from "@linaria/core"; -import { styled } from "@linaria/react"; import { ComponentProps } from "react"; -const BaseIonIcon = styled(IonIcon)` - font-size: 24px; -`; +import { cx } from "#/helpers/css"; -const selectedStyles = css` - color: var(--ion-color-primary); -`; - -const unselectedStyles = css` - opacity: 0.08; -`; +import styles from "./ToggleIcon.module.css"; interface ToggleIconProps extends ComponentProps { selected: boolean; @@ -21,11 +11,12 @@ interface ToggleIconProps extends ComponentProps { export function ToggleIcon({ selected, ...props }: ToggleIconProps) { return ( - ); diff --git a/src/features/community/communitySlice.ts b/src/features/community/communitySlice.ts index 1d0ddc2b73..70d8a05003 100644 --- a/src/features/community/communitySlice.ts +++ b/src/features/community/communitySlice.ts @@ -1,4 +1,4 @@ -import { PayloadAction, createSlice } from "@reduxjs/toolkit"; +import { createSlice, PayloadAction } from "@reduxjs/toolkit"; import { CommunityModeratorView, CommunityView, diff --git a/src/features/community/list/AlphabetJump.module.css b/src/features/community/list/AlphabetJump.module.css new file mode 100644 index 0000000000..79826f8b33 --- /dev/null +++ b/src/features/community/list/AlphabetJump.module.css @@ -0,0 +1,33 @@ +.container { + --line-height: 15px; + + position: absolute; + right: env(safe-area-inset-right); + z-index: 1; + + top: 50%; + transform: translateY(-50%); + + display: flex; + flex-direction: column; + + font-size: 0.7rem; + font-weight: 500; + color: var(--ion-color-primary); + text-align: center; + + padding-left: 6px; + padding-right: 3px; + + white-space: pre; + line-height: var(--line-height); + + ion-icon { + height: var(--line-height); + } + + /* Hide alphabet jump query DO NOT MODIFY unless also changing everywhere else */ + @media (max-height: 600px) and (orientation: landscape) { + display: none; + } +} diff --git a/src/features/community/list/AlphabetJump.tsx b/src/features/community/list/AlphabetJump.tsx index 7d60fc083e..2bd807c828 100644 --- a/src/features/community/list/AlphabetJump.tsx +++ b/src/features/community/list/AlphabetJump.tsx @@ -1,6 +1,5 @@ import { ImpactStyle } from "@capacitor/haptics"; import { IonIcon } from "@ionic/react"; -import { styled } from "@linaria/react"; import { compact } from "es-toolkit"; import { ellipseOutline, menuOutline, star } from "ionicons/icons"; import { MouseEvent, RefObject, TouchEvent, useMemo, useRef } from "react"; @@ -9,6 +8,8 @@ import { VListHandle } from "virtua"; import { findCurrentPage } from "#/helpers/ionic"; import useHapticFeedback from "#/helpers/useHapticFeedback"; +import styles from "./AlphabetJump.module.css"; + const alphabetUpperCase = Array.from({ length: 26 }, (_, i) => String.fromCharCode(65 + i), ); @@ -21,7 +22,9 @@ const SpecialSection = { type SpecialSectionType = (typeof SpecialSection)[keyof typeof SpecialSection]; -type JumpItem = SpecialSectionType | string; +type JumpValue = SpecialSectionType | string; + +type JumpItem = [JumpValue, number]; const SECTIONS = [ , @@ -50,54 +53,27 @@ const SIMPLIFIED_SECTIONS = SECTIONS.reduce( [], ); -export const HIDE_ALPHABET_JUMP = - "(max-height: 600px) and (orientation: landscape)" as const; - -const Container = styled.div` - --line-height: 15px; - - position: absolute; - right: env(safe-area-inset-right); - z-index: 1; - - top: 50%; - transform: translateY(-50%); - - display: flex; - flex-direction: column; - - font-size: 0.7rem; - font-weight: 500; - color: var(--ion-color-primary); - text-align: center; - - padding-left: 6px; - padding-right: 3px; - - white-space: pre; - line-height: var(--line-height); - - ion-icon { - height: var(--line-height); - } +const LOOKUP: Record = { + Moderator: SpecialSection.Moderated, + Favorites: SpecialSection.Favorited, +} as const; - @media ${HIDE_ALPHABET_JUMP} { - display: none; - } -`; +function mapSeparatorsToJumpSections( + separators: { label: string; index: number }[], +): JumpItem[] { + return compact( + separators.map(({ label, index }) => [LOOKUP[label] ?? label, index]), + ); +} interface AlphabetJumpProps { virtuaRef: RefObject; - hasModerated: boolean; - hasFavorited: boolean; - letters: string[]; + separators: { label: string; index: number }[]; } export default function AlphabetJump({ virtuaRef, - hasFavorited, - hasModerated, - letters, + separators, }: AlphabetJumpProps) { const containerElTopRef = useRef(); const scrollViewRef = useRef(); @@ -105,21 +81,18 @@ export default function AlphabetJump({ const jumpTableLookup = useMemo( () => buildJumpToTable( - compact([ - SpecialSection.Home, - hasFavorited ? SpecialSection.Favorited : undefined, - hasModerated ? SpecialSection.Moderated : undefined, - ...letters, - ]), - compact([ - SpecialSection.Home, - SpecialSection.Favorited, - SpecialSection.Moderated, - ...alphabetUpperCase, - "#", - ]), + compact(mapSeparatorsToJumpSections(separators)), + compact( + [ + SpecialSection.Home, + SpecialSection.Favorited, + SpecialSection.Moderated, + ...alphabetUpperCase, + "#", + ].map((value, index) => [value, index]), + ), ), - [hasFavorited, hasModerated, letters], + [separators], ); const containerRef = useRef(null); @@ -158,7 +131,8 @@ export default function AlphabetJump({ }; return ( - { @@ -174,7 +148,7 @@ export default function AlphabetJump({ slot="fixed" > {SIMPLIFIED_SECTIONS} - +
); } @@ -184,8 +158,8 @@ function buildJumpToTable(partial: JumpItem[], all: JumpItem[]): number[] { let lastFound = 0; for (let i = 0; i < all.length; i++) { - const foundIndex = partial.findIndex((p) => p === all[i]); - if (foundIndex !== -1) lastFound = foundIndex; + const foundItem = partial.find((p) => p[0] === all[i]![0]); + if (foundItem) lastFound = foundItem[1]; jumpToTable.push(lastFound); } diff --git a/src/features/community/list/GuestCommunitiesList.tsx b/src/features/community/list/GuestCommunitiesList.tsx index 26ba1951f5..12109e2ea9 100644 --- a/src/features/community/list/GuestCommunitiesList.tsx +++ b/src/features/community/list/GuestCommunitiesList.tsx @@ -1,8 +1,14 @@ +import { IonRefresher, IonRefresherContent } from "@ionic/react"; import { Community } from "lemmy-js-client"; -import { useEffect, useState } from "react"; +import { + useEffect, + experimental_useEffectEvent as useEffectEvent, + useState, +} from "react"; import { clientSelector } from "#/features/auth/authSelectors"; import { CenteredSpinner } from "#/features/shared/CenteredSpinner"; +import { isSafariFeedHackEnabled } from "#/routes/pages/shared/FeedContent"; import { useAppSelector } from "#/store"; import { CommunitiesListProps } from "./CommunitiesList"; @@ -19,29 +25,51 @@ const SHOW_LOCAL_ONLY = ["lemmynsfw.com"]; export default function GuestCommunitiesList({ actor }: CommunitiesListProps) { const [communities, setCommunities] = useState(); const client = useAppSelector(clientSelector); + const [isListAtTop, setIsListAtTop] = useState(true); - useEffect(() => { - (async () => { + async function update() { + let communities; + + try { + ({ communities } = await client.listCommunities({ + type_: SHOW_LOCAL_ONLY.includes(actor) ? "Local" : "All", + sort: "TopAll", + limit: 50, + })); + } catch (error) { setCommunities(undefined); + throw error; + } + + setCommunities(communities.map((c) => c.community)); + } + + const updateEvent = useEffectEvent(update); + + useEffect(() => { + setCommunities(undefined); - let communities; - - try { - ({ communities } = await client.listCommunities({ - type_: SHOW_LOCAL_ONLY.includes(actor) ? "Local" : "All", - sort: "TopAll", - limit: 50, - })); - } catch (error) { - setCommunities(undefined); - throw error; - } - - setCommunities(communities.map((c) => c.community)); - })(); + updateEvent(); }, [client, actor]); if (communities === undefined) return ; - return ; + return ( + <> + { + updateEvent().finally(() => e.detail.complete()); + }} + disabled={isSafariFeedHackEnabled && !isListAtTop} + > + + + + + ); } diff --git a/src/features/community/list/InitialPageRedirectBootstrapper.module.css b/src/features/community/list/InitialPageRedirectBootstrapper.module.css new file mode 100644 index 0000000000..861a765baa --- /dev/null +++ b/src/features/community/list/InitialPageRedirectBootstrapper.module.css @@ -0,0 +1,6 @@ +.loadingOverlay { + background: var(--ion-background-color); + position: fixed; + inset: 0; + z-index: 1000; +} diff --git a/src/features/community/list/InitialPageRedirectBootstrapper.tsx b/src/features/community/list/InitialPageRedirectBootstrapper.tsx index 87b4ae8df6..7b2b55fa8d 100644 --- a/src/features/community/list/InitialPageRedirectBootstrapper.tsx +++ b/src/features/community/list/InitialPageRedirectBootstrapper.tsx @@ -1,5 +1,4 @@ import { useIonViewDidEnter } from "@ionic/react"; -import { styled } from "@linaria/react"; import { useEffect, experimental_useEffectEvent as useEffectEvent, @@ -14,12 +13,7 @@ import { useAppDispatch } from "#/store"; import { appIsReadyToAcceptDeepLinks } from "./deepLinkReadySlice"; -const LoadingOverlay = styled.div` - background: var(--ion-background-color); - position: fixed; - inset: 0; - z-index: 1000; -`; +import styles from "./InitialPageRedirectBootstrapper.module.css"; interface InitialPageRedirectBootstrapperProps { to: string | undefined; @@ -105,5 +99,5 @@ export default function InitialPageRedirectBootstrapper({ if (!isInstalled() || bootstrapped) return null; - return ; + return
; } diff --git a/src/features/community/list/Item.tsx b/src/features/community/list/Item.tsx new file mode 100644 index 0000000000..203976e6ff --- /dev/null +++ b/src/features/community/list/Item.tsx @@ -0,0 +1,51 @@ +import { IonItemDivider } from "@ionic/react"; + +import { useAppSelector } from "#/store"; + +import CommunityListItem from "./items/CommunityListItem"; +import SpecialItem from "./items/SpecialItem"; +import { ItemType } from "./ResolvedCommunitiesList"; + +import sharedStyles from "#/features/shared/shared.module.css"; + +interface ItemProps { + item: ItemType; + actor: string; + line: boolean | undefined; +} + +export default function Item({ item, actor, line }: ItemProps) { + const favorites = useAppSelector((state) => state.community.favorites); + + switch (item.type) { + case "separator": + return ( + + {item.value} + + ); + case "all": + case "home": + case "local": + case "mod": + return ( + + ); + case "community": + case "favorite": + return ( + + ); + } +} diff --git a/src/features/community/list/LoggedInCommunitiesList.tsx b/src/features/community/list/LoggedInCommunitiesList.tsx index ff2d24b10b..a45e845bdb 100644 --- a/src/features/community/list/LoggedInCommunitiesList.tsx +++ b/src/features/community/list/LoggedInCommunitiesList.tsx @@ -1,25 +1,48 @@ +import { IonRefresher, IonRefresherContent } from "@ionic/react"; import { compact, uniqBy } from "es-toolkit"; import { CommunityFollowerView, CommunityView } from "lemmy-js-client"; +import { useState } from "react"; -import { useAppSelector } from "#/store"; +import { getSite } from "#/features/auth/siteSlice"; +import { isSafariFeedHackEnabled } from "#/routes/pages/shared/FeedContent"; +import { useAppDispatch, useAppSelector } from "#/store"; import { CommunitiesListProps } from "./CommunitiesList"; import ResolvedCommunitiesList from "./ResolvedCommunitiesList"; export default function LoggedInCommunitiesList(props: CommunitiesListProps) { + const dispatch = useAppDispatch(); const follows = useAppSelector( (state) => state.site.response?.my_user?.follows, ); - const communityByHandle = useAppSelector( (state) => state.community.communityByHandle, ); + const [isListAtTop, setIsListAtTop] = useState(true); + + async function refresh() { + await dispatch(getSite()); + } + return ( - + <> + { + refresh().finally(() => e.detail.complete()); + }} + disabled={isSafariFeedHackEnabled && !isListAtTop} + > + + + + + ); } diff --git a/src/features/community/list/ResolvedCommunitiesList.module.css b/src/features/community/list/ResolvedCommunitiesList.module.css new file mode 100644 index 0000000000..0a75721a10 --- /dev/null +++ b/src/features/community/list/ResolvedCommunitiesList.module.css @@ -0,0 +1,38 @@ +.subIcon { + border-radius: 50%; + padding: 6px; + width: 1rem; + height: 1rem; + + color: white; + + /* Background color set in style */ +} + +.content { + margin: 0.7rem 0; + + display: flex; + align-items: center; + gap: 1rem; + + aside { + margin-top: 0.2rem; + color: var(--ion-color-medium); + font-size: 0.8em; + } +} + +.virtualizerScrollView { + display: block; + overflow-y: auto; + contain: strict; + width: 100%; + height: 100%; + + &::-webkit-scrollbar { + display: none; + width: 0; + height: 0; + } +} diff --git a/src/features/community/list/ResolvedCommunitiesList.tsx b/src/features/community/list/ResolvedCommunitiesList.tsx index 33c7f48de3..aa2b96a0c1 100644 --- a/src/features/community/list/ResolvedCommunitiesList.tsx +++ b/src/features/community/list/ResolvedCommunitiesList.tsx @@ -1,84 +1,72 @@ -import { - IonIcon, - IonItem, - IonItemDivider, - IonItemGroup, - IonLabel, - IonList, -} from "@ionic/react"; -import { styled } from "@linaria/react"; -import { sortBy } from "es-toolkit"; -import { earth, home, people, shieldCheckmark } from "ionicons/icons"; +import { IonList } from "@ionic/react"; +import { compact, sortBy } from "es-toolkit"; import { Community } from "lemmy-js-client"; -import { memo, useMemo, useRef } from "react"; -import { VList, VListHandle } from "virtua"; +import { + createContext, + memo, + useCallback, + useContext, + useEffect, + useMemo, + useRef, + useState, +} from "react"; +import { CustomItemComponentProps, Virtualizer, VListHandle } from "virtua"; import { jwtSelector } from "#/features/auth/authSelectors"; -import { maxWidthCss } from "#/features/shared/AppContent"; -import { attributedPreventOnClickNavigationBug } from "#/helpers/ionic"; +import { cx } from "#/helpers/css"; import { getHandle } from "#/helpers/lemmy"; -import { useBuildGeneralBrowseLink } from "#/helpers/routes"; +import { isSafariFeedHackEnabled } from "#/routes/pages/shared/FeedContent"; import { useAppSelector } from "#/store"; import AlphabetJump from "./AlphabetJump"; -import CommunityListItem from "./CommunityListItem"; +import Item from "./Item"; import useShowModeratorFeed from "./useShowModeratorFeed"; -const SubIcon = styled(IonIcon)<{ color: string }>` - border-radius: 50%; - padding: 6px; - width: 1rem; - height: 1rem; - - background: ${({ color }) => color}; - --ion-color-base: white; -`; - -export const Content = styled.div` - margin: 0.7rem 0; +import styles from "./ResolvedCommunitiesList.module.css"; - display: flex; - align-items: center; - gap: 1rem; +const OVERSCAN_AMOUNT = 3; - aside { - margin-top: 0.2rem; - color: var(--ion-color-medium); - font-size: 0.8em; - } -`; +interface SeparatorItem { + type: "separator"; + value: string; +} -const StyledIonList = styled(IonList)` - height: 100%; -`; +interface SpecialItem { + type: "home" | "all" | "local" | "mod"; +} -const StyledVList = styled(VList)` - height: 100%; +interface CommunityItem { + type: "community"; + value: Community; +} - &::-webkit-scrollbar { - display: none; - width: 0; - height: 0; - } +interface FavoriteItem { + type: "favorite"; + value: string | Community; +} - ion-item-group { - ${maxWidthCss} - } -`; +export type ItemType = + | SeparatorItem + | SpecialItem + | CommunityItem + | FavoriteItem; interface CommunitiesListParams { actor: string; communities: Community[]; + onListAtTopChange?: (isAtTop: boolean) => void; } function ResolvedCommunitiesList({ actor, communities, + onListAtTopChange, }: CommunitiesListParams) { - const buildGeneralBrowseLink = useBuildGeneralBrowseLink(); const jwt = useAppSelector(jwtSelector); const virtuaRef = useRef(null); + const [shift, setShift] = useState(false); const moderates = useAppSelector( (state) => state.site.response?.my_user?.moderates, @@ -115,133 +103,158 @@ function ResolvedCommunitiesList({ ); }, [communities]); + const { items, throughFavoritesCount } = useMemo(() => { + const favoriteItems: (FavoriteItem | SeparatorItem)[] = favorites?.length + ? [ + { type: "separator", value: "Favorites" }, + ...favoritesAsCommunitiesIfFound.map( + (c) => ({ type: "favorite", value: c }) as const, + ), + ] + : []; + + const modItems = moderates?.length + ? [ + { type: "separator", value: "Moderator" } as const, + ...moderates.map( + (c) => ({ type: "community", value: c.community }) as const, + ), + ] + : []; + + const alphabetItems = communitiesGroupedByLetter.flatMap( + ([letter, communities]) => [ + { type: "separator", value: letter } as const, + ...communities.map((c) => ({ type: "community", value: c }) as const), + ], + ); + + const upThroughFavorites: ItemType[] = compact([ + jwt && { type: "home" }, + { type: "all" }, + { type: "local" }, + showModeratorFeed && { type: "mod" }, + ...favoriteItems, + ]); + + const throughFavoritesCount = upThroughFavorites.length; + + const items: ItemType[] = compact([ + ...upThroughFavorites, + ...modItems, + ...alphabetItems, + ]); + + return { + items, + throughFavoritesCount, + }; + }, [ + communitiesGroupedByLetter, + favorites?.length, + favoritesAsCommunitiesIfFound, + jwt, + moderates, + showModeratorFeed, + ]); + + const stickyIndexes = useMemo(() => { + const indexes = new Set(); + for (const [index, item] of items.entries()) { + if ("type" in item && item.type === "separator") { + indexes.add(index); + } + } + return indexes; + }, [items]); + + const [activeIndex, setActiveIndex] = useState(-1); + + const updateActiveIndex = useCallback(() => { + if (!virtuaRef.current) return; + const start = virtuaRef.current.findStartIndex(); + const activeStickyIndex = + [...stickyIndexes].reverse().find((index) => start >= index) ?? -1; + setActiveIndex(activeStickyIndex); + }, [stickyIndexes]); + + useEffect(() => { + updateActiveIndex(); + }, [updateActiveIndex]); + return ( - <> - - +
+ { + onListAtTopChange?.(offset < 10); + + if (virtuaRef.current) { + setShift( + virtuaRef.current.findStartIndex() > + throughFavoritesCount + OVERSCAN_AMOUNT, // overscan + ); + } else { + setShift(false); + } + + updateActiveIndex(); + }} + // @ts-expect-error Virtua types not correct + as={IonList} + keepMounted={activeIndex >= 0 ? [activeIndex] : []} + // @ts-expect-error Virtua types not correct + item={StickyItem} > - - {jwt && ( - - - -
- Home - -
-
-
- )} - - - -
- All -
-
-
- - - -
- Local -
-
-
- {showModeratorFeed && ( - - - -
- Moderator Posts - -
-
-
- )} -
- - {favoritesAsCommunitiesIfFound.length > 0 && ( - - - Favorites - - - {favoritesAsCommunitiesIfFound.map((favorite) => ( - - ))} - - )} - - {moderates?.length ? ( - - - Moderator - - {moderates.map(({ community }) => ( - - ))} - - ) : ( - "" - )} - {communitiesGroupedByLetter.map(([letter, communities]) => ( - - - {letter} - - {communities.map((community) => ( - - ))} - + {items.map((item, index) => ( + ))} - - +
+
letter)} + separators={compact( + items.map((item, index) => + item.type === "separator" ? { label: item.value, index } : null, + ), + )} /> - + ); } export default memo(ResolvedCommunitiesList); + +const StickyIndexContext = createContext(-1); +function StickyItem({ style, index, ...props }: CustomItemComponentProps) { + const activeIndex = useContext(StickyIndexContext); + return ( +
+ ); +} diff --git a/src/features/community/list/items/CommunityListItem.module.css b/src/features/community/list/items/CommunityListItem.module.css new file mode 100644 index 0000000000..30849de43e --- /dev/null +++ b/src/features/community/list/items/CommunityListItem.module.css @@ -0,0 +1,10 @@ +.toggleIcon { + @media (max-width: 725px) { + margin-right: 8px; + } + + /* Hide alphabet jump query DO NOT MODIFY unless also changing everywhere else */ + @media (max-height: 600px) and (orientation: landscape) { + margin-right: 0; + } +} diff --git a/src/features/community/list/CommunityListItem.tsx b/src/features/community/list/items/CommunityListItem.tsx similarity index 84% rename from src/features/community/list/CommunityListItem.tsx rename to src/features/community/list/items/CommunityListItem.tsx index b91160372e..24c649bb11 100644 --- a/src/features/community/list/CommunityListItem.tsx +++ b/src/features/community/list/items/CommunityListItem.tsx @@ -4,7 +4,6 @@ import { IonItemOptions, IonItemSliding, } from "@ionic/react"; -import { styled } from "@linaria/react"; import { star } from "ionicons/icons"; import { Community } from "lemmy-js-client"; import { useMemo } from "react"; @@ -23,34 +22,31 @@ import { import useAppToast from "#/helpers/useAppToast"; import { useAppDispatch, useAppSelector } from "#/store"; -import { ToggleIcon } from "../ToggleIcon"; import { addFavorite, followCommunity, removeFavorite, -} from "../communitySlice"; -import { HIDE_ALPHABET_JUMP } from "./AlphabetJump"; -import { Content } from "./ResolvedCommunitiesList"; +} from "../../communitySlice"; +import { ToggleIcon } from "../../ToggleIcon"; -const StyledToggleIcon = styled(ToggleIcon)` - @media (max-width: 725px) { - margin-right: 8px; - } +import listStyles from "../ResolvedCommunitiesList.module.css"; +import styles from "./CommunityListItem.module.css"; - @media ${HIDE_ALPHABET_JUMP} { - margin-right: 0; - } -`; +interface CommunityListItemProps { + community: Community | string; + favorites?: string[]; + removeAction: "follow" | "favorite" | "none"; + line: boolean | undefined; + className?: string; +} export default function CommunityListItem({ community, favorites, removeAction, -}: { - community: Community | string; - favorites?: string[]; - removeAction: "follow" | "favorite" | "none"; -}) { + line, + className, +}: CommunityListItemProps) { const buildGeneralBrowseLink = useBuildGeneralBrowseLink(); const dispatch = useAppDispatch(); const presentToast = useAppToast(); @@ -114,14 +110,16 @@ export default function CommunityListItem({ return ( - +
{handle} - +
{loggedIn && ( - + )}
diff --git a/src/features/community/list/items/SpecialItem.tsx b/src/features/community/list/items/SpecialItem.tsx new file mode 100644 index 0000000000..9fe525b4b4 --- /dev/null +++ b/src/features/community/list/items/SpecialItem.tsx @@ -0,0 +1,96 @@ +import { IonIcon, IonItem } from "@ionic/react"; +import { earth, home, people, shieldCheckmark } from "ionicons/icons"; + +import { attributedPreventOnClickNavigationBug } from "#/helpers/ionic"; +import { useBuildGeneralBrowseLink } from "#/helpers/routes"; + +import listStyles from "../ResolvedCommunitiesList.module.css"; + +interface SpecialItemProps { + type: "home" | "all" | "local" | "mod"; + actor: string; + line: boolean | undefined; + className?: string; +} + +export default function SpecialItem({ + type, + actor, + line, + className, +}: SpecialItemProps) { + const buildGeneralBrowseLink = useBuildGeneralBrowseLink(); + return ( + +
+ +
+ {getTitle(type)} + +
+
+
+ ); +} + +function getTitle(type: SpecialItemProps["type"]) { + switch (type) { + case "home": + return "Home"; + case "all": + return "All"; + case "local": + return "Local"; + case "mod": + return "Moderator"; + } +} + +function getIcon(type: SpecialItemProps["type"]) { + switch (type) { + case "home": + return home; + case "all": + return earth; + case "local": + return people; + case "mod": + return shieldCheckmark; + } +} + +function getIconBg(type: SpecialItemProps["type"]) { + switch (type) { + case "home": + return "red"; + case "all": + return "#009dff"; + case "local": + return "#00f100"; + case "mod": + return "#464646"; + } +} + +function getDescription(type: SpecialItemProps["type"], actor: string) { + switch (type) { + case "home": + return "Posts from subscriptions"; + case "all": + return "Posts across all federated communities"; + case "local": + return `Posts from communities on ${actor}`; + case "mod": + return "Posts from moderated communities"; + } +} diff --git a/src/features/community/titleSearch/TitleSearch.module.css b/src/features/community/titleSearch/TitleSearch.module.css new file mode 100644 index 0000000000..9f069ee2f9 --- /dev/null +++ b/src/features/community/titleSearch/TitleSearch.module.css @@ -0,0 +1,45 @@ +.titleContents { + display: inline-flex; + align-items: center; + + :global(.ios) & { + justify-content: center; + } + + gap: 0.25rem; + + width: 100%; + + span { + overflow: hidden; + text-overflow: ellipsis; + } +} + +.input { + max-width: 115px; + margin: auto; + background: none; + border: 0; + font-weight: normal; + width: 100%; + text-align: inherit; + outline: none; + + &.input { + padding-top: 0; + padding-bottom: 0; + } + + :global(.searchbar-search-icon) { + display: none; + width: 0; + height: 0; + } + + --background: none; +} + +.dropdownIcon { + flex-shrink: 0; +} diff --git a/src/features/community/titleSearch/TitleSearch.tsx b/src/features/community/titleSearch/TitleSearch.tsx index f775b984a7..beead41d76 100644 --- a/src/features/community/titleSearch/TitleSearch.tsx +++ b/src/features/community/titleSearch/TitleSearch.tsx @@ -1,59 +1,15 @@ import { IonButton, IonButtons, IonIcon } from "@ionic/react"; -import { styled } from "@linaria/react"; import { chevronDown, close } from "ionicons/icons"; import React, { useContext, useEffect, useRef } from "react"; import AppTitle, { AppTitleHandle } from "#/features/shared/AppTitle"; +import { cx } from "#/helpers/css"; import { isIosTheme } from "#/helpers/device"; import { findCurrentPage } from "#/helpers/ionic"; import { TitleSearchContext } from "./TitleSearchProvider"; -const TitleContents = styled.span` - display: inline-flex; - align-items: center; - - .ios & { - justify-content: center; - } - - gap: 0.25rem; - - width: 100%; - - span { - overflow: hidden; - text-overflow: ellipsis; - } -`; - -const StyledInput = styled.input` - max-width: 115px; - margin: auto; - background: none; - border: 0; - font-weight: normal; - width: 100%; - text-align: inherit; - outline: none; - - && { - padding-top: 0; - padding-bottom: 0; - } - - .searchbar-search-icon { - display: none; - width: 0; - height: 0; - } - - --background: none; -`; - -const DropdownIcon = styled(IonIcon)` - flex-shrink: 0; -`; +import styles from "./TitleSearch.module.css"; const TITLE_CLASS = "title-search-opener"; @@ -97,7 +53,8 @@ export default function TitleSearch({ name, children, ref }: TitleSearchProps) { return ( <> - setSearch(e.target.value || "")} @@ -128,9 +85,10 @@ export default function TitleSearch({ name, children, ref }: TitleSearchProps) { return ( <> - - {name} - + + {name}{" "} + + {children} diff --git a/src/features/community/titleSearch/TitleSearchResults.module.css b/src/features/community/titleSearch/TitleSearchResults.module.css new file mode 100644 index 0000000000..babf213ea0 --- /dev/null +++ b/src/features/community/titleSearch/TitleSearchResults.module.css @@ -0,0 +1,52 @@ +.backdrop { + position: absolute; + right: 0; + top: 0; + bottom: 0; + left: 0; + z-index: 100; + + background: rgba(0, 0, 0, 0.2); + + :global(.ion-palette-dark) & { + background: rgba(0, 0, 0, 0.7); + } + + display: flex; + align-items: flex-start; + justify-content: center; +} + +.keyboardContent { + display: flex; + + transition: max-height 150ms ease-out; +} + +.contents { + --background: var(--ion-background-color); + + :global(.ion-palette-dark) & { + --background: var(--ion-background-color-step-100); + } + + background: var(--background); + width: 100%; + max-width: 500px; + width: calc(100vw - 2rem); + min-height: 175px; + max-height: 450px; + overflow: auto; + margin: 1rem; + border-radius: 0.5rem; + + overscroll-behavior: contain; + + ion-item { + --ion-item-background: var(--ion-background-color); + + :global(.ion-palette-dark) & { + --ion-item-background: var(--ion-background-color-step-100); + } + } +} diff --git a/src/features/community/titleSearch/TitleSearchResults.tsx b/src/features/community/titleSearch/TitleSearchResults.tsx index e66055d57b..2af3cf0a1f 100644 --- a/src/features/community/titleSearch/TitleSearchResults.tsx +++ b/src/features/community/titleSearch/TitleSearchResults.tsx @@ -1,5 +1,4 @@ import { IonItem, IonList } from "@ionic/react"; -import { styled } from "@linaria/react"; import { useDebouncedValue } from "@mantine/hooks"; import { compact, sortBy, uniqBy } from "es-toolkit"; import { Community, CommunityView } from "lemmy-js-client"; @@ -21,58 +20,7 @@ import { useAppSelector } from "#/store"; import { TitleSearchContext } from "./TitleSearchProvider"; -const Backdrop = styled.div` - position: absolute; - right: 0; - top: 0; - bottom: 0; - left: 0; - z-index: 100; - - background: rgba(0, 0, 0, 0.2); - - .ion-palette-dark & { - background: rgba(0, 0, 0, 0.7); - } - - display: flex; - align-items: flex-start; - justify-content: center; -`; - -const KeyboardContent = styled.div` - display: flex; - - transition: max-height 150ms ease-out; -`; - -const Contents = styled.div` - --background: var(--ion-background-color); - - .ion-palette-dark & { - --background: var(--ion-background-color-step-100); - } - - background: var(--background); - width: 100%; - max-width: 500px; - width: calc(100vw - 2rem); - min-height: 175px; - max-height: 450px; - overflow: auto; - margin: 1rem; - border-radius: 0.5rem; - - overscroll-behavior: contain; - - ion-item { - --ion-item-background: var(--ion-background-color); - - .ion-palette-dark & { - --ion-item-background: var(--ion-background-color-step-100); - } - } -`; +import styles from "./TitleSearchResults.module.css"; const SPECIAL_FEEDS = [ { @@ -251,12 +199,17 @@ export default function TitleSearchResults() { if (!searching) return null; return ( - setSearching(false)} slot="fixed"> - setSearching(false)} + slot="fixed" + > +
- e.stopPropagation()}> +
e.stopPropagation()}> {results.map((c) => ( ))} - - - +
+
+
); } diff --git a/src/features/community/useCommunityActions.tsx b/src/features/community/useCommunityActions.tsx index a1b8a5fb82..91c46c80db 100644 --- a/src/features/community/useCommunityActions.tsx +++ b/src/features/community/useCommunityActions.tsx @@ -13,7 +13,7 @@ import { checkIsMod, getHandle as useGetHandle } from "#/helpers/lemmy"; import { useBuildGeneralBrowseLink } from "#/helpers/routes"; import { allNSFWHidden, - buildBlocked, + buildBlockedCommunity, buildFavorited, buildProblemSubscribing, buildSuccessSubscribing, @@ -161,7 +161,7 @@ export default function useCommunityActions( handler: () => { (async () => { await _block(); - presentToast(buildBlocked(!isBlocked)); + presentToast(buildBlockedCommunity(!isBlocked)); })(); }, }, @@ -175,7 +175,7 @@ export default function useCommunityActions( db.setSetting("has_presented_block_nsfw_tip", true); } else { await _block(); - presentToast(buildBlocked(!isBlocked)); + presentToast(buildBlockedCommunity(!isBlocked)); } }; diff --git a/src/features/feed/Feed.tsx b/src/features/feed/Feed.tsx index 4aeec30220..092e142897 100644 --- a/src/features/feed/Feed.tsx +++ b/src/features/feed/Feed.tsx @@ -5,8 +5,8 @@ import { } from "@ionic/react"; import { differenceBy } from "es-toolkit"; import React, { - Fragment, createContext, + Fragment, useCallback, useContext, useEffect, @@ -149,7 +149,11 @@ export default function Feed({ const fetchMore = useCallback( async (refresh = false) => { // previous request must be done before subsequent fetching (existence of abort controller) - if (abortControllerRef.current) return; + if ( + abortControllerRef.current && + !abortControllerRef.current?.signal.aborted + ) + return; // Don't fetch more if we're at the end of the feed (unless refreshing) if (atEndRef.current && !refresh) return; @@ -185,6 +189,9 @@ export default function Feed({ setLoading(false); setLoadFailed(true); throw error; + } finally { + if (abortControllerRef.current === abortController) + abortControllerRef.current = undefined; } let newPageItems; @@ -195,7 +202,6 @@ export default function Feed({ if (result.next_page) currentPage = result.next_page; } - abortControllerRef.current = undefined; setLoading(false); const filteredNewPageItems = filterOnRxFn @@ -235,7 +241,6 @@ export default function Feed({ useEffect(() => { return () => { abortControllerRef.current?.abort(ABORT_REASON_UNMOUNT); - abortControllerRef.current = undefined; }; }, []); diff --git a/src/features/feed/FeedContext.tsx b/src/features/feed/FeedContext.tsx index 1ab610dee3..948c595dc7 100644 --- a/src/features/feed/FeedContext.tsx +++ b/src/features/feed/FeedContext.tsx @@ -1,4 +1,4 @@ -import React, { MutableRefObject, createContext, useRef } from "react"; +import React, { createContext, MutableRefObject, useRef } from "react"; import { PostCommentItem } from "./PostCommentFeed"; diff --git a/src/features/feed/PostCommentFeed.module.css b/src/features/feed/PostCommentFeed.module.css new file mode 100644 index 0000000000..c5583025a3 --- /dev/null +++ b/src/features/feed/PostCommentFeed.module.css @@ -0,0 +1,3 @@ +.thickBottomBorder { + border-bottom: 8px solid var(--thick-separator-color); +} diff --git a/src/features/feed/PostCommentFeed.tsx b/src/features/feed/PostCommentFeed.tsx index 6830e2b3ca..5325062ef9 100644 --- a/src/features/feed/PostCommentFeed.tsx +++ b/src/features/feed/PostCommentFeed.tsx @@ -1,4 +1,3 @@ -import { css } from "@linaria/core"; import { CommentView, PostView } from "lemmy-js-client"; import { ReactElement, @@ -29,11 +28,9 @@ import Feed, { FeedProps, FetchFn } from "./Feed"; import { FeedContext } from "./FeedContext"; import { useAutohidePostIfNeeded } from "./PageTypeContext"; -export type PostCommentItem = PostView | CommentView; +import styles from "./PostCommentFeed.module.css"; -const thickBorderCss = css` - border-bottom: 8px solid var(--thick-separator-color); -`; +export type PostCommentItem = PostView | CommentView; interface PostCommentFeed extends Omit, "renderItemContent"> { @@ -90,7 +87,7 @@ export default function PostCommentFeed({ case "compact": return undefined; case "large": - return thickBorderCss; + return styles.thickBottomBorder; } })(); diff --git a/src/features/feed/endItems/EndPost.module.css b/src/features/feed/endItems/EndPost.module.css new file mode 100644 index 0000000000..06d1b2a557 --- /dev/null +++ b/src/features/feed/endItems/EndPost.module.css @@ -0,0 +1,10 @@ +.container { + display: flex; + flex-direction: column; + gap: 1rem; + padding: 3rem 3rem 4rem; + font-size: 0.875em; + align-items: center; + justify-content: center; + color: var(--ion-color-medium); +} diff --git a/src/features/feed/endItems/EndPost.tsx b/src/features/feed/endItems/EndPost.tsx index 07b3776b24..ed7eaba66d 100644 --- a/src/features/feed/endItems/EndPost.tsx +++ b/src/features/feed/endItems/EndPost.tsx @@ -1,16 +1,6 @@ -import { styled } from "@linaria/react"; import { CommentSortType, PostSortType } from "lemmy-js-client"; -export const Container = styled.div` - display: flex; - flex-direction: column; - gap: 1rem; - padding: 3rem 3rem 4rem; - font-size: 0.875em; - align-items: center; - justify-content: center; - color: var(--ion-color-medium); -`; +import styles from "./EndPost.module.css"; export interface EndPostProps { empty: boolean | undefined; @@ -47,7 +37,7 @@ export default function EndPost({ return <>You've reached the end!; } - return {renderError()}; + return
{renderError()}
; } export function getSortDuration( diff --git a/src/features/feed/endItems/FeedLoadMoreFailed.tsx b/src/features/feed/endItems/FeedLoadMoreFailed.tsx index 88fc8f78c5..f8ece59d95 100644 --- a/src/features/feed/endItems/FeedLoadMoreFailed.tsx +++ b/src/features/feed/endItems/FeedLoadMoreFailed.tsx @@ -1,4 +1,4 @@ -import { Container } from "./EndPost"; +import endPostStyles from "./EndPost.module.css"; interface FeedLoadMoreFailedProps { fetchMore: () => void; @@ -12,8 +12,8 @@ export default function FeedLoadMoreFailed({ pluralType = "posts", }: FeedLoadMoreFailedProps) { return ( - fetchMore()}> +
fetchMore()} className={endPostStyles.container}> Failed to load more {pluralType}. {loading ? "Loading..." : "Try again?"} - +
); } diff --git a/src/features/feed/endItems/FetchMore.module.css b/src/features/feed/endItems/FetchMore.module.css new file mode 100644 index 0000000000..e6d5dc9a3a --- /dev/null +++ b/src/features/feed/endItems/FetchMore.module.css @@ -0,0 +1,9 @@ +.container { + display: flex; + flex-direction: column; + height: 100px; + font-size: 0.875em; + align-items: center; + justify-content: center; + color: var(--ion-color-medium); +} diff --git a/src/features/feed/endItems/FetchMore.tsx b/src/features/feed/endItems/FetchMore.tsx index 521bac7ad6..becaa028fb 100644 --- a/src/features/feed/endItems/FetchMore.tsx +++ b/src/features/feed/endItems/FetchMore.tsx @@ -1,16 +1,7 @@ import { IonIcon, IonLabel, IonSpinner } from "@ionic/react"; -import { styled } from "@linaria/react"; import { chevronDown } from "ionicons/icons"; -export const Container = styled.div` - display: flex; - flex-direction: column; - height: 100px; - font-size: 0.875em; - align-items: center; - justify-content: center; - color: var(--ion-color-medium); -`; +import styles from "./FetchMore.module.css"; interface FeedLoadMoreFailedProps { fetchMore: () => void; @@ -24,7 +15,7 @@ export default function FetchMore({ page, }: FeedLoadMoreFailedProps) { return ( - fetchMore()}> +
fetchMore()} className={styles.container}> {!loading ? ( Load Page {page + 1} @@ -32,6 +23,6 @@ export default function FetchMore({ ) : ( )} - +
); } diff --git a/src/features/feed/sort/feedSortSlice.tsx b/src/features/feed/sort/feedSortSlice.tsx index be632c0aa6..9a22070d29 100644 --- a/src/features/feed/sort/feedSortSlice.tsx +++ b/src/features/feed/sort/feedSortSlice.tsx @@ -1,4 +1,4 @@ -import { PayloadAction, createAsyncThunk, createSlice } from "@reduxjs/toolkit"; +import { createAsyncThunk, createSlice, PayloadAction } from "@reduxjs/toolkit"; import { CommentSortType, PostSortType } from "lemmy-js-client"; import { db } from "#/services/db"; diff --git a/src/features/feed/sort/useFeedSort.tsx b/src/features/feed/sort/useFeedSort.tsx index 0e29bb8c87..c1650b36d0 100644 --- a/src/features/feed/sort/useFeedSort.tsx +++ b/src/features/feed/sort/useFeedSort.tsx @@ -5,10 +5,10 @@ import { useAppDispatch, useAppSelector } from "#/store"; import { AnyFeed } from "../helpers"; import { - SetSortActionPayload, getFeedSort, getFeedSortSelectorBuilder, setFeedSort, + SetSortActionPayload, } from "./feedSortSlice"; interface Sorts { diff --git a/src/features/feed/useRangeChange.ts b/src/features/feed/useRangeChange.ts index a7d22d0010..20dfadd6bf 100644 --- a/src/features/feed/useRangeChange.ts +++ b/src/features/feed/useRangeChange.ts @@ -13,8 +13,9 @@ export function useRangeChange( const virtuaHandle = virtuaHandleRef.current; if (!virtuaHandle) return; - const startIndex = virtuaHandle.startIndex; - const endIndex = virtuaHandle.endIndex; + + const startIndex = virtuaHandle.findStartIndex(); + const endIndex = virtuaHandle.findEndIndex(); if ( startIndex !== startIndexRef.current || diff --git a/src/features/inbox/InboxItem.module.css b/src/features/inbox/InboxItem.module.css new file mode 100644 index 0000000000..8cfc06f5cf --- /dev/null +++ b/src/features/inbox/InboxItem.module.css @@ -0,0 +1,104 @@ +.container { + composes: maxWidth from "#/features/shared/shared.module.css"; + + display: flex; + gap: var(--padding-start); + + padding: 0.5rem 0; + + font-size: 0.875em; + + strong { + font-weight: 500; + } +} + +.label { + display: inline-flex; + max-width: 100%; + + font-weight: 500; + + a { + overflow: hidden; + text-overflow: ellipsis; + } +} + +.hr { + composes: maxWidth from "#/features/shared/shared.module.css"; + + position: relative; + height: 1px; + + &::after { + content: ""; + position: absolute; + + --right-offset: calc(23px + 1lh); + + width: calc(100% - var(--right-offset)); + left: var(--right-offset); + top: 0; + border-bottom: 1px solid + var( + --ion-item-border-color, + var(--ion-border-color, var(--ion-background-color-step-250, #c8c7cc)) + ); + } +} + +.item { + --ion-item-border-color: transparent; + --padding-start: 12px; +} + +.itemUnread { + --background: var(--unread-item-background-color); +} + +.startContent { + display: flex; + flex-direction: column; + gap: var(--padding-start); + + ion-icon { + width: 1lh; + height: 1lh; + } +} + +.typeIcon { + color: var(--ion-color-medium2); +} + +.content { + flex: 1; + min-width: 0; +} + +.body { + color: var(--ion-color-medium); +} + +.footer { + display: flex; + align-items: center; + justify-content: space-between; + + color: var(--ion-color-medium); + + > div { + min-width: 0; + } + + > aside { + margin-left: auto; + + display: flex; + align-items: center; + gap: 6px; + + color: var(--ion-color-medium2); + } +} diff --git a/src/features/inbox/InboxItem.tsx b/src/features/inbox/InboxItem.tsx index 9be34a9007..53ef2c06ef 100644 --- a/src/features/inbox/InboxItem.tsx +++ b/src/features/inbox/InboxItem.tsx @@ -1,6 +1,4 @@ import { IonIcon, IonItem } from "@ionic/react"; -import { css, cx } from "@linaria/core"; -import { styled } from "@linaria/react"; import { albums, chatbubble, mail, personCircle } from "ionicons/icons"; import { CommentReplyView, @@ -14,8 +12,8 @@ import CommentMarkdown from "#/features/comment/CommentMarkdown"; import Ago from "#/features/labels/Ago"; import CommunityLink from "#/features/labels/links/CommunityLink"; import PersonLink from "#/features/labels/links/PersonLink"; -import { maxWidthCss } from "#/features/shared/AppContent"; import SlidingInbox from "#/features/shared/sliding/SlidingInbox"; +import { cx } from "#/helpers/css"; import { isTouchDevice } from "#/helpers/device"; import { stopIonicTapClick } from "#/helpers/ionic"; import { getHandle } from "#/helpers/lemmy"; @@ -28,115 +26,10 @@ import { useAppDispatch, useAppSelector } from "#/store"; import InboxItemMoreActions, { InboxItemMoreActionsHandle, } from "./InboxItemMoreActions"; -import VoteArrow from "./VoteArrow"; import { getInboxItemId, markRead as markReadAction } from "./inboxSlice"; +import VoteArrow from "./VoteArrow"; -const labelStyles = css` - display: inline-flex; - max-width: 100%; - - font-weight: 500; - - a { - overflow: hidden; - text-overflow: ellipsis; - } -`; - -const Hr = styled.div` - ${maxWidthCss} - - position: relative; - height: 1px; - - &::after { - content: ""; - position: absolute; - - --right-offset: calc(23px + 1lh); - - width: calc(100% - var(--right-offset)); - left: var(--right-offset); - top: 0; - border-bottom: 1px solid - var( - --ion-item-border-color, - var(--ion-border-color, var(--ion-background-color-step-250, #c8c7cc)) - ); - } -`; - -const StyledIonItem = styled(IonItem)` - --ion-item-border-color: transparent; - --padding-start: 12px; -`; - -const itemUnreadCss = css` - --background: var(--unread-item-background-color); -`; - -const Container = styled.div` - display: flex; - gap: var(--padding-start); - - ${maxWidthCss} - - padding: 0.5rem 0; - - font-size: 0.875em; - - strong { - font-weight: 500; - } -`; - -const StartContent = styled.div` - display: flex; - flex-direction: column; - gap: var(--padding-start); - - ion-icon { - width: 1lh; - height: 1lh; - } -`; - -const TypeIcon = styled(IonIcon)` - color: var(--ion-color-medium2); -`; - -const Content = styled.div` - flex: 1; - min-width: 0; -`; - -const Header = styled.div``; - -const Body = styled.div` - color: var(--ion-color-medium); -`; - -const Footer = styled.div` - display: flex; - align-items: center; - justify-content: space-between; - - color: var(--ion-color-medium); - - > div { - min-width: 0; - } - - > aside { - margin-left: auto; - - display: flex; - align-items: center; - gap: 6px; - - color: var(--ion-color-medium2); - } -`; +import styles from "./InboxItem.module.css"; export type InboxItemView = | PersonMentionView @@ -213,7 +106,7 @@ export default function InboxItem({ item }: InboxItemProps) { <> {" "} @@ -222,7 +115,7 @@ export default function InboxItem({ item }: InboxItemProps) { community={item.community} subscribed={item.subscribed} hideIcon - className={labelStyles} + className={styles.label} /> ); @@ -289,10 +182,11 @@ export default function InboxItem({ item }: InboxItemProps) { }); const contents = ( - - - - +
+
+ - - -
{renderHeader()}
- +
+
+
{renderHeader()}
+
{renderContents()} - -
+
+
{renderFooterDetails()}
- - - - +
+
+
+ ); return ( <> {contents} -
+
); } diff --git a/src/features/inbox/InboxItemMoreActions.module.css b/src/features/inbox/InboxItemMoreActions.module.css new file mode 100644 index 0000000000..91972bea41 --- /dev/null +++ b/src/features/inbox/InboxItemMoreActions.module.css @@ -0,0 +1,7 @@ +.button { + composes: plainButton from "#/features/shared/shared.module.css"; + + &.button { + font-size: 1.12em; + } +} diff --git a/src/features/inbox/InboxItemMoreActions.tsx b/src/features/inbox/InboxItemMoreActions.tsx index 1ca8ad2057..115deba36f 100644 --- a/src/features/inbox/InboxItemMoreActions.tsx +++ b/src/features/inbox/InboxItemMoreActions.tsx @@ -1,17 +1,13 @@ -import { styled } from "@linaria/react"; import { mailOutline, mailUnreadOutline } from "ionicons/icons"; import MoreActions from "#/features/comment/CommentEllipsis"; -import { PlainButton } from "#/features/shared/PlainButton"; import { useAppDispatch, useAppSelector } from "#/store"; import { InboxItemView } from "./InboxItem"; -import PrivateMessageMoreActions from "./PrivateMessageMoreActions"; import { getInboxItemId, markRead } from "./inboxSlice"; +import PrivateMessageMoreActions from "./PrivateMessageMoreActions"; -const StyledPlainButton = styled(PlainButton)` - font-size: 1.12em; -`; +import styles from "./InboxItemMoreActions.module.css"; interface InboxItemMoreActionsProps { item: InboxItemView; @@ -42,7 +38,7 @@ export default function InboxItemMoreActions({ }; return ( - + ); } diff --git a/src/features/inbox/PrivateMessageMoreActions.module.css b/src/features/inbox/PrivateMessageMoreActions.module.css new file mode 100644 index 0000000000..047c2988a7 --- /dev/null +++ b/src/features/inbox/PrivateMessageMoreActions.module.css @@ -0,0 +1,3 @@ +.icon { + font-size: 1.2em; +} diff --git a/src/features/inbox/PrivateMessageMoreActions.tsx b/src/features/inbox/PrivateMessageMoreActions.tsx index ebaf8c9549..ffc15c7a25 100644 --- a/src/features/inbox/PrivateMessageMoreActions.tsx +++ b/src/features/inbox/PrivateMessageMoreActions.tsx @@ -1,5 +1,4 @@ import { ActionSheetButton, IonIcon } from "@ionic/react"; -import { styled } from "@linaria/react"; import { arrowUndoOutline, ellipsisHorizontal, @@ -18,9 +17,7 @@ import store, { useAppDispatch } from "#/store"; import { markRead, syncMessages } from "./inboxSlice"; -const StyledIonIcon = styled(IonIcon)` - font-size: 1.2em; -`; +import styles from "./PrivateMessageMoreActions.module.css"; interface PrivateMessageMoreActionsHandle { present: () => void; @@ -113,7 +110,8 @@ export default function PrivateMessageMoreActions({ ); return ( - { e.stopPropagation(); diff --git a/src/features/inbox/SendMessageBox.module.css b/src/features/inbox/SendMessageBox.module.css new file mode 100644 index 0000000000..ddabc50f71 --- /dev/null +++ b/src/features/inbox/SendMessageBox.module.css @@ -0,0 +1,64 @@ +.maxSizeContainer { + height: 100%; +} + +.sendContainer { + position: relative; + + padding: 0.5rem; +} + +.inputContainer { + position: relative; + + display: flex; + align-items: flex-end; + gap: 4px; +} + +.input { + border: 1px solid + var( + --ion-tab-bar-border-color, + var( + --ion-border-color, + var( + --ion-color-step-150, + var(--ion-background-color-step-150, rgba(0, 0, 0, 0.2)) + ) + ) + ); + border-radius: 1rem; + + /* Exact px measurements to prevent */ + /* pixel rounding browser inconsistencies */ + padding: 8px 12px; + line-height: 18px; + font-size: 16px; + margin: 0; + + background: var(--ion-background-color); + color: var(--ion-text-color); + outline: none; + + width: 100%; + resize: none; + appearance: none; +} + +.iconButton { + margin: 0; + min-height: 36px; + + ion-icon { + font-size: 22px; + } +} + +.resizeIcon { + transform: scale(1.1); +} + +.sendIcon { + transform: rotate(270deg); +} diff --git a/src/features/inbox/SendMessageBox.tsx b/src/features/inbox/SendMessageBox.tsx index 8f39fe1152..021a9f064b 100644 --- a/src/features/inbox/SendMessageBox.tsx +++ b/src/features/inbox/SendMessageBox.tsx @@ -1,6 +1,4 @@ import { IonButton, IonIcon } from "@ionic/react"; -import { css } from "@linaria/core"; -import { styled } from "@linaria/react"; import { resize, send as sendIcon } from "ionicons/icons"; import { Person } from "lemmy-js-client"; import { KeyboardEvent, useContext, useEffect, useRef, useState } from "react"; @@ -18,62 +16,7 @@ import { useAppDispatch } from "#/store"; import { receivedMessages } from "./inboxSlice"; -const MaxSizeContainer = styled(MaxWidthContainer)` - height: 100%; -`; - -const SendContainer = styled.div` - position: relative; - - padding: 0.5rem; -`; - -const InputContainer = styled.div` - position: relative; - - display: flex; - align-items: flex-end; - gap: 4px; -`; - -const Input = styled(TextareaAutosize)` - border: 1px solid - var( - --ion-tab-bar-border-color, - var( - --ion-border-color, - var( - --ion-color-step-150, - var(--ion-background-color-step-150, rgba(0, 0, 0, 0.2)) - ) - ) - ); - border-radius: 1rem; - - // Exact px measurements to prevent - // pixel rounding browser inconsistencies - padding: 8px 12px; - line-height: 18px; - font-size: 16px; - margin: 0; - - background: var(--ion-background-color); - color: var(--ion-text-color); - outline: none; - - width: 100%; - resize: none; - appearance: none; -`; - -const IconButton = styled(IonButton)` - margin: 0; - min-height: 36px; - - ion-icon { - font-size: 22px; - } -`; +import styles from "./SendMessageBox.module.css"; interface SendMessageBoxProps { recipient: Person; @@ -141,10 +84,11 @@ export default function SendMessageBox({ }, [router]); return ( - - - - + +
+ { @@ -163,12 +107,11 @@ export default function SendMessageBox({ - - + - - - - - + +
+
+
); } diff --git a/src/features/inbox/VoteArrow.module.css b/src/features/inbox/VoteArrow.module.css new file mode 100644 index 0000000000..68aa5b0d98 --- /dev/null +++ b/src/features/inbox/VoteArrow.module.css @@ -0,0 +1,15 @@ +.container { + font-size: 1.4em; + + width: 100%; + height: 1rem; + + position: relative; +} + +.voteIcon { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); +} diff --git a/src/features/inbox/VoteArrow.tsx b/src/features/inbox/VoteArrow.tsx index a0e3acef76..0384562814 100644 --- a/src/features/inbox/VoteArrow.tsx +++ b/src/features/inbox/VoteArrow.tsx @@ -1,28 +1,13 @@ import { IonIcon } from "@ionic/react"; -import { styled } from "@linaria/react"; import { arrowDown, arrowUp } from "ionicons/icons"; import { - VOTE_COLORS, bgColorToVariable, + VOTE_COLORS, } from "#/features/settings/appearance/themes/votesTheme/VotesTheme"; import { useAppSelector } from "#/store"; -const Container = styled.div` - font-size: 1.4em; - - width: 100%; - height: 1rem; - - position: relative; -`; - -const VoteIcon = styled(IonIcon)` - position: absolute; - left: 50%; - top: 50%; - transform: translate(-50%, -50%); -`; +import styles from "./VoteArrow.module.css"; interface VoteArrowProps { vote: 1 | 0 | -1 | undefined; @@ -37,20 +22,22 @@ export default function VoteArrow({ vote }: VoteArrowProps) { if (vote === 1) return ( - - + - +
); if (vote === -1) return ( - - + - + ); } diff --git a/src/features/inbox/inboxSlice.ts b/src/features/inbox/inboxSlice.ts index 1d5f808675..b26d36f7ac 100644 --- a/src/features/inbox/inboxSlice.ts +++ b/src/features/inbox/inboxSlice.ts @@ -1,4 +1,4 @@ -import { PayloadAction, createSelector, createSlice } from "@reduxjs/toolkit"; +import { createSelector, createSlice, PayloadAction } from "@reduxjs/toolkit"; import { differenceBy, groupBy, sortBy, uniqBy } from "es-toolkit"; import { GetUnreadCountResponse, PrivateMessageView } from "lemmy-js-client"; diff --git a/src/features/inbox/messages/ConversationItem.module.css b/src/features/inbox/messages/ConversationItem.module.css new file mode 100644 index 0000000000..f38edb98f1 --- /dev/null +++ b/src/features/inbox/messages/ConversationItem.module.css @@ -0,0 +1,79 @@ +.itemIcon { + margin: 0.75rem 0; +} + +.messageContent { + display: flex; + flex-direction: column; + gap: 0.5rem; + margin: 0.5rem 0; + + width: 100%; + min-width: 0; +} + +.messageLine { + display: flex; + gap: 0.3rem; + min-width: 0; + white-space: nowrap; +} + +.personLabel { + flex: 1; + + font-size: 1rem; + margin: 0; + min-width: 0; + + display: inline; + margin-right: auto; + + overflow: hidden; + text-overflow: ellipsis; +} + +.openDetails { + flex: 0; + + font-size: 0.875em; + + display: inline-flex; + align-items: center; + gap: 0.25rem; + + color: var(--ion-color-medium); +} + +.messagePreview { + --line-height: 1.3rem; + --num-lines: 2; + + height: 2.5rem; + line-height: var(--line-height); + font-size: 0.875em; + height: calc(var(--line-height) * var(--num-lines)); + + color: var(--ion-color-medium); + + display: -webkit-box; + -webkit-line-clamp: var(--num-lines); + -webkit-box-orient: vertical; + overflow: hidden; +} + +.dot { + position: absolute; + top: 50%; + left: 0.25rem; + transform: translateY(-50%); + + background: var(--ion-color-primary); + + --size: 8px; + + border-radius: calc(var(--size) / 2); + + width: var(--size); + height: var(--size); +} diff --git a/src/features/inbox/messages/ConversationItem.tsx b/src/features/inbox/messages/ConversationItem.tsx index b775606390..1535f29719 100644 --- a/src/features/inbox/messages/ConversationItem.tsx +++ b/src/features/inbox/messages/ConversationItem.tsx @@ -7,7 +7,6 @@ import { IonLoading, useIonAlert, } from "@ionic/react"; -import { styled } from "@linaria/react"; import { chevronForwardOutline } from "ionicons/icons"; import { PrivateMessageView } from "lemmy-js-client"; import { useState } from "react"; @@ -20,85 +19,7 @@ import { useAppDispatch, useAppSelector } from "#/store"; import Time from "./Time"; -const StyledItemIcon = styled(ItemIcon)` - margin: 0.75rem 0; -`; - -const MessageContent = styled.div` - display: flex; - flex-direction: column; - gap: 0.5rem; - margin: 0.5rem 0; - - width: 100%; - min-width: 0; -`; - -const MessageLine = styled.div` - display: flex; - gap: 0.3rem; - min-width: 0; - white-space: nowrap; -`; - -const PersonLabel = styled.h3` - flex: 1; - - font-size: 1rem; - margin: 0; - min-width: 0; - - display: inline; - margin-right: auto; - - overflow: hidden; - text-overflow: ellipsis; -`; - -const OpenDetails = styled.span` - flex: 0; - - font-size: 0.875em; - - display: inline-flex; - align-items: center; - gap: 0.25rem; - - color: var(--ion-color-medium); -`; - -const MessagePreview = styled.div` - --line-height: 1.3rem; - --num-lines: 2; - - height: 2.5rem; - line-height: var(--line-height); - font-size: 0.875em; - height: calc(var(--line-height) * var(--num-lines)); - - color: var(--ion-color-medium); - - display: -webkit-box; - -webkit-line-clamp: var(--num-lines); - -webkit-box-orient: vertical; - overflow: hidden; -`; - -const Dot = styled.div` - position: absolute; - top: 50%; - left: 0.25rem; - transform: translateY(-50%); - - background: var(--ion-color-primary); - - --size: 8px; - - border-radius: calc(var(--size) / 2); - - width: var(--size); - height: var(--size); -`; +import styles from "./ConversationItem.module.css"; interface ConversationItemProps { messages: PrivateMessageView[]; @@ -193,25 +114,25 @@ export default function ConversationItem({ messages }: ConversationItemProps) { detail={false} >
- {unread ? : ""} - + {unread ?
: ""} +
- - - +
+
+

{person.display_name ?? getHandle(person)} - - +

+ - - - + +
+
{previewMsg.private_message.content} - - +
+
diff --git a/src/features/inbox/messages/Message.module.css b/src/features/inbox/messages/Message.module.css new file mode 100644 index 0000000000..266fdd648e --- /dev/null +++ b/src/features/inbox/messages/Message.module.css @@ -0,0 +1,80 @@ +.container { + position: relative; /* Setup a relative container for our pseudo elements */ + max-width: min(75%, 400px); + padding: 10px 15px; + line-height: 1.3; + word-wrap: break-word; /* Make sure the text wraps to multiple lines if long */ + + font-size: 1rem; + + --border-radius: 20px; + + border-radius: var(--border-radius); + + --bg: var(--ion-background-color); + --sentColor: var(--ion-color-primary); + --receiveColor: #eee; + + :global(.ion-palette-dark) & { + --receiveColor: var(--ion-color-medium); + } + + &:before { + width: 20px; + } + + &:after { + width: 26px; + background-color: var(--bg); /* All tails have the same bg cutout */ + } + + a { + color: white; + } + + &:before, + &:after { + position: absolute; + bottom: 0; + height: var( + --border-radius + ); /* height of our bubble "tail" - should match the border-radius above */ + content: ""; + } + + margin-bottom: 15px; +} + +.sent { + align-self: flex-end; + color: white; + background: var(--sentColor); + + &:before { + right: -7px; + background-color: var(--sentColor); + border-bottom-left-radius: 16px 14px; + } + + &:after { + right: -26px; + border-bottom-left-radius: 10px; + } +} + +.received { + align-self: flex-start; + color: black; + background: var(--receiveColor); + + &:before { + left: -7px; + background-color: var(--receiveColor); + border-bottom-right-radius: 16px 14px; + } + + &:after { + left: -26px; + border-bottom-right-radius: 10px; + } +} diff --git a/src/features/inbox/messages/Message.tsx b/src/features/inbox/messages/Message.tsx index 57edcc2c1e..2dea684fcd 100644 --- a/src/features/inbox/messages/Message.tsx +++ b/src/features/inbox/messages/Message.tsx @@ -1,6 +1,4 @@ import { useIonViewDidLeave, useIonViewWillEnter } from "@ionic/react"; -import { css } from "@linaria/core"; -import { styled } from "@linaria/react"; import { PrivateMessageView } from "lemmy-js-client"; import { useCallback, @@ -14,93 +12,13 @@ import { useLongPress } from "use-long-press"; import { PageContext } from "#/features/auth/PageContext"; import Markdown from "#/features/shared/markdown/Markdown"; +import { cx } from "#/helpers/css"; import useClient from "#/helpers/useClient"; import { useAppDispatch, useAppSelector } from "#/store"; import { getInboxCounts, receivedMessages } from "../inboxSlice"; -const Container = styled.div<{ first: boolean }>` - position: relative; /* Setup a relative container for our pseudo elements */ - max-width: min(75%, 400px); - padding: 10px 15px; - line-height: 1.3; - word-wrap: break-word; /* Make sure the text wraps to multiple lines if long */ - - font-size: 1rem; - - --border-radius: 20px; - - border-radius: var(--border-radius); - - --bg: var(--ion-background-color); - --sentColor: var(--ion-color-primary); - --receiveColor: #eee; - - .ion-palette-dark & { - --receiveColor: var(--ion-color-medium); - } - - &:before { - width: 20px; - } - - &:after { - width: 26px; - background-color: var(--bg); /* All tails have the same bg cutout */ - } - - a { - color: white; - } - - &:before, - &:after { - position: absolute; - bottom: 0; - height: var( - --border-radius - ); /* height of our bubble "tail" - should match the border-radius above */ - content: ""; - } - - margin-bottom: 15px; - - margin-top: ${({ first }) => (first ? "15px" : "0")}; -`; - -const sentCss = css` - align-self: flex-end; - color: white; - background: var(--sentColor); - - &:before { - right: -7px; - background-color: var(--sentColor); - border-bottom-left-radius: 16px 14px; - } - - &:after { - right: -26px; - border-bottom-left-radius: 10px; - } -`; - -const receivedCss = css` - align-self: flex-start; - color: black; - background: var(--receiveColor); - - &:before { - left: -7px; - background-color: var(--receiveColor); - border-bottom-right-radius: 16px 14px; - } - - &:after { - left: -26px; - border-bottom-right-radius: 10px; - } -`; +import styles from "./Message.module.css"; interface MessageProps { message: PrivateMessageView; @@ -166,9 +84,12 @@ export default function Message({ message, first }: MessageProps) { }, [focused, message, thisIsMyMessage, thisIsASelfMessage]); return ( - @@ -178,6 +99,6 @@ export default function Message({ message, first }: MessageProps) { > {message.private_message.content} - +
); } diff --git a/src/features/instances/instancesSlice.tsx b/src/features/instances/instancesSlice.tsx index 576ae724b2..8f56e07c3c 100644 --- a/src/features/instances/instancesSlice.tsx +++ b/src/features/instances/instancesSlice.tsx @@ -1,4 +1,4 @@ -import { PayloadAction, createSelector, createSlice } from "@reduxjs/toolkit"; +import { createSelector, createSlice, PayloadAction } from "@reduxjs/toolkit"; import { FederatedInstances } from "lemmy-js-client"; import { clientSelector, urlSelector } from "#/features/auth/authSelectors"; diff --git a/src/features/labels/Edited.module.css b/src/features/labels/Edited.module.css new file mode 100644 index 0000000000..68c8027ff5 --- /dev/null +++ b/src/features/labels/Edited.module.css @@ -0,0 +1,8 @@ +.edited { + display: flex; + align-items: center; + gap: inherit; + + margin: -3px; + padding: 3px; +} diff --git a/src/features/labels/Edited.tsx b/src/features/labels/Edited.tsx index afca345a25..badee7e024 100644 --- a/src/features/labels/Edited.tsx +++ b/src/features/labels/Edited.tsx @@ -1,22 +1,13 @@ import { useIonAlert } from "@ionic/react"; -import { styled } from "@linaria/react"; import { pencil } from "ionicons/icons"; import { CommentView, PostView } from "lemmy-js-client"; import { MouseEvent } from "react"; import Stat from "#/features/post/detail/Stat"; -import { PlainButton } from "#/features/shared/PlainButton"; import { formatRelative } from "./Ago"; -const EditedStat = styled(Stat)` - display: flex; - align-items: center; - gap: inherit; - - margin: -3px; - padding: 3px; -`; +import styles from "./Edited.module.css"; interface EditedProps { item: PostView | CommentView; @@ -58,13 +49,14 @@ export default function Edited({ item, showDate, className }: EditedProps) { } return ( - {editedLabelIfNeeded} - + ); } diff --git a/src/features/labels/Handle.module.css b/src/features/labels/Handle.module.css new file mode 100644 index 0000000000..39c40bfba2 --- /dev/null +++ b/src/features/labels/Handle.module.css @@ -0,0 +1,4 @@ +.aside { + display: inline; + opacity: 0.7; +} diff --git a/src/features/labels/Handle.tsx b/src/features/labels/Handle.tsx index 604ae0d267..831bfd77c4 100644 --- a/src/features/labels/Handle.tsx +++ b/src/features/labels/Handle.tsx @@ -1,12 +1,8 @@ -import { styled } from "@linaria/react"; import { Person } from "lemmy-js-client"; import { getItemActorName } from "#/helpers/lemmy"; -const Aside = styled.aside` - display: inline; - opacity: 0.7; -`; +import styles from "./Handle.module.css"; interface HandleProps { showInstanceWhenRemote?: boolean; @@ -19,8 +15,11 @@ export default function Handle(props: HandleProps) { export function renderHandle({ showInstanceWhenRemote, item }: HandleProps) { if (showInstanceWhenRemote && !item.local) - // eslint-disable-next-line react/jsx-key - return [item.name, ]; + return [ + item.name, + // eslint-disable-next-line react/jsx-key + , + ]; return [item.name]; } diff --git a/src/features/labels/Nsfw.module.css b/src/features/labels/Nsfw.module.css new file mode 100644 index 0000000000..88f4a9be8c --- /dev/null +++ b/src/features/labels/Nsfw.module.css @@ -0,0 +1,10 @@ +.container { + font-size: 0.8rem; + vertical-align: middle; + padding: 2px 4px; + border-radius: 8px; + margin-left: 4px; + background: #ff0000; + background: color(display-p3 1 0 0); + color: white; +} diff --git a/src/features/labels/Nsfw.tsx b/src/features/labels/Nsfw.tsx index a56b9448e0..85be862ac7 100644 --- a/src/features/labels/Nsfw.tsx +++ b/src/features/labels/Nsfw.tsx @@ -1,22 +1,12 @@ -import { styled } from "@linaria/react"; import { PostView } from "lemmy-js-client"; import { getItemActorName } from "#/helpers/lemmy"; import { OPostBlurNsfw, PostBlurNsfwType } from "#/services/db"; -const Container = styled.span` - font-size: 0.8rem; - vertical-align: middle; - padding: 2px 4px; - border-radius: 8px; - margin-left: 4px; - background: #ff0000; - background: color(display-p3 1 0 0); - color: white; -`; +import styles from "./Nsfw.module.css"; export default function Nsfw() { - return NSFW; + return NSFW; } const NSFW_INSTANCES = ["lemmynsfw.com"]; diff --git a/src/features/labels/Save.module.css b/src/features/labels/Save.module.css new file mode 100644 index 0000000000..b817e00bb8 --- /dev/null +++ b/src/features/labels/Save.module.css @@ -0,0 +1,14 @@ +.marker { + position: absolute; + right: 0; + bottom: 1px; /* Match bottom edge of sliding options, which is slightly inset */ + + --size: 18px; + + width: 0; + height: 0; + border-left: var(--size) solid transparent; + border-right: 0 solid transparent; + + border-bottom: var(--size) solid var(--ion-color-success); +} diff --git a/src/features/labels/Save.tsx b/src/features/labels/Save.tsx index b204b84971..ed7536ed78 100644 --- a/src/features/labels/Save.tsx +++ b/src/features/labels/Save.tsx @@ -1,21 +1,6 @@ -import { styled } from "@linaria/react"; - import { useAppSelector } from "#/store"; -const Marker = styled.div` - position: absolute; - right: 0; - bottom: 1px; // Match bottom edge of sliding options, which is slightly inset - - --size: 18px; - - width: 0; - height: 0; - border-left: var(--size) solid transparent; - border-right: 0 solid transparent; - - border-bottom: var(--size) solid var(--ion-color-success); -`; +import styles from "./Save.module.css"; interface SaveProps { type: "comment" | "post"; @@ -23,11 +8,13 @@ interface SaveProps { } export default function Save({ type, id }: SaveProps) { - const savedById = useAppSelector((state) => + const saved = useAppSelector((state) => type === "comment" - ? state.comment.commentSavedById - : state.post.postSavedById, + ? state.comment.commentSavedById[id] + : state.post.postSavedById[id], ); - return savedById[id] ? : null; + if (!saved) return null; + + return
; } diff --git a/src/features/labels/Vote.module.css b/src/features/labels/Vote.module.css new file mode 100644 index 0000000000..d4e21e1e2f --- /dev/null +++ b/src/features/labels/Vote.module.css @@ -0,0 +1,7 @@ +.icon { + /* Vote icons are tall and narrow, but svg container is square. + * This creates visually inconsistent padding. + * So fudge it so it looks better next to more square icons + */ + margin: 0 -2px; +} diff --git a/src/features/labels/Vote.tsx b/src/features/labels/Vote.tsx index 2fe34e307b..30a364e538 100644 --- a/src/features/labels/Vote.tsx +++ b/src/features/labels/Vote.tsx @@ -1,5 +1,4 @@ import { ImpactStyle } from "@capacitor/haptics"; -import { css } from "@linaria/core"; import { arrowDownSharp, arrowUpSharp } from "ionicons/icons"; import { CommentView, PostView } from "lemmy-js-client"; import React, { useContext } from "react"; @@ -8,7 +7,6 @@ import { PageContext } from "#/features/auth/PageContext"; import { isDownvoteEnabledSelector } from "#/features/auth/siteSlice"; import { voteOnComment } from "#/features/comment/commentSlice"; import { voteOnPost } from "#/features/post/postSlice"; -import { PlainButton } from "#/features/shared/PlainButton"; import { getVoteErrorMessage } from "#/helpers/lemmyErrors"; import { formatNumber } from "#/helpers/number"; import { downvotesDisabled } from "#/helpers/toastMessages"; @@ -20,13 +18,7 @@ import { useAppDispatch, useAppSelector } from "#/store"; import VoteStat from "./VoteStat"; -const iconClass = css` - // Vote icons are tall and narrow, but svg container is square. - // This creates visually inconsistent padding. - // So fudge it so it looks better next to more square icons - margin: 0 -2px; -`; - +import styles from "./Vote.module.css"; interface VoteProps { item: PostView | CommentView; className?: string; @@ -94,10 +86,10 @@ export default function Vote({ return ( <> { @@ -107,10 +99,10 @@ export default function Vote({ {formatNumber(upvotes)} { @@ -125,10 +117,10 @@ export default function Vote({ case OVoteDisplayMode.Hide: return ( { await onVote(e, myVote ? 0 : 1); @@ -140,10 +132,10 @@ export default function Vote({ const score = calculateTotalScore(item, votesById); return ( { await onVote(e, myVote ? 0 : 1); diff --git a/src/features/labels/VoteStat.tsx b/src/features/labels/VoteStat.tsx index 21ec5308b5..17d72cb0ea 100644 --- a/src/features/labels/VoteStat.tsx +++ b/src/features/labels/VoteStat.tsx @@ -2,8 +2,8 @@ import { ComponentProps } from "react"; import Stat from "#/features/post/detail/Stat"; import { - VOTE_COLORS, bgColorToVariable, + VOTE_COLORS, } from "#/features/settings/appearance/themes/votesTheme/VotesTheme"; import { VotesThemeType } from "#/services/db"; import { useAppSelector } from "#/store"; diff --git a/src/features/labels/img/ItemIcon.module.css b/src/features/labels/img/ItemIcon.module.css new file mode 100644 index 0000000000..bfbaee8cf0 --- /dev/null +++ b/src/features/labels/img/ItemIcon.module.css @@ -0,0 +1,4 @@ +.subImgIcon { + border-radius: 50%; + object-fit: cover; +} diff --git a/src/features/labels/img/ItemIcon.tsx b/src/features/labels/img/ItemIcon.tsx index d578d37c21..7fec3b322d 100644 --- a/src/features/labels/img/ItemIcon.tsx +++ b/src/features/labels/img/ItemIcon.tsx @@ -1,15 +1,11 @@ -import { styled } from "@linaria/react"; import { Community, Person } from "lemmy-js-client"; +import { useState } from "react"; import FakeIcon from "#/features/shared/FakeIcon"; +import { cx } from "#/helpers/css"; import { getImageSrc } from "#/services/lemmy"; -const SubImgIcon = styled.img<{ size: number }>` - width: ${({ size }) => size}px; - height: ${({ size }) => size}px; - border-radius: 50%; - object-fit: cover; -`; +import styles from "./ItemIcon.module.css"; interface ItemIconProps { item: Community | Person | string; @@ -24,6 +20,8 @@ export default function ItemIcon({ className, slot, }: ItemIconProps) { + const [failed, setFailed] = useState(false); + size = size ?? 28; if (typeof item === "string") @@ -33,14 +31,17 @@ export default function ItemIcon({ const icon = "posting_restricted_to_mods" in item ? item.icon : item.avatar; - if (icon) + if (icon && !failed) return ( - { + setFailed(true); + }} + className={cx(styles.subImgIcon, className)} slot={slot} /> ); diff --git a/src/features/labels/links/AgeBadge.tsx b/src/features/labels/links/AgeBadge.tsx index af7f3f3a83..c3a2fe78ce 100644 --- a/src/features/labels/links/AgeBadge.tsx +++ b/src/features/labels/links/AgeBadge.tsx @@ -1,9 +1,9 @@ -import { styled } from "@linaria/react"; import { useMemo } from "react"; import { calculateIsCakeDay, calculateNewAccount } from "#/helpers/date"; import { useAppSelector } from "#/store"; +import styles from "./AppBadge.module.css"; import Ago from "../Ago"; const NewAccountBadge = styled.span` @@ -49,10 +49,10 @@ export default function AgeBadge({ published }: AgeBadgeProps) { if (!highlightNewAccount) return; return ( - + {" "} 👶 {formatDaysOld(ageBadgeData.days)} - + ); } case "alien": { diff --git a/src/features/labels/links/AppBadge.module.css b/src/features/labels/links/AppBadge.module.css new file mode 100644 index 0000000000..8a4794cd85 --- /dev/null +++ b/src/features/labels/links/AppBadge.module.css @@ -0,0 +1,7 @@ +.newAccountBadge { + color: #d9a900; + + :global(.ion-palette-dark) & { + color: gold; + } +} diff --git a/src/features/labels/links/CommunityLink.module.css b/src/features/labels/links/CommunityLink.module.css new file mode 100644 index 0000000000..b01c86d3cb --- /dev/null +++ b/src/features/labels/links/CommunityLink.module.css @@ -0,0 +1,18 @@ +.itemIcon { + margin-right: 0.4rem; + vertical-align: middle; +} + +.subscribedIcon { + color: var(--ion-color-primary); + vertical-align: middle; + + margin-bottom: 1px; + margin-left: 2px; + + opacity: 0.4; + + :global(.ion-palette-dark) & { + opacity: 0.5; + } +} diff --git a/src/features/labels/links/CommunityLink.tsx b/src/features/labels/links/CommunityLink.tsx index 3875655e3a..c7e2ceefc9 100644 --- a/src/features/labels/links/CommunityLink.tsx +++ b/src/features/labels/links/CommunityLink.tsx @@ -1,6 +1,4 @@ import { IonIcon, useIonActionSheet } from "@ionic/react"; -import { cx } from "@linaria/core"; -import { styled } from "@linaria/react"; import { heart, heartDislikeOutline, @@ -10,11 +8,13 @@ import { } from "ionicons/icons"; import { Community, SubscribedType } from "lemmy-js-client"; import { createContext, useContext } from "react"; +import { Link } from "react-router-dom"; import { LongPressOptions, useLongPress } from "use-long-press"; import useCommunityActions from "#/features/community/useCommunityActions"; import ItemIcon from "#/features/labels/img/ItemIcon"; import { ShareImageContext } from "#/features/share/asImage/ShareAsImage"; +import { cx } from "#/helpers/css"; import { preventOnClickNavigationBug, stopIonicTapClick, @@ -25,26 +25,9 @@ import { OShowSubscribedIcon } from "#/services/db"; import { useAppSelector } from "#/store"; import { renderHandle } from "../Handle"; -import { LinkContainer, StyledLink, hideCss } from "./shared"; -const StyledItemIcon = styled(ItemIcon)` - margin-right: 0.4rem; - vertical-align: middle; -`; - -const SubscribedIcon = styled(IonIcon)` - color: var(--ion-color-primary); - vertical-align: middle; - - margin-bottom: 1px; - margin-left: 2px; - - opacity: 0.4; - - .ion-palette-dark & { - opacity: 0.5; - } -`; +import styles from "./CommunityLink.module.css"; +import sharedStyles from "./shared.module.css"; interface CommunityLinkProps { community: Community; @@ -131,17 +114,22 @@ export default function CommunityLink({ <> {instance} {showSubscribed && !hideSubscribed && isSubscribed && ( - + )} ); return ( - - { e.stopPropagation(); @@ -150,14 +138,18 @@ export default function CommunityLink({ draggable={false} > {showCommunityIcons && !hideCommunity && !hideIcon && ( - + )} {name} {!disableInstanceClick && end} - + {disableInstanceClick && end} - + ); } diff --git a/src/features/labels/links/PersonLink.module.css b/src/features/labels/links/PersonLink.module.css new file mode 100644 index 0000000000..5fbe939efc --- /dev/null +++ b/src/features/labels/links/PersonLink.module.css @@ -0,0 +1,3 @@ +.prefix { + font-weight: normal; +} diff --git a/src/features/labels/links/PersonLink.tsx b/src/features/labels/links/PersonLink.tsx index b5c3ae58e6..a0109597d5 100644 --- a/src/features/labels/links/PersonLink.tsx +++ b/src/features/labels/links/PersonLink.tsx @@ -1,7 +1,6 @@ -import { cx } from "@linaria/core"; -import { styled } from "@linaria/react"; import { Person } from "lemmy-js-client"; import { useCallback, useContext } from "react"; +import { Link } from "react-router-dom"; import { LongPressOptions, useLongPress } from "use-long-press"; import { ShareImageContext } from "#/features/share/asImage/ShareAsImage"; @@ -10,6 +9,7 @@ import UserTag from "#/features/tags/UserTag"; import usePresentUserActions, { PresentUserActionsOptions, } from "#/features/user/usePresentUserActions"; +import { cx } from "#/helpers/css"; import { preventOnClickNavigationBug, stopIonicTapClick, @@ -21,11 +21,9 @@ import { useAppSelector } from "#/store"; import { renderHandle } from "../Handle"; import AgeBadge from "./AgeBadge"; -import { LinkContainer, StyledLink, hideCss } from "./shared"; -const Prefix = styled.span` - font-weight: normal; -`; +import styles from "./PersonLink.module.css"; +import sharedStyles from "./shared.module.css"; interface PersonLinkProps extends Pick { person: Person; @@ -129,12 +127,17 @@ export default function PersonLink({ ); return ( - - { e.stopPropagation(); @@ -144,14 +147,14 @@ export default function PersonLink({ > {prefix ? ( <> - {prefix}{" "} + {prefix}{" "} ) : undefined} {handle} {!disableInstanceClick && end} - + {disableInstanceClick && end} - + ); } diff --git a/src/features/labels/links/shared.ts b/src/features/labels/links/shared.module.css similarity index 58% rename from src/features/labels/links/shared.ts rename to src/features/labels/links/shared.module.css index cb3c6f15aa..82fe5d4d2d 100644 --- a/src/features/labels/links/shared.ts +++ b/src/features/labels/links/shared.module.css @@ -1,8 +1,4 @@ -import { css } from "@linaria/core"; -import { styled } from "@linaria/react"; -import { Link } from "react-router-dom"; - -export const LinkContainer = styled.span` +.linkContainer { display: inline; font-weight: 500; @@ -12,14 +8,14 @@ export const LinkContainer = styled.span` overflow: hidden; position: relative; -`; +} -export const StyledLink = styled(Link)` +.link { text-decoration: none; color: inherit; -`; +} -export const hideCss = css` +.hide { position: relative; &:after { @@ -28,4 +24,4 @@ export const hideCss = css` inset: 0; background: var(--ion-background-color-step-150, #ccc); } -`; +} diff --git a/src/features/media/InlineMedia.tsx b/src/features/media/InlineMedia.tsx index 9370f05927..9c72624326 100644 --- a/src/features/media/InlineMedia.tsx +++ b/src/features/media/InlineMedia.tsx @@ -1,24 +1,23 @@ -import { cx } from "@linaria/core"; import { CSSProperties } from "react"; import Media, { MediaProps } from "#/features/media/Media"; -import useLatch from "#/helpers/useLatch"; +import { cx } from "#/helpers/css"; import { useAppDispatch } from "#/store"; -import MediaPlaceholder from "./MediaPlaceholder"; import { IMAGE_FAILED, imageFailed, imageLoaded } from "./imageSlice"; +import MediaPlaceholder from "./MediaPlaceholder"; import { isLoadedAspectRatio } from "./useAspectRatio"; import useMediaLoadObserver, { getTargetDimensions, } from "./useMediaLoadObserver"; +import mediaPlaceholderStyles from "./MediaPlaceholder.module.css"; + export type InlineMediaProps = Omit & { defaultAspectRatio?: number; mediaClassName?: string; }; -export const MEDIA_EL_CLASSNAME = "media"; - export default function InlineMedia({ src, className, @@ -28,15 +27,7 @@ export default function InlineMedia({ ...props }: InlineMediaProps) { const dispatch = useAppDispatch(); - const [mediaRef, currentAspectRatio] = useMediaLoadObserver(src); - - /** - * Cross posts have different image thumbnail url when loaded, so prevent resizing by latching - * - * If the new image is different size (or errors), it will be properly updated then - * (IMAGE_FAILED is truthy) - */ - const aspectRatio = useLatch(currentAspectRatio); + const [mediaRef, aspectRatio] = useMediaLoadObserver(src); function buildPlaceholderState() { if (aspectRatio === IMAGE_FAILED) return "error"; @@ -61,7 +52,7 @@ export default function InlineMedia({ { diff --git a/src/features/media/Media.tsx b/src/features/media/Media.tsx index cdc52c0439..2613226bb3 100644 --- a/src/features/media/Media.tsx +++ b/src/features/media/Media.tsx @@ -14,7 +14,15 @@ export interface MediaProps >; } -export default function Media({ nativeControls, src, ...props }: MediaProps) { +export default function Media({ + nativeControls, + src, + shouldPortal, + animationType, + volume, + progress, + ...props +}: MediaProps) { const isVideo = src && isUrlVideo(src, props.post?.post.url_content_type); if (isVideo) @@ -22,6 +30,9 @@ export default function Media({ nativeControls, src, ...props }: MediaProps) {
); } case OVoteDisplayMode.Separate: { @@ -146,20 +127,20 @@ function Voting({ post }: GalleryPostActionsProps): React.ReactElement { ); return ( -
+
- {upvotes} +
{upvotes}
- {downvotes} -
+
{downvotes}
+ ); } case OVoteDisplayMode.Hide: return ( -
+
-
+ ); } } diff --git a/src/features/media/gallery/actions/ImageMoreActions.module.css b/src/features/media/gallery/actions/ImageMoreActions.module.css new file mode 100644 index 0000000000..76482a3e6b --- /dev/null +++ b/src/features/media/gallery/actions/ImageMoreActions.module.css @@ -0,0 +1,16 @@ +.topContainer { + position: absolute; + top: 0; + right: 0; + left: 0; + height: 60px; + padding: 0 1rem; + margin-top: var(--ion-safe-area-top, env(safe-area-inset-top, 0)); + + display: flex; + align-items: center; + + color: white; + + font-size: 1.5em; +} diff --git a/src/features/media/gallery/actions/ImageMoreActions.tsx b/src/features/media/gallery/actions/ImageMoreActions.tsx index 4755f2fa02..a0e24bd4c0 100644 --- a/src/features/media/gallery/actions/ImageMoreActions.tsx +++ b/src/features/media/gallery/actions/ImageMoreActions.tsx @@ -1,27 +1,10 @@ -import { styled } from "@linaria/react"; - import { isNative } from "#/helpers/device"; import AltText from "./AltText"; import GalleryActions from "./GalleryActions"; import { BottomContainer, BottomContainerActions } from "./shared"; -const TopContainer = styled.div` - position: absolute; - top: 0; - right: 0; - left: 0; - height: 60px; - padding: 0 1rem; - margin-top: var(--ion-safe-area-top, env(safe-area-inset-top, 0)); - - display: flex; - align-items: center; - - color: white; - - font-size: 1.5em; -`; +import styles from "./ImageMoreActions.module.css"; interface ImageMoreActionsProps { imgSrc: string; @@ -35,14 +18,14 @@ export default function ImageMoreActions({ return ( <> {isNative() && ( - +
- +
)} {alt && ( - + )} diff --git a/src/features/media/gallery/actions/shared.module.css b/src/features/media/gallery/actions/shared.module.css new file mode 100644 index 0000000000..5a728b7098 --- /dev/null +++ b/src/features/media/gallery/actions/shared.module.css @@ -0,0 +1,52 @@ +.bottomContainer { + position: absolute; + bottom: 0; + right: 0; + left: 0; + + max-height: 100%; + + display: flex; + flex-direction: column; + align-items: center; + + > *:not(.bottomContainerActions) { + position: relative; + z-index: 1; + } +} + +.bottomContainerActions { + width: 100%; + + padding: 1rem; + padding-bottom: calc( + 1rem + var(--ion-safe-area-bottom, env(safe-area-inset-bottom, 0)) + ); + + color: white; + background: none; + + display: flex; + flex-direction: column; + align-items: center; + gap: 1rem; +} + +.withBg { + &:after { + content: ""; + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 100%; + + background: linear-gradient(0deg, rgba(0, 0, 0, 1), transparent); + } + + > * { + position: relative; + z-index: 1; + } +} diff --git a/src/features/media/gallery/actions/shared.ts b/src/features/media/gallery/actions/shared.ts deleted file mode 100644 index 2a732c1537..0000000000 --- a/src/features/media/gallery/actions/shared.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { styled } from "@linaria/react"; - -export const BottomContainer = styled.div` - position: absolute; - bottom: 0; - right: 0; - left: 0; - - display: flex; - flex-direction: column; - align-items: center; - - --topPadding: 4rem; -`; - -export const BottomContainerActions = styled.div<{ withBg: boolean }>` - width: 100%; - - padding: 1rem; - padding-top: var(--topPadding); - padding-bottom: calc( - 1rem + var(--ion-safe-area-bottom, env(safe-area-inset-bottom, 0)) - ); - - color: white; - background: ${({ withBg }) => - withBg ? "linear-gradient(0deg, rgba(0, 0, 0, 1), transparent)" : "none"}; - - display: flex; - flex-direction: column; - align-items: center; - gap: 1rem; -`; diff --git a/src/features/media/gallery/actions/shared.tsx b/src/features/media/gallery/actions/shared.tsx new file mode 100644 index 0000000000..7a5dc15f5a --- /dev/null +++ b/src/features/media/gallery/actions/shared.tsx @@ -0,0 +1,24 @@ +import React from "react"; + +import { cx } from "#/helpers/css"; + +import styles from "./shared.module.css"; + +export function BottomContainer({ children }: React.PropsWithChildren) { + return
{children}
; +} + +interface BottomContainerActionsProps extends React.PropsWithChildren { + withBg: boolean; +} + +export function BottomContainerActions({ + withBg, + children, +}: BottomContainerActionsProps) { + return ( +
+ {children} +
+ ); +} diff --git a/src/features/media/imageSlice.ts b/src/features/media/imageSlice.ts index 3dd319a2b4..51fbf9c578 100644 --- a/src/features/media/imageSlice.ts +++ b/src/features/media/imageSlice.ts @@ -1,4 +1,4 @@ -import { PayloadAction, createSlice } from "@reduxjs/toolkit"; +import { createSlice, PayloadAction } from "@reduxjs/toolkit"; import { round } from "es-toolkit"; export const IMAGE_FAILED = -1; diff --git a/src/features/media/useMediaLoadObserver.ts b/src/features/media/useMediaLoadObserver.ts index 3325e7b54f..a0c351c566 100644 --- a/src/features/media/useMediaLoadObserver.ts +++ b/src/features/media/useMediaLoadObserver.ts @@ -1,7 +1,7 @@ import { ComponentRef, useEffect, useRef } from "react"; -import type Media from "#/features/media/Media"; import { imageLoaded } from "#/features/media/imageSlice"; +import type Media from "#/features/media/Media"; import { useAppDispatch } from "#/store"; import useAspectRatio, { isLoadedAspectRatio } from "./useAspectRatio"; diff --git a/src/features/media/video/OutPortalEventDispatcher.module.css b/src/features/media/video/OutPortalEventDispatcher.module.css new file mode 100644 index 0000000000..0222fb29fe --- /dev/null +++ b/src/features/media/video/OutPortalEventDispatcher.module.css @@ -0,0 +1,5 @@ +.container { + flex: 1; + display: flex; + width: 100%; +} diff --git a/src/features/media/video/OutPortalEventDispatcher.tsx b/src/features/media/video/OutPortalEventDispatcher.tsx index 48f8043679..bf553647ef 100644 --- a/src/features/media/video/OutPortalEventDispatcher.tsx +++ b/src/features/media/video/OutPortalEventDispatcher.tsx @@ -1,11 +1,6 @@ -import { styled } from "@linaria/react"; import React, { MouseEvent, useEffect, useRef } from "react"; -const Container = styled.div` - flex: 1; - display: flex; - width: 100%; -`; +import styles from "./OutPortalEventDispatcher.module.css"; export interface OutPortalEventDispatcherProps extends React.PropsWithChildren { onClick?: (e: MouseEvent) => boolean | void; @@ -65,5 +60,9 @@ export default function OutPortalEventDispatcher({ }; }, [eventsToPropagateViaOutPortal]); - return {children}; + return ( +
+ {children} +
+ ); } diff --git a/src/features/media/video/Player.module.css b/src/features/media/video/Player.module.css new file mode 100644 index 0000000000..d0b4e8c594 --- /dev/null +++ b/src/features/media/video/Player.module.css @@ -0,0 +1,80 @@ +.container { + position: relative; + overflow: hidden; + + display: flex; +} + +.progress { + position: absolute; + bottom: -6px; + right: 0; + left: 0; + width: 100%; + appearance: none; + height: 12px; + transform: translate3d(0, 0, 0); + + background: none; + border: 0; + + &::-webkit-progress-bar { + background: rgba(0, 0, 0, 0.0045); + backdrop-filter: blur(30px); + } + + @supports selector(::-moz-progress-bar) { + background: rgba(0, 0, 0, 0.0045); + backdrop-filter: blur(30px); + } + + &::-moz-progress-bar { + background: rgba(255, 255, 255, 0.3); + } + + &::-webkit-progress-value { + background: rgba(255, 255, 255, 0.3); + } +} + +.videoEl { + flex: 1; + + width: 100%; + object-fit: contain; + + overflow: hidden; +} + +.volumeButton { + composes: plainButton from "#/features/shared/shared.module.css"; + + position: absolute; + top: 0; + right: 0; + + &.volumeButton { + padding: 14px; + font-size: 26px; + color: #aaa; + } + + svg { + filter: blur(10px) invert(80%); + } +} + +.playOverlay { + position: absolute; + inset: 0; + + display: flex; + align-items: center; + justify-content: center; + + font-size: 80px; + + color: #fff; + + background: rgba(0, 0, 0, 0.1); +} diff --git a/src/features/media/video/Player.tsx b/src/features/media/video/Player.tsx index 7b5a0ab50a..3e2b134cbf 100644 --- a/src/features/media/video/Player.tsx +++ b/src/features/media/video/Player.tsx @@ -1,9 +1,8 @@ import { IonIcon } from "@ionic/react"; -import { styled } from "@linaria/react"; import { play, volumeHigh, volumeOff } from "ionicons/icons"; import { - CSSProperties, ChangeEvent, + CSSProperties, useCallback, useEffect, useImperativeHandle, @@ -14,90 +13,11 @@ import { import { useInView } from "react-intersection-observer"; import useShouldAutoplay from "#/core/listeners/network/useShouldAutoplay"; -import { PlainButton } from "#/features/shared/PlainButton"; +import { cx } from "#/helpers/css"; import { stopIonicTapClick } from "#/helpers/ionic"; import { getVideoSrcForUrl } from "#/helpers/url"; -const Container = styled.div` - position: relative; - overflow: hidden; - - display: flex; -`; - -const sharedProgressBarCss = ` - background: rgba(0, 0, 0, 0.0045); - backdrop-filter: blur(30px); -`; - -const Progress = styled.progress` - position: absolute; - bottom: -6px; - right: 0; - left: 0; - width: 100%; - appearance: none; - height: 12px; - transform: translate3d(0, 0, 0); - - background: none; - border: 0; - - &::-webkit-progress-bar { - ${sharedProgressBarCss} - } - - @supports selector(::-moz-progress-bar) { - ${sharedProgressBarCss} - } - - &::-moz-progress-bar { - background: rgba(255, 255, 255, 0.3); - } - - &::-webkit-progress-value { - background: rgba(255, 255, 255, 0.3); - } -`; - -const VideoEl = styled.video` - flex: 1; - - width: 100%; - object-fit: contain; - - overflow: hidden; -`; - -const VolumeButton = styled(PlainButton)` - position: absolute; - top: 0; - right: 0; - - padding: 14px; - font-size: 26px; - - color: #aaa; - - svg { - filter: blur(10px) invert(80%); - } -`; - -const PlayOverlay = styled.div` - position: absolute; - inset: 0; - - display: flex; - align-items: center; - justify-content: center; - - font-size: 80px; - - color: #fff; - - background: rgba(0, 0, 0, 0.1); -`; +import styles from "./Player.module.css"; export interface PlayerProps { src: string; @@ -191,9 +111,10 @@ export default function Player({ }, [inView, pause, resume]); return ( - - + + ); } diff --git a/src/features/media/video/Video.tsx b/src/features/media/video/Video.tsx index e6f18de1e4..529a0a4df9 100644 --- a/src/features/media/video/Video.tsx +++ b/src/features/media/video/Video.tsx @@ -10,8 +10,8 @@ export interface VideoProps extends Omit { shouldPortal?: boolean; } -export default function Video(props: VideoProps) { - const VideoComponent = props.shouldPortal ? PortaledVideo : UnportaledVideo; +export default function Video({ shouldPortal, ...props }: VideoProps) { + const VideoComponent = shouldPortal ? PortaledVideo : UnportaledVideo; return ; } diff --git a/src/features/migrate/migrationSlice.ts b/src/features/migrate/migrationSlice.ts index 5079a1d3e4..02c2e87a44 100644 --- a/src/features/migrate/migrationSlice.ts +++ b/src/features/migrate/migrationSlice.ts @@ -1,4 +1,4 @@ -import { PayloadAction, createSlice } from "@reduxjs/toolkit"; +import { createSlice, PayloadAction } from "@reduxjs/toolkit"; import { uniq } from "es-toolkit"; import { db } from "#/services/db"; diff --git a/src/features/moderation/ModeratableItem.tsx b/src/features/moderation/ModeratableItem.tsx index 2af037e311..31fe3a03b0 100644 --- a/src/features/moderation/ModeratableItem.tsx +++ b/src/features/moderation/ModeratableItem.tsx @@ -1,24 +1,27 @@ -import { styled } from "@linaria/react"; import { CommentView, PostView } from "lemmy-js-client"; -import { ReactNode, createContext, useContext } from "react"; +import { createContext, ReactNode, useContext } from "react"; import { isPost } from "#/helpers/lemmy"; import { useAppSelector } from "#/store"; import ModeratableItemBanner, { - ItemModStateType, getModStateBackgroundColor, + ItemModStateType, useItemModState, } from "./banner/ModeratableItemBanner"; import useCanModerate from "./useCanModerate"; -const ModeratableItemContainer = styled.div<{ +interface ModeratableItemContainerProps extends React.ComponentProps<"div"> { modState?: ItemModStateType; highlighted?: boolean; -}>` - width: 100%; +} - background: ${({ modState, highlighted }) => { +function ModeratableItemContainer({ + modState, + highlighted, + ...props +}: ModeratableItemContainerProps) { + const background = (() => { const color = modState !== undefined ? getModStateBackgroundColor(modState) : undefined; @@ -27,8 +30,15 @@ const ModeratableItemContainer = styled.div<{ if (highlighted) return "var(--ion-color-light)"; return "none"; - }}; -`; + })(); + + const styles = { + width: "100%", + background, + }; + + return
; +} interface ModeratableItemProps { itemView: PostView | CommentView; diff --git a/src/features/moderation/ModqueueItemActions.tsx b/src/features/moderation/ModqueueItemActions.tsx index 9b329f2a10..fe4f489577 100644 --- a/src/features/moderation/ModqueueItemActions.tsx +++ b/src/features/moderation/ModqueueItemActions.tsx @@ -21,44 +21,43 @@ import { resolveCommentReport, resolvePostReport } from "./modSlice"; import useCanModerate, { getModColor } from "./useCanModerate"; interface ModqueueItemActionsProps { - item: PostView | CommentView; + itemView: PostView | CommentView; } export default function ModqueueItemActions({ - item, + itemView, }: ModqueueItemActionsProps) { const dispatch = useAppDispatch(); const presentToast = useAppToast(); - const canModerate = useCanModerate(item.community); + const canModerate = useCanModerate(itemView.community); async function modRemoveItem(remove: boolean) { - const id = isPost(item) ? item.post.id : item.comment.id; - const isAlreadyRemoved = isPost(item) - ? item.post.removed - : item.comment.removed; + const item = isPost(itemView) ? itemView.post : itemView.comment; + const isAlreadyRemoved = item.removed; // If removal status already in the state you want, just resolve reports if (remove === isAlreadyRemoved) { - const action = isPost(item) ? resolvePostReport : resolveCommentReport; - await dispatch(action(id)); + const action = isPost(itemView) + ? resolvePostReport + : resolveCommentReport; + await dispatch(action(item.id)); if (remove) - presentToast(isPost(item) ? postRemovedMod : commentRemovedMod); - else presentToast(isPost(item) ? postApproved : commentApproved); + presentToast(isPost(itemView) ? postRemovedMod : commentRemovedMod); + else presentToast(isPost(itemView) ? postApproved : commentApproved); return; } - const action = isPost(item) ? modRemovePost : modRemoveComment; - - await dispatch(action(id, remove)); + if (isPost(itemView)) await dispatch(modRemovePost(itemView.post, remove)); + else await dispatch(modRemoveComment(itemView.comment, remove)); const toastMessage = (() => { if (remove) { - if (isPost(item)) return postRemovedMod; + if (isPost(itemView)) return postRemovedMod; else return commentRemovedMod; } else { - if (isPost(item)) return postRestored; + if (isPost(itemView)) return postRestored; else return commentRestored; } })(); diff --git a/src/features/moderation/ban/BanUser.module.css b/src/features/moderation/ban/BanUser.module.css new file mode 100644 index 0000000000..c081845449 --- /dev/null +++ b/src/features/moderation/ban/BanUser.module.css @@ -0,0 +1,10 @@ +.daysValues { + display: flex; + align-items: center; + gap: 16px; +} + +.banTextContainer { + font-size: 0.925em; + margin: 0 32px 32px; +} diff --git a/src/features/moderation/ban/BanUser.tsx b/src/features/moderation/ban/BanUser.tsx index 449b4a32f6..bb0026868e 100644 --- a/src/features/moderation/ban/BanUser.tsx +++ b/src/features/moderation/ban/BanUser.tsx @@ -5,18 +5,17 @@ import { IonItem, IonLabel, IonList, + IonSpinner, IonTextarea, IonTitle, IonToggle, IonToolbar, useIonActionSheet, } from "@ionic/react"; -import { styled } from "@linaria/react"; import { addDays } from "date-fns"; import { useEffect, useState } from "react"; import { BanUserPayload } from "#/features/auth/PageContext"; -import { Centered, Spinner } from "#/features/auth/login/LoginNav"; import { preventPhotoswipeGalleryFocusTrap } from "#/features/media/gallery/GalleryImg"; import AddRemoveButtons from "#/features/share/asImage/AddRemoveButtons"; import AppHeader from "#/features/shared/AppHeader"; @@ -26,21 +25,7 @@ import { buildBanFailed, buildBanned } from "#/helpers/toastMessages"; import useAppToast from "#/helpers/useAppToast"; import { useAppDispatch } from "#/store"; -const Title = styled.span` - overflow: hidden; - text-overflow: ellipsis; -`; - -const DaysValues = styled.div` - display: flex; - align-items: center; - gap: 16px; -`; - -const BanTextContainer = styled.div` - font-size: 0.925em; - margin: 0 32px 32px; -`; +import styles from "./BanUser.module.css"; interface BanUserProps { dismiss: () => void; @@ -124,23 +109,15 @@ export default function BanUser({ dismiss()}>Cancel - - - - Ban {getHandle(user)} {loading && <Spinner color="dark" />} - - - + Ban {getHandle(user)} - - Ban - + {loading ? ( + + ) : ( + + Ban + + )} @@ -166,7 +143,7 @@ export default function BanUser({ {!permanent && ( Days - +
{days} 999} @@ -174,7 +151,7 @@ export default function BanUser({ onAdd={() => setDays((days) => days + 1)} onRemove={() => setDays((days) => days - 1)} /> - +
)} @@ -187,9 +164,9 @@ export default function BanUser({ - +
{text} - +
); diff --git a/src/features/moderation/ban/BanUserModal.module.css b/src/features/moderation/ban/BanUserModal.module.css new file mode 100644 index 0000000000..007644800a --- /dev/null +++ b/src/features/moderation/ban/BanUserModal.module.css @@ -0,0 +1,3 @@ +.modPrimaryColor { + --ion-color-primary: var(--ion-color-success); +} diff --git a/src/features/moderation/ban/BanUserModal.tsx b/src/features/moderation/ban/BanUserModal.tsx index 3729f928f1..e6b6a49e8c 100644 --- a/src/features/moderation/ban/BanUserModal.tsx +++ b/src/features/moderation/ban/BanUserModal.tsx @@ -1,13 +1,9 @@ -import { css } from "@linaria/core"; - import { BanUserPayload } from "#/features/auth/PageContext"; import { DynamicDismissableModal } from "#/features/shared/DynamicDismissableModal"; import BanUser from "./BanUser"; -const modPrimaryStyle = css` - --ion-color-primary: var(--ion-color-success); -`; +import styles from "./BanUserModal.module.css"; interface BanUserModalProps { item: BanUserPayload; @@ -24,7 +20,7 @@ export default function BanUserModal({ {({ setCanDismiss, dismiss }) => ( diff --git a/src/features/moderation/banner/ModeratableItemBanner.module.css b/src/features/moderation/banner/ModeratableItemBanner.module.css new file mode 100644 index 0000000000..18d79fc8d8 --- /dev/null +++ b/src/features/moderation/banner/ModeratableItemBanner.module.css @@ -0,0 +1,15 @@ +.sharedBanner { + composes: maxWidth from "#/features/shared/shared.module.css"; + + display: flex; + align-items: center; + justify-content: center; + gap: 6px; + + font-size: 0.875rem; + + padding: 6px 0; + border-radius: 6px; + + text-align: center; +} diff --git a/src/features/moderation/banner/ModeratableItemBanner.tsx b/src/features/moderation/banner/ModeratableItemBanner.tsx index 613bbcbdff..97cbfa3870 100644 --- a/src/features/moderation/banner/ModeratableItemBanner.tsx +++ b/src/features/moderation/banner/ModeratableItemBanner.tsx @@ -1,7 +1,6 @@ -import { styled } from "@linaria/react"; import { Comment, CommentView, Post, PostView } from "lemmy-js-client"; -import { maxWidthCss } from "#/features/shared/AppContent"; +import { cx } from "#/helpers/css"; import { useAppSelector } from "#/store"; import { @@ -11,6 +10,8 @@ import { import RemovedBanner from "./RemovedBanner"; import ReportBanner from "./ReportBanner"; +import styles from "./ModeratableItemBanner.module.css"; + export const ItemModState = { None: 0, Flagged: 1, @@ -19,26 +20,22 @@ export const ItemModState = { export type ItemModStateType = (typeof ItemModState)[keyof typeof ItemModState]; -export const Banner = styled.div<{ +interface BannerProps extends React.HTMLAttributes { modState: typeof ItemModState.Flagged | typeof ItemModState.RemovedByMod; -}>` - ${maxWidthCss} - - display: flex; - align-items: center; - justify-content: center; - gap: 6px; - - font-size: 0.875rem; - - padding: 6px 0; - border-radius: 6px; - - text-align: center; +} - background: ${({ modState }) => getModStateBannerBgColor(modState)!}; - color: ${({ modState }) => getModStateBannerColor(modState)!}; -`; +export function Banner({ modState, ...props }: BannerProps) { + return ( +
+ ); +} interface RemovedByBannerProps { modState: ItemModStateType; diff --git a/src/features/moderation/banner/RemovedBanner.tsx b/src/features/moderation/banner/RemovedBanner.tsx index f1f2c79ea0..fe21500892 100644 --- a/src/features/moderation/banner/RemovedBanner.tsx +++ b/src/features/moderation/banner/RemovedBanner.tsx @@ -27,10 +27,10 @@ export default function RemovedBanner({ itemView }: RemovedBannerProps) { handler: () => { (async () => { if (isPost(itemView)) { - dispatch(modRemovePost(itemView.post.id, false)); + dispatch(modRemovePost(itemView.post, false)); presentToast(postApproved); } else { - await dispatch(modRemoveComment(itemView.comment.id, false)); + await dispatch(modRemoveComment(itemView.comment, false)); presentToast(commentApproved); } })(); diff --git a/src/features/moderation/logs/ModlogItem.module.css b/src/features/moderation/logs/ModlogItem.module.css new file mode 100644 index 0000000000..67af623835 --- /dev/null +++ b/src/features/moderation/logs/ModlogItem.module.css @@ -0,0 +1,75 @@ +.container { + composes: maxWidth from "#/features/shared/shared.module.css"; + + display: flex; + gap: 1rem; + + padding: 0.5rem 0; + + font-size: 0.875em; + + strong { + font-weight: 500; + } +} + +.startContent { + display: flex; + flex-direction: column; + gap: 1rem; + + ion-icon { + width: 1lh; + height: 1lh; + } +} + +.typeIcon { + color: var(--ion-color-medium2); +} + +.content { + flex: 1; +} + +.header { + display: flex; + justify-content: space-between; + + aside { + margin-left: auto; + + display: flex; + align-items: center; + gap: 0.5rem; + + color: var(--ion-color-medium2); + } +} + +.body { + color: var(--ion-color-medium); + padding: 0.5rem 0; +} + +.footer { + display: flex; + justify-content: space-between; + align-items: center; + + aside { + display: flex; + align-items: center; + gap: 6px; + + color: var(--ion-color-medium2); + } +} + +.by { + display: flex; + justify-content: right; + align-items: center; + gap: 6px; + padding: 0.5rem 0; +} diff --git a/src/features/moderation/logs/ModlogItem.tsx b/src/features/moderation/logs/ModlogItem.tsx index 922f22b384..38b2cc4cca 100644 --- a/src/features/moderation/logs/ModlogItem.tsx +++ b/src/features/moderation/logs/ModlogItem.tsx @@ -1,22 +1,20 @@ import { IonIcon, IonItem } from "@ionic/react"; -import { cx } from "@linaria/core"; -import { styled } from "@linaria/react"; import { timerOutline } from "ionicons/icons"; import Ago from "#/features/labels/Ago"; -import { maxWidthCss } from "#/features/shared/AppContent"; +import { cx } from "#/helpers/css"; import { isTouchDevice } from "#/helpers/device"; import { useBuildGeneralBrowseLink } from "#/helpers/routes"; import { - ModeratorRole, getModColor, getModIcon, getModName, + ModeratorRole, } from "../useCanModerate"; import useIsAdmin from "../useIsAdmin"; -import ModlogItemMoreActions from "./ModlogItemMoreActions"; import { ModlogItemType } from "./helpers"; +import ModlogItemMoreActions from "./ModlogItemMoreActions"; import addCommunity from "./types/addCommunity"; import addInstance from "./types/addInstance"; import banFromCommunity from "./types/banFromCommunity"; @@ -33,84 +31,8 @@ import removeCommunity from "./types/removeCommunity"; import removePost from "./types/removePost"; import transferCommunity from "./types/transferCommunity"; -const Container = styled.div` - display: flex; - gap: 1rem; - - ${maxWidthCss} - - padding: 0.5rem 0; - - font-size: 0.875em; - - strong { - font-weight: 500; - } -`; - -const StartContent = styled.div` - display: flex; - flex-direction: column; - gap: 1rem; - - ion-icon { - width: 1lh; - height: 1lh; - } -`; - -const TypeIcon = styled(IonIcon)` - color: var(--ion-color-medium2); -`; - -const Content = styled.div` - flex: 1; -`; - -const Header = styled.div` - display: flex; - justify-content: space-between; - - aside { - margin-left: auto; - - display: flex; - align-items: center; - gap: 0.5rem; - - color: var(--ion-color-medium2); - } -`; - -const Body = styled.div` - color: var(--ion-color-medium); - padding: 0.5rem 0; -`; - -const Footer = styled.div` - display: flex; - justify-content: space-between; - align-items: center; - - aside { - display: flex; - align-items: center; - gap: 6px; - - color: var(--ion-color-medium2); - } -`; - -const Title = styled.div``; -const Reason = styled.div``; -const By = styled.div<{ color: string }>` - display: flex; - justify-content: right; - align-items: center; - gap: 6px; - padding: 0.5rem 0; - color: ${({ color }) => `var(--ion-color-${color}-shade)`}; -`; +import sharedStyles from "#/features/shared/shared.module.css"; +import styles from "./ModlogItem.module.css"; interface ModLogItemProps { item: ModlogItemType; @@ -200,38 +122,44 @@ export function ModlogItem({ item }: ModLogItemProps) { return ( - - - - - -
- {title} +
+
+ +
+
+
+
{title}
-
- {message} - {reason && Reason: {reason}} -
- +
+
{message}
+ {reason &&
Reason: {reason}
} +
+
{by ? by : getModName(role)} - +
{expires && ( )} - - - +
+
+ ); } diff --git a/src/features/moderation/logs/ModlogItemMoreActions.module.css b/src/features/moderation/logs/ModlogItemMoreActions.module.css new file mode 100644 index 0000000000..6a1102dd97 --- /dev/null +++ b/src/features/moderation/logs/ModlogItemMoreActions.module.css @@ -0,0 +1,11 @@ +.button { + composes: plainButton from "#/features/shared/shared.module.css"; + + &.button { + margin: -6px 0; /* prevent size from breaking line height */ + } +} + +.ellipsisIcon { + font-size: 1.2rem; +} diff --git a/src/features/moderation/logs/ModlogItemMoreActions.tsx b/src/features/moderation/logs/ModlogItemMoreActions.tsx index 3070686bad..1fca6be201 100644 --- a/src/features/moderation/logs/ModlogItemMoreActions.tsx +++ b/src/features/moderation/logs/ModlogItemMoreActions.tsx @@ -1,6 +1,4 @@ import { IonIcon, useIonActionSheet } from "@ionic/react"; -import { css } from "@linaria/core"; -import { styled } from "@linaria/react"; import { compact } from "es-toolkit"; import { ellipsisHorizontal, @@ -8,16 +6,13 @@ import { personOutline, } from "ionicons/icons"; -import { PlainButton } from "#/features/shared/PlainButton"; import { getHandle } from "#/helpers/lemmy"; import useAppNavigation from "#/helpers/useAppNavigation"; -import { ModeratorRole, getModIcon } from "../useCanModerate"; +import { getModIcon, ModeratorRole } from "../useCanModerate"; import { ModlogItemType } from "./helpers"; -const EllipsisIcon = styled(IonIcon)` - font-size: 1.2rem; -`; +import styles from "./ModlogItemMoreActions.module.css"; interface ModlogItemMoreActions { item: ModlogItemType; @@ -85,18 +80,15 @@ export default function ModlogItemMoreActions({ } return ( - - + { e.stopPropagation(); presentMoreActions(); }} /> - + ); } diff --git a/src/features/moderation/modSlice.tsx b/src/features/moderation/modSlice.tsx index 1a9be7bfcf..6ae5d4add5 100644 --- a/src/features/moderation/modSlice.tsx +++ b/src/features/moderation/modSlice.tsx @@ -1,4 +1,4 @@ -import { PayloadAction, createSelector, createSlice } from "@reduxjs/toolkit"; +import { createSelector, createSlice, PayloadAction } from "@reduxjs/toolkit"; import { isBefore, subSeconds } from "date-fns"; import { groupBy } from "es-toolkit"; import { CommentReport, PostReport } from "lemmy-js-client"; diff --git a/src/features/moderation/useCommentModActions.tsx b/src/features/moderation/useCommentModActions.tsx index b848bcb96b..58decec746 100644 --- a/src/features/moderation/useCommentModActions.tsx +++ b/src/features/moderation/useCommentModActions.tsx @@ -101,7 +101,7 @@ export default function useCommentModActions(commentView: CommentView) { icon: trashOutline, handler: () => { (async () => { - await dispatch(modRemoveComment(comment.id, true)); + await dispatch(modRemoveComment(comment, true)); presentToast(commentRemovedMod); })(); @@ -112,7 +112,7 @@ export default function useCommentModActions(commentView: CommentView) { icon: checkmarkCircleOutline, handler: () => { (async () => { - await dispatch(modRemoveComment(comment.id, false)); + await dispatch(modRemoveComment(comment, false)); presentToast(commentApproved); })(); @@ -130,9 +130,7 @@ export default function useCommentModActions(commentView: CommentView) { cssClass: "mod", handler: ({ reason }) => { (async () => { - await dispatch( - modRemoveComment(comment.id, true, reason), - ); + await dispatch(modRemoveComment(comment, true, reason)); presentToast(commentRemovedMod); })(); diff --git a/src/features/moderation/useModZoneActions.tsx b/src/features/moderation/useModZoneActions.tsx index 91396d6754..c401ffedc9 100644 --- a/src/features/moderation/useModZoneActions.tsx +++ b/src/features/moderation/useModZoneActions.tsx @@ -83,7 +83,7 @@ export default function useModZoneActions(props: UseModZoneActionsProps) { // icon: shieldCheckmarkOutline, // handler: () => { // (async () => { - // // await dispatch(modRemoveComment(comment.id, false)); + // // await dispatch(modRemoveComment(comment, false)); // // presentToast(commentApproved); // })(); // }, diff --git a/src/features/moderation/usePostModActions.tsx b/src/features/moderation/usePostModActions.tsx index 4cca8accca..062c34ceee 100644 --- a/src/features/moderation/usePostModActions.tsx +++ b/src/features/moderation/usePostModActions.tsx @@ -78,7 +78,7 @@ export default function usePostModActions(post: PostView) { icon: trashOutline, handler: () => { (async () => { - await dispatch(modRemovePost(post.post.id, true)); + await dispatch(modRemovePost(post.post, true)); presentToast(postRemovedMod); })(); @@ -89,7 +89,7 @@ export default function usePostModActions(post: PostView) { icon: checkmarkCircleOutline, handler: () => { (async () => { - await dispatch(modRemovePost(post.post.id, false)); + await dispatch(modRemovePost(post.post, false)); presentToast(postRestored); })(); @@ -107,7 +107,7 @@ export default function usePostModActions(post: PostView) { cssClass: "mod", handler: ({ reason }) => { (async () => { - await dispatch(modRemovePost(post.post.id, true, reason)); + await dispatch(modRemovePost(post.post, true, reason)); presentToast(postRemovedMod); })(); diff --git a/src/features/post/actions/ActionButton.module.css b/src/features/post/actions/ActionButton.module.css new file mode 100644 index 0000000000..bfb1b58e7e --- /dev/null +++ b/src/features/post/actions/ActionButton.module.css @@ -0,0 +1,13 @@ +.button { + display: flex; + align-items: center; + justify-content: center; + + background: inherit; + font-size: inherit; + color: inherit; + + padding: 0.35rem; + + border-radius: 8px; +} diff --git a/src/features/post/actions/ActionButton.tsx b/src/features/post/actions/ActionButton.tsx index 43083ca6ef..0d604742ac 100644 --- a/src/features/post/actions/ActionButton.tsx +++ b/src/features/post/actions/ActionButton.tsx @@ -1,15 +1,9 @@ -import { styled } from "@linaria/react"; +import { ButtonHTMLAttributes } from "react"; -export const ActionButton = styled.button` - display: flex; - align-items: center; - justify-content: center; +import { cx } from "#/helpers/css"; - background: inherit; - font-size: inherit; - color: inherit; +import styles from "./ActionButton.module.css"; - padding: 0.35rem; - - border-radius: 8px; -`; +export function ActionButton(props: ButtonHTMLAttributes) { + return
- -
+ + ); } diff --git a/src/features/share/asImage/ShareAsImage.module.css b/src/features/share/asImage/ShareAsImage.module.css new file mode 100644 index 0000000000..2038875cc0 --- /dev/null +++ b/src/features/share/asImage/ShareAsImage.module.css @@ -0,0 +1,81 @@ +.container { + --bottom-padding: max( + var(--ion-safe-area-bottom, env(safe-area-inset-bottom, 0)), + 16px + ); + + --top-space: 50px; + + @media (max-height: 650px) { + --top-space: 0px; + } + + display: grid; + grid-template-rows: max-content 1fr max-content; + + max-height: calc( + 100vh - var(--ion-safe-area-top, env(safe-area-inset-top, 0)) - + var(--top-space) + ); + + padding: 0 16px var(--bottom-padding); +} + +.sharedImg { + min-height: 0; + max-height: 100%; + justify-self: center; + max-width: 100%; + + filter: var(--share-img-drop-shadow); + + :global(.ios) & { + border-radius: 8px; + } + + :global(.md) & { + margin-top: 16px; + } +} + +.placeholderImg { + composes: sharedImg; + + background: white; + + :global(.ion-palette-dark) & { + background: black; + } + + height: 80px; + width: 80%; +} + +.previewImg { + composes: sharedImg; +} + +.list { + &:global(.list-ios.list-inset) { + margin-inline-start: 0; + margin-inline-end: 0; + } +} + +.parentCommentValues { + display: flex; + align-items: center; + gap: 16px; +} + +.commentSnapshotContainer { + background: var(--ion-item-background, var(--ion-background-color, #fff)); +} + +.postCommentSpacer { + height: 6px; +} + +.hideBottomBorder { + --inner-border-width: 0 0 0 0; +} diff --git a/src/features/share/asImage/ShareAsImage.tsx b/src/features/share/asImage/ShareAsImage.tsx index 46ab789b71..5ee3989bff 100644 --- a/src/features/share/asImage/ShareAsImage.tsx +++ b/src/features/share/asImage/ShareAsImage.tsx @@ -2,12 +2,10 @@ import { CapacitorHttp } from "@capacitor/core"; import { Directory, Filesystem } from "@capacitor/filesystem"; import { Share } from "@capacitor/share"; import { IonButton, IonItem, IonLabel, IonList, IonToggle } from "@ionic/react"; -import { css } from "@linaria/core"; -import { styled } from "@linaria/react"; -import { Options as DomToBlobOptions, domToBlob } from "modern-screenshot"; +import { domToBlob, Options as DomToBlobOptions } from "modern-screenshot"; import { - ReactNode, createContext, + ReactNode, useCallback, useEffect, useLayoutEffect, @@ -18,99 +16,19 @@ import { createPortal } from "react-dom"; import CommentTree from "#/features/comment/inTree/CommentTree"; import PostHeader from "#/features/post/detail/PostHeader"; import { blobToDataURL, blobToString } from "#/helpers/blob"; +import { cx } from "#/helpers/css"; import { isNative } from "#/helpers/device"; import { buildCommentsTree, getDepthFromComment } from "#/helpers/lemmy"; import useAppToast from "#/helpers/useAppToast"; import { getImageSrc } from "#/services/lemmy"; -import { webviewServerUrl } from "#/services/nativeFetch"; +import { getServerUrl } from "#/services/nativeFetch"; import AddRemoveButtons from "./AddRemoveButtons"; +import includeStyleProperties from "./includeStyleProperties"; import { ShareAsImageData } from "./ShareAsImageModal"; import Watermark from "./Watermark"; -import includeStyleProperties from "./includeStyleProperties"; - -const Container = styled.div` - --bottom-padding: max( - var(--ion-safe-area-bottom, env(safe-area-inset-bottom, 0)), - 16px - ); - - --top-space: 50px; - - @media (max-height: 650px) { - --top-space: 0px; - } - - display: grid; - grid-template-rows: max-content 1fr max-content; - - max-height: calc( - 100vh - var(--ion-safe-area-top, env(safe-area-inset-top, 0)) - var( - --top-space - ) - ); - - padding: 0 16px var(--bottom-padding); -`; - -const sharedImgCss = ` - min-height: 0; - max-height: 100%; - justify-self: center; - max-width: 100%; - - filter: var(--share-img-drop-shadow); - - .ios & { - border-radius: 8px; - } - - .md & { - margin-top: 16px; - } -`; - -const PlaceholderImg = styled.div` - ${sharedImgCss} - - background: white; - - .ion-palette-dark & { - background: black; - } - - height: 80px; - width: 80%; -`; - -const PreviewImg = styled.img` - ${sharedImgCss} -`; - -const StyledIonList = styled(IonList)` - &.list-ios.list-inset { - margin-inline-start: 0; - margin-inline-end: 0; - } -`; - -const ParentCommentValues = styled.div` - display: flex; - align-items: center; - gap: 16px; -`; - -const CommentSnapshotContainer = styled.div` - background: var(--ion-item-background, var(--ion-background-color, #fff)); -`; - -const PostCommentSpacer = styled.div` - height: 6px; -`; -const hideBottomBorderCss = css` - --inner-border-width: 0 0 0 0; -`; +import styles from "./ShareAsImage.module.css"; const domToBlobOptions: DomToBlobOptions = { scale: 4, @@ -127,7 +45,8 @@ const domToBlobOptions: DomToBlobOptions = { fetchFn: isNative() ? async (url) => { // Pass through relative URLs to browser fetching - if (url.startsWith(`${webviewServerUrl}/`)) { + // !: running in native environment + if (url.startsWith(`${getServerUrl!()}/`)) { return false; } @@ -280,12 +199,13 @@ export default function ShareAsImage({ data, header }: ShareAsImageProps) { } return ( - +
{header} {!imageSrc ? ( - +
) : ( - { @@ -306,7 +226,7 @@ export default function ShareAsImage({ data, header }: ShareAsImageProps) { /> )} - + {"comment" in data && ( <> @@ -331,7 +251,7 @@ export default function ShareAsImage({ data, header }: ShareAsImageProps) { {!!getDepthFromComment(data.comment.comment) && ( Parent Comments - +
{(getDepthFromComment(data.comment.comment) ?? 0) - minDepth} @@ -344,7 +264,7 @@ export default function ShareAsImage({ data, header }: ShareAsImageProps) { onAdd={() => setMinDepth((minDepth) => minDepth - 1)} onRemove={() => setMinDepth((minDepth) => minDepth + 1)} /> - +
)} @@ -375,19 +295,19 @@ export default function ShareAsImage({ data, header }: ShareAsImageProps) { Watermark
-
+ {isNative() || "canShare" in navigator ? "Share" : "Download"} {createPortal( - +
{includePostDetails && ( - {includePostDetails && } + {includePostDetails && ( +
+ )} {watermark && } - , +
, shareAsImageRenderRoot, )} - +
); } diff --git a/src/features/share/asImage/ShareAsImageModal.module.css b/src/features/share/asImage/ShareAsImageModal.module.css new file mode 100644 index 0000000000..6297e2393d --- /dev/null +++ b/src/features/share/asImage/ShareAsImageModal.module.css @@ -0,0 +1,3 @@ +.content { + background: var(--ion-background-color-step-50, #f2f2f7); +} diff --git a/src/features/share/asImage/ShareAsImageModal.tsx b/src/features/share/asImage/ShareAsImageModal.tsx index 7b17958253..a689455919 100644 --- a/src/features/share/asImage/ShareAsImageModal.tsx +++ b/src/features/share/asImage/ShareAsImageModal.tsx @@ -1,17 +1,21 @@ -import { IonButtons, IonIcon, IonTitle } from "@ionic/react"; -import { styled } from "@linaria/react"; +import { + IonButton, + IonButtons, + IonIcon, + IonTitle, + IonToolbar, +} from "@ionic/react"; import { close } from "ionicons/icons"; import { CommentView, PostView } from "lemmy-js-client"; import { MutableRefObject, useEffect, useState } from "react"; import AppHeader from "#/features/shared/AppHeader"; -import { - CloseButton, - TransparentIonToolbar, -} from "#/features/shared/selectorModals/GenericSelectorModal"; import ShareAsImage from "./ShareAsImage"; +import sharedStyles from "#/features/shared/shared.module.css"; +import styles from "./ShareAsImageModal.module.css"; + export type ShareAsImageData = | { post: PostView; @@ -27,10 +31,6 @@ interface SelectTextProps { onDismiss: () => void; } -const Content = styled.div` - background: var(--ion-background-color-step-50, #f2f2f7); -`; - export default function ShareAsImageModal({ dataRef, onDismiss, @@ -42,24 +42,28 @@ export default function ShareAsImageModal({ }, [dataRef]); return ( - +
{data && ( - + - onDismiss()}> + onDismiss()} + > - + Preview - + } /> )} - +
); } diff --git a/src/features/share/asImage/Watermark.module.css b/src/features/share/asImage/Watermark.module.css new file mode 100644 index 0000000000..31c197f517 --- /dev/null +++ b/src/features/share/asImage/Watermark.module.css @@ -0,0 +1,24 @@ +.container { + width: 100%; + font-size: 12px; + font-weight: 300; + padding: 0 8px 8px; + + display: flex; + align-items: center; + justify-content: flex-end; + gap: 8px; + + opacity: 0.6; + + color: var(--ion-item-color, var(--ion-text-color, #000)); +} + +.text { + opacity: 0.5; +} + +.logoImg { + border-radius: 4px; + width: 25px; +} diff --git a/src/features/share/asImage/Watermark.tsx b/src/features/share/asImage/Watermark.tsx index 4aaf909acf..4320f2a82e 100644 --- a/src/features/share/asImage/Watermark.tsx +++ b/src/features/share/asImage/Watermark.tsx @@ -1,35 +1,10 @@ -import { styled } from "@linaria/react"; - -const Container = styled.div` - width: 100%; - font-size: 12px; - font-weight: 300; - padding: 0 8px 8px; - - display: flex; - align-items: center; - justify-content: flex-end; - gap: 8px; - - opacity: 0.6; - - color: var(--ion-item-color, var(--ion-text-color, #000)); -`; - -const Text = styled.div` - opacity: 0.5; -`; - -const LogoImg = styled.img` - border-radius: 4px; - width: 25px; -`; +import styles from "./Watermark.module.css"; export default function Watermark() { return ( - - Voyager for Lemmy - - +
+
Voyager for Lemmy
+ +
); } diff --git a/src/features/shared/AppContent.tsx b/src/features/shared/AppContent.tsx index 5e956dde6e..753652237a 100644 --- a/src/features/shared/AppContent.tsx +++ b/src/features/shared/AppContent.tsx @@ -1,16 +1,14 @@ import { IonContent } from "@ionic/react"; -import { styled } from "@linaria/react"; -export const maxWidthCss = ` - width: 100%; - max-width: 700px; - margin-right: auto; - margin-left: auto; -`; +import { cx } from "#/helpers/css"; -export const MaxWidthContainer = styled.div` - ${maxWidthCss} -`; +import sharedStyles from "./shared.module.css"; + +export function MaxWidthContainer(props: React.HTMLAttributes) { + return ( +
+ ); +} export default function AppContent({ children, diff --git a/src/features/shared/CenteredSpinner.module.css b/src/features/shared/CenteredSpinner.module.css new file mode 100644 index 0000000000..2663cbd30b --- /dev/null +++ b/src/features/shared/CenteredSpinner.module.css @@ -0,0 +1,6 @@ +.centeredSpinner { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); +} diff --git a/src/features/shared/CenteredSpinner.tsx b/src/features/shared/CenteredSpinner.tsx index e3998f04b6..bedb5a312c 100644 --- a/src/features/shared/CenteredSpinner.tsx +++ b/src/features/shared/CenteredSpinner.tsx @@ -1,9 +1,16 @@ import { IonSpinner } from "@ionic/react"; -import { styled } from "@linaria/react"; -export const CenteredSpinner = styled(IonSpinner)` - position: absolute; - left: 50%; - top: 50%; - transform: translate(-50%, -50%); -`; +import { cx } from "#/helpers/css"; + +import styles from "./CenteredSpinner.module.css"; + +export function CenteredSpinner( + props: React.ComponentProps, +) { + return ( + + ); +} diff --git a/src/features/shared/DynamicDismissableModal.tsx b/src/features/shared/DynamicDismissableModal.tsx index febfef63f8..8932875ddb 100644 --- a/src/features/shared/DynamicDismissableModal.tsx +++ b/src/features/shared/DynamicDismissableModal.tsx @@ -9,8 +9,8 @@ import React, { } from "react"; import { Prompt, useLocation } from "react-router"; -import { PageContext } from "#/features/auth/PageContext"; import { instanceSelector } from "#/features/auth/authSelectors"; +import { PageContext } from "#/features/auth/PageContext"; import { isNative } from "#/helpers/device"; import useStateRef from "#/helpers/useStateRef"; import { clearRecoveredText } from "#/helpers/useTextRecovery"; diff --git a/src/features/shared/FakeIcon.module.css b/src/features/shared/FakeIcon.module.css new file mode 100644 index 0000000000..2af48be919 --- /dev/null +++ b/src/features/shared/FakeIcon.module.css @@ -0,0 +1,9 @@ +.container { + border-radius: 50%; + + display: inline-flex; + align-items: center; + justify-content: center; + + color: white; +} diff --git a/src/features/shared/FakeIcon.tsx b/src/features/shared/FakeIcon.tsx index ccba35a9b1..479e34e906 100644 --- a/src/features/shared/FakeIcon.tsx +++ b/src/features/shared/FakeIcon.tsx @@ -1,17 +1,6 @@ -import { styled } from "@linaria/react"; +import { cx } from "#/helpers/css"; -const FakeIconContainer = styled.div<{ bg: string; size: number }>` - width: ${({ size }) => size}px; - height: ${({ size }) => size}px; - border-radius: 50%; - - display: inline-flex; - align-items: center; - justify-content: center; - - background-color: ${({ bg }) => bg}; - color: white; -`; +import styles from "./FakeIcon.module.css"; interface FakeIconProps { seed: string | number; @@ -28,15 +17,20 @@ export default function FakeIcon({ name, slot, }: FakeIconProps) { + const cssSize = `${size ?? 20}px`; + return ( - {name.slice(0, 1).toUpperCase()} - +
); } diff --git a/src/features/shared/IonModalAutosizedForOnScreenKeyboard.module.css b/src/features/shared/IonModalAutosizedForOnScreenKeyboard.module.css new file mode 100644 index 0000000000..7840beafd3 --- /dev/null +++ b/src/features/shared/IonModalAutosizedForOnScreenKeyboard.module.css @@ -0,0 +1,10 @@ +.pwaIonModal { + /* Capacitor inside native web view resizes for on-screen keyboard, so we don't need bespoke layout management */ + ion-content::part(scroll) { + max-height: calc(var(--sv-viewportHeight) * 1px); + } + + ion-content .fixedToolbarContainer { + max-height: calc(var(--sv-viewportHeight) * 1px); + } +} diff --git a/src/features/shared/IonModalAutosizedForOnScreenKeyboard.tsx b/src/features/shared/IonModalAutosizedForOnScreenKeyboard.tsx index 3b153c9afb..81d5920b5f 100644 --- a/src/features/shared/IonModalAutosizedForOnScreenKeyboard.tsx +++ b/src/features/shared/IonModalAutosizedForOnScreenKeyboard.tsx @@ -1,33 +1,39 @@ import { IonModal } from "@ionic/react"; -import { styled } from "@linaria/react"; import { useDocumentVisibility } from "@mantine/hooks"; import React, { useCallback, useEffect, useRef, useState } from "react"; +import { cx, sv } from "#/helpers/css"; import { isNative } from "#/helpers/device"; +import styles from "./IonModalAutosizedForOnScreenKeyboard.module.css"; + // TODO it's a bit buggy trying to compute this // in realtime with the new post dialog + comment dialogs // So hardcode for now const FIXED_HEADER_HEIGHT = 56; -const StyledIonModal = styled(IonModal)<{ viewportHeight: number }>` - /* Capacitor inside native web view resizes for on-screen keyboard, so we don't need bespoke layout management */ - ion-content::part(scroll) { - max-height: ${({ viewportHeight }) => viewportHeight}px; - } +interface PWAIonModalProps + extends Omit, "style"> { + viewportHeight: number; +} - ion-content .fixed-toolbar-container { - max-height: ${({ viewportHeight }) => viewportHeight}px; - } -`; +function PWAIonModal({ viewportHeight, ...props }: PWAIonModalProps) { + return ( + + ); +} -const Modal = isNative() ? IonModal : StyledIonModal; +const Modal = isNative() ? IonModal : PWAIonModal; /** * This component is only needed for Safari PWAs. It is not necessary for native. */ export default function IonModalAutosizedForOnScreenKeyboard( - props: React.ComponentProps, + props: Omit, "style">, ) { const [viewportHeight, setViewportHeight] = useState( document.documentElement.clientHeight, diff --git a/src/features/shared/ListEditor.module.css b/src/features/shared/ListEditor.module.css new file mode 100644 index 0000000000..dd7c89887d --- /dev/null +++ b/src/features/shared/ListEditor.module.css @@ -0,0 +1,13 @@ +.removeIcon { + position: relative; + font-size: 1.6rem; + + &:after { + z-index: -1; + content: ""; + position: absolute; + inset: 5px; + border-radius: 50%; + background: white; + } +} diff --git a/src/features/shared/ListEditor.tsx b/src/features/shared/ListEditor.tsx index 1746add482..0905bbcf47 100644 --- a/src/features/shared/ListEditor.tsx +++ b/src/features/shared/ListEditor.tsx @@ -1,11 +1,12 @@ import { IonButton, IonIcon } from "@ionic/react"; -import { styled } from "@linaria/react"; import { noop } from "es-toolkit"; import { checkmark, ellipsisVertical, removeCircle } from "ionicons/icons"; import React, { createContext, useContext, useRef, useState } from "react"; import { isIosTheme } from "#/helpers/device"; +import styles from "./ListEditor.module.css"; + export function ListEditorProvider({ children }: React.PropsWithChildren) { const [editing, setEditing] = useState(false); @@ -56,20 +57,6 @@ export function ListEditButton() { ); } -const RemoveIcon = styled(IonIcon)` - position: relative; - font-size: 1.6rem; - - &:after { - z-index: -1; - content: ""; - position: absolute; - inset: 5px; - border-radius: 50%; - background: white; - } -`; - export function RemoveItemButton() { const { editing } = useContext(ListEditorContext); const ref = useRef(null); @@ -90,7 +77,12 @@ export function RemoveItemButton() { slider.open("end"); }} > - + ); } diff --git a/src/features/shared/MultilineTitle.module.css b/src/features/shared/MultilineTitle.module.css new file mode 100644 index 0000000000..3d2c2ce1e9 --- /dev/null +++ b/src/features/shared/MultilineTitle.module.css @@ -0,0 +1,23 @@ +.multilineTitle { + display: flex; + align-items: center; + gap: 0.5rem; + line-height: 1; + + :global(.ios) & { + justify-content: center; + } + + ion-spinner { + flex-shrink: 0; + } +} + +.subheaderText { + font-size: 0.7em; + font-weight: normal; +} + +.titleContainer { + line-height: 1; +} diff --git a/src/features/shared/MultilineTitle.tsx b/src/features/shared/MultilineTitle.tsx new file mode 100644 index 0000000000..c306e566cb --- /dev/null +++ b/src/features/shared/MultilineTitle.tsx @@ -0,0 +1,29 @@ +import { IonText, IonTitle } from "@ionic/react"; + +import styles from "./MultilineTitle.module.css"; + +interface MultilineTitleProps + extends Omit, "className"> { + subheader?: string; +} + +export default function MultilineTitle({ + subheader, + children, + ...props +}: MultilineTitleProps) { + return ( + +
+
+ {children} +
+ + {subheader} + +
+
+
+
+ ); +} diff --git a/src/features/shared/PlainButton.tsx b/src/features/shared/PlainButton.tsx deleted file mode 100644 index 254ca58ed2..0000000000 --- a/src/features/shared/PlainButton.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { styled } from "@linaria/react"; - -// https://gist.github.com/MoOx/9137295 -export const PlainButton = styled.button` - border: none; - margin: 0; - padding: 0; - width: auto; - overflow: visible; - - background: transparent; - - /* inherit font & color from ancestor */ - color: inherit; - font: inherit; - - /* Normalize line-height. Cannot be changed from normal in Firefox 4+. */ - line-height: normal; - - /* Corrects font smoothing for webkit */ - -webkit-font-smoothing: inherit; - -moz-osx-font-smoothing: inherit; - - /* Corrects inability to style clickable input types in iOS */ - -webkit-appearance: none; - appearance: none; - - display: inline-flex; -`; diff --git a/src/features/shared/SelectTextModal.module.css b/src/features/shared/SelectTextModal.module.css new file mode 100644 index 0000000000..b047222da8 --- /dev/null +++ b/src/features/shared/SelectTextModal.module.css @@ -0,0 +1,37 @@ +.container { + min-height: 100%; + + display: flex; + + html:global(.ios:not(.ion-palette-dark)) & { + background: var(--ion-item-background); + } +} + +.sharedSelect { + /* Override `all: unset` specificity by setting default below .invisibleTextarea */ +} + +.invisibleTextarea { + composes: sharedSelect; + + all: unset; + white-space: pre-wrap; + width: 100%; +} + +.selectable { + composes: sharedSelect; + + user-select: text; + white-space: pre-wrap; +} + +.sharedSelect { + padding: 8px; + width: calc(100% - 16px); + + user-select: text; + + margin-bottom: var(--ion-safe-area-bottom, env(safe-area-inset-bottom)); +} diff --git a/src/features/shared/SelectTextModal.tsx b/src/features/shared/SelectTextModal.tsx index ef5d0a9078..2467af0048 100644 --- a/src/features/shared/SelectTextModal.tsx +++ b/src/features/shared/SelectTextModal.tsx @@ -7,12 +7,10 @@ import { IonTitle, IonToolbar, } from "@ionic/react"; -import { styled } from "@linaria/react"; import { copyOutline } from "ionicons/icons"; import { useRef } from "react"; import TextareaAutosize from "react-textarea-autosize"; -import { Centered } from "#/features/auth/login/LoginNav"; import { isTouchDevice } from "#/helpers/device"; import { preventModalSwipeOnTextSelection } from "#/helpers/ionic"; import { @@ -23,39 +21,7 @@ import useAppToast from "#/helpers/useAppToast"; import AppHeader from "./AppHeader"; -const Container = styled.div` - min-height: 100%; - - display: flex; - - html.ios:not(.ion-palette-dark) & { - background: var(--ion-item-background); - } -`; - -const sharedSelectStyles = ` - padding: 8px; - width: calc(100% - 16px); - - user-select: text; - - margin-bottom: var(--ion-safe-area-bottom, env(safe-area-inset-bottom)); -`; - -const InvisibleTextarea = styled(TextareaAutosize)` - all: unset; - white-space: pre-wrap; - width: 100%; - - ${sharedSelectStyles} -`; - -const Selectable = styled.div` - user-select: text; - white-space: pre-wrap; - - ${sharedSelectStyles} -`; +import styles from "./SelectTextModal.module.css"; interface SelectTextProps { text: string; @@ -103,9 +69,7 @@ export default function SelectTextModal({ - - Select Text - + Select Text { @@ -118,13 +82,17 @@ export default function SelectTextModal({ - +
{touch ? ( - +
{text} - +
) : ( - e.stopPropagation()} onClick={() => { @@ -145,7 +113,7 @@ export default function SelectTextModal({ value={text} /> )} - +
); diff --git a/src/features/shared/Url.tsx b/src/features/shared/Url.tsx index bf452443fe..7c71cc0e42 100644 --- a/src/features/shared/Url.tsx +++ b/src/features/shared/Url.tsx @@ -1,11 +1,5 @@ -import { styled } from "@linaria/react"; - import { parseUrlForDisplay } from "#/helpers/url"; -const Rest = styled.span` - opacity: 0.6; -`; - interface UrlProps { children: string; } @@ -18,7 +12,7 @@ export default function Url({ children }: UrlProps) { return ( <> {domain} - {rest !== "/" ? {rest} : ""} + {rest !== "/" ? {rest} : ""} ); } diff --git a/src/features/shared/animations.ts b/src/features/shared/animations.ts deleted file mode 100644 index 7630c90ac0..0000000000 --- a/src/features/shared/animations.ts +++ /dev/null @@ -1,29 +0,0 @@ -const bounceName = "bounce"; - -const bounce = ` - @keyframes ${bounceName} { - 0% { - transform: scale(1); - } - 50% { - transform: scale(1.25); - } - 100% { - transform: scale(1); - } - } -`; - -export const bounceMs = 175; - -export const bounceAnimation = ` - ${bounce} - - animation: ${bounceName} ${bounceMs}ms linear; -`; - -export const bounceAnimationOnTransition = ` - &.entering { - ${bounceAnimation} - } -`; diff --git a/src/features/shared/bounce.module.css b/src/features/shared/bounce.module.css new file mode 100644 index 0000000000..ac7a169165 --- /dev/null +++ b/src/features/shared/bounce.module.css @@ -0,0 +1,15 @@ +.bounce { + animation: bounce 175ms linear; +} + +@keyframes bounce { + 0% { + transform: scale(1); + } + 50% { + transform: scale(1.25); + } + 100% { + transform: scale(1); + } +} diff --git a/src/features/shared/markdown/LinkInterceptor.module.css b/src/features/shared/markdown/LinkInterceptor.module.css new file mode 100644 index 0000000000..fcbc572fbd --- /dev/null +++ b/src/features/shared/markdown/LinkInterceptor.module.css @@ -0,0 +1,3 @@ +.link { + -webkit-touch-callout: default; +} diff --git a/src/features/shared/markdown/LinkInterceptor.tsx b/src/features/shared/markdown/LinkInterceptor.tsx index 24bc19fb1a..35a421bf44 100644 --- a/src/features/shared/markdown/LinkInterceptor.tsx +++ b/src/features/shared/markdown/LinkInterceptor.tsx @@ -1,15 +1,13 @@ -import { styled } from "@linaria/react"; import React from "react"; +import { cx } from "#/helpers/css"; import { buildBaseLemmyUrl } from "#/services/lemmy"; import { useAppSelector } from "#/store"; import InAppExternalLink, { AdditionalLinkProps } from "../InAppExternalLink"; import useLemmyUrlHandler from "../useLemmyUrlHandler"; -const LinkInterceptor = styled(LinkInterceptorUnstyled)` - -webkit-touch-callout: default; -`; +import styles from "./LinkInterceptor.module.css"; type LinkInterceptorUnstyledProps = React.JSX.IntrinsicElements["a"] & { el?: "div"; @@ -21,7 +19,7 @@ type LinkInterceptorUnstyledProps = React.JSX.IntrinsicElements["a"] & { forceResolveObject?: boolean; } & AdditionalLinkProps; -function LinkInterceptorUnstyled({ +export default function LinkInterceptor({ onClick: _onClick, onClickCompleted, forceResolveObject, @@ -58,6 +56,7 @@ function LinkInterceptorUnstyled({ return ( ); } - -export default LinkInterceptor; diff --git a/src/features/shared/markdown/Markdown.module.css b/src/features/shared/markdown/Markdown.module.css new file mode 100644 index 0000000000..386037079a --- /dev/null +++ b/src/features/shared/markdown/Markdown.module.css @@ -0,0 +1,52 @@ +.markdown { + @media (max-width: 700px) { + ul, + ol { + padding-left: 28px; + } + } + + code { + white-space: pre-wrap; + } + + code:not(:global(.hljs)) { + background: var(--lightroom-bg); + border-radius: 4px; + padding: 1px 3px; + color: rgba(var(--ion-color-dark-rgb), 0.9); + } + + pre { + background: var(--lightroom-bg); + padding: 8px; + border-radius: 8px; + font-size: 0.9375em; + } + + blockquote { + padding-left: 0.5rem; + border-left: 3px solid + var(--ion-border-color, var(--ion-background-color-step-250, #c8c7cc)); + margin-left: 0; + } + + hr { + background-color: var( + --ion-border-color, + var(--ion-background-color-step-250, #c8c7cc) + ); + + min-width: min(100%, 100px); + width: 80%; + + height: 2px; + } + + ol, + ul { + li > p:first-child:last-child { + margin: 0; + } + } +} diff --git a/src/features/shared/markdown/Markdown.tsx b/src/features/shared/markdown/Markdown.tsx index f874639f6c..cc20c0534d 100644 --- a/src/features/shared/markdown/Markdown.tsx +++ b/src/features/shared/markdown/Markdown.tsx @@ -1,71 +1,20 @@ import spoiler from "@aeharding/remark-lemmy-spoiler"; -import { css, cx } from "@linaria/core"; import ReactMarkdown, { Options as ReactMarkdownOptions } from "react-markdown"; import rehypeHighlight from "rehype-highlight"; import superSub from "remark-supersub-lemmy"; +import { cx } from "#/helpers/css"; import { useAppSelector } from "#/store"; import InAppExternalLink from "../InAppExternalLink"; -import LinkInterceptor from "./LinkInterceptor"; -import MarkdownImg from "./MarkdownImg"; -import Table from "./components/Table"; import Details from "./components/spoiler/Details"; import Summary from "./components/spoiler/Summary"; +import Table from "./components/Table"; import customRemarkGfm from "./customRemarkGfm"; +import LinkInterceptor from "./LinkInterceptor"; +import MarkdownImg from "./MarkdownImg"; -const markdownCss = css` - @media (max-width: 700px) { - ul, - ol { - padding-left: 28px; - } - } - - code { - white-space: pre-wrap; - } - - code:not(.hljs) { - background: var(--lightroom-bg); - border-radius: 4px; - padding: 1px 3px; - color: rgba(var(--ion-color-dark-rgb), 0.9); - } - - pre { - background: var(--lightroom-bg); - padding: 8px; - border-radius: 8px; - font-size: 0.9375em; - } - - blockquote { - padding-left: 0.5rem; - border-left: 3px solid - var(--ion-border-color, var(--ion-background-color-step-250, #c8c7cc)); - margin-left: 0; - } - - hr { - background-color: var( - --ion-border-color, - var(--ion-background-color-step-250, #c8c7cc) - ); - - min-width: min(100%, 100px); - width: 80%; - - height: 2px; - } - - ol, - ul { - li > p:first-child:last-child { - margin: 0; - } - } -`; +import styles from "./Markdown.module.css"; // TODO - remove never when upgrading to rehypeHighlight v7 // TODO - ignoreMissing not needed in v7 @@ -101,7 +50,7 @@ export default function Markdown({ return ( ( e.stopPropagation()} /> diff --git a/src/features/shared/markdown/MarkdownImg.module.css b/src/features/shared/markdown/MarkdownImg.module.css new file mode 100644 index 0000000000..0137272b03 --- /dev/null +++ b/src/features/shared/markdown/MarkdownImg.module.css @@ -0,0 +1,13 @@ +.small { + max-height: 200px; +} + +.media { + display: inline-flex; + vertical-align: middle; + + &:global(.not-loaded) { + height: 200px; + border: 1px solid rgba(var(--ion-color-dark-rgb), 0.15); + } +} diff --git a/src/features/shared/markdown/MarkdownImg.tsx b/src/features/shared/markdown/MarkdownImg.tsx index 4d20fbbccf..46f5ac1388 100644 --- a/src/features/shared/markdown/MarkdownImg.tsx +++ b/src/features/shared/markdown/MarkdownImg.tsx @@ -1,21 +1,8 @@ -import { css, cx } from "@linaria/core"; - -import InlineMedia from "#/features/media/InlineMedia"; import { GalleryMediaProps } from "#/features/media/gallery/GalleryMedia"; +import InlineMedia from "#/features/media/InlineMedia"; +import { cx } from "#/helpers/css"; -const smallStyles = css` - max-height: 200px; -`; - -const mediaStyles = css` - display: inline-flex; - vertical-align: middle; - - &.not-loaded { - height: 200px; - border: 1px solid rgba(var(--ion-color-dark-rgb), 0.15); - } -`; +import styles from "./MarkdownImg.module.css"; interface MarkdownImgProps extends Omit { /** @@ -29,7 +16,7 @@ export default function MarkdownImg({ src, ...props }: MarkdownImgProps) { - const sharedStyles = small ? smallStyles : undefined; + const sharedStyles = small ? styles.small : undefined; if (!src) return; @@ -38,7 +25,7 @@ export default function MarkdownImg({ {...props} src={src} mediaClassName={cx(sharedStyles, props.className)} - className={mediaStyles} + className={styles.media} animationType="zoom" progress={false} volume={false} diff --git a/src/features/shared/markdown/components/Table.module.css b/src/features/shared/markdown/components/Table.module.css new file mode 100644 index 0000000000..ff098871cf --- /dev/null +++ b/src/features/shared/markdown/components/Table.module.css @@ -0,0 +1,30 @@ +.tableContainer { + display: flex; + overflow-x: auto; + margin: 15px -1rem; + padding: 0 1rem; + max-width: calc(100% + 2rem); + + tbody { + border-collapse: collapse; + } + td, + th { + padding: 4px 6px; + } + td { + border: 1px solid var(--ion-color-light); + } + tr:first-child td { + border-top: 0; + } + tr td:first-child { + border-left: 0; + } + tr:last-child td { + border-bottom: 0; + } + tr td:last-child { + border-right: 0; + } +} diff --git a/src/features/shared/markdown/components/Table.tsx b/src/features/shared/markdown/components/Table.tsx index 6d6f3a1766..a063423452 100644 --- a/src/features/shared/markdown/components/Table.tsx +++ b/src/features/shared/markdown/components/Table.tsx @@ -1,37 +1,7 @@ -import { styled } from "@linaria/react"; import { useRef } from "react"; import { ExtraProps } from "react-markdown"; -const TableContainer = styled.div` - display: flex; - overflow-x: auto; - margin: 15px -1rem; - padding: 0 1rem; - max-width: calc(100% + 2rem); - - tbody { - border-collapse: collapse; - } - td, - th { - padding: 4px 6px; - } - td { - border: 1px solid var(--ion-color-light); - } - tr:first-child td { - border-top: 0; - } - tr td:first-child { - border-left: 0; - } - tr:last-child td { - border-bottom: 0; - } - tr td:last-child { - border-right: 0; - } -`; +import styles from "./Table.module.css"; export default function Table( props: JSX.IntrinsicElements["table"] & ExtraProps, @@ -39,7 +9,7 @@ export default function Table( const tableContainerRef = useRef(null); return ( - +
- + ); } diff --git a/src/features/shared/markdown/components/spoiler/Details.module.css b/src/features/shared/markdown/components/spoiler/Details.module.css new file mode 100644 index 0000000000..a1c6f0c6f2 --- /dev/null +++ b/src/features/shared/markdown/components/spoiler/Details.module.css @@ -0,0 +1,40 @@ +.accordionGroup { + margin: 1em -12px; +} + +.headerItem { + --padding-start: 12px; + --padding-end: 12px; + --inner-padding-end: 0; + --inner-padding-start: 0; + + font-size: inherit; + font-weight: 600; + + --background: none; + --background-hover: none; + + strong { + /* Differentiate from already bold title in header */ + font-weight: 900; + } +} + +.accordion { + background: none; + + [slot="content"] { + padding: 1em 12px; + + background: transparent; + + img { + max-height: none; + } + } + + :global(.ion-accordion-toggle-icon) { + color: var(--ion-color-medium2); + font-size: 1.45em; + } +} diff --git a/src/features/shared/markdown/components/spoiler/Details.tsx b/src/features/shared/markdown/components/spoiler/Details.tsx index 115ff500b9..9ebd3877af 100644 --- a/src/features/shared/markdown/components/spoiler/Details.tsx +++ b/src/features/shared/markdown/components/spoiler/Details.tsx @@ -1,5 +1,4 @@ import { IonAccordion, IonAccordionGroup, IonItem } from "@ionic/react"; -import { styled } from "@linaria/react"; import { noop } from "es-toolkit"; import { ComponentProps, @@ -14,46 +13,7 @@ import store, { useAppDispatch } from "#/store"; import { getSpoilerId, updateSpoilerState } from "./spoilerSlice"; -const StyledIonAccordionGroup = styled(IonAccordionGroup)` - margin: 1em -12px; -`; - -const HeaderItem = styled(IonItem)` - --padding-start: 12px; - --padding-end: 12px; - --inner-padding-end: 0; - --inner-padding-start: 0; - - font-size: inherit; - font-weight: 600; - - --background: none; - --background-hover: none; - - strong { - // Differentiate from already bold title in header - font-weight: 900; - } -`; - -const StyledIonAccordion = styled(IonAccordion)` - background: none; - - [slot="content"] { - padding: 1em 12px; - - background: transparent; - - img { - max-height: none; - } - } - - .ion-accordion-toggle-icon { - color: var(--ion-color-medium2); - font-size: 1.45em; - } -`; +import styles from "./Details.module.css"; type DetailsProps = JSX.IntrinsicElements["details"] & ExtraProps & { @@ -87,16 +47,24 @@ export default function Details({ children, node, id }: DetailsProps) { return ( - - - e.stopPropagation()}> + + + e.stopPropagation()} + >
{label}
-
+
{children}
-
-
+ +
); } diff --git a/src/features/shared/markdown/components/spoiler/spoilerSlice.ts b/src/features/shared/markdown/components/spoiler/spoilerSlice.ts index 2572d51666..4c78915cc0 100644 --- a/src/features/shared/markdown/components/spoiler/spoilerSlice.ts +++ b/src/features/shared/markdown/components/spoiler/spoilerSlice.ts @@ -1,4 +1,4 @@ -import { PayloadAction, createSlice } from "@reduxjs/toolkit"; +import { createSlice, PayloadAction } from "@reduxjs/toolkit"; import type { ExtraProps } from "react-markdown"; interface NetworkState { diff --git a/src/features/shared/markdown/editing/Editor.module.css b/src/features/shared/markdown/editing/Editor.module.css new file mode 100644 index 0000000000..1e32f632cc --- /dev/null +++ b/src/features/shared/markdown/editing/Editor.module.css @@ -0,0 +1,35 @@ +.container { + min-height: 100%; + + display: flex; + flex-direction: column; + + padding-bottom: var(--markdown-toolbar-height); + + html:global(.ios:not(.ion-palette-dark)) & { + background: var(--ion-item-background); + } + + @media screen and (max-width: 767px) { + padding-bottom: calc( + var(--markdown-toolbar-height) + + var(--ion-safe-area-bottom, env(safe-area-inset-bottom)) + ); + + &.keyboardOpen { + padding-bottom: var(--markdown-toolbar-height); + } + } +} + +.textarea { + border: 0; + background: none; + resize: none; + outline: 0; + padding: 16px; + + min-height: 200px; + + flex: 1 0 auto; +} diff --git a/src/features/shared/markdown/editing/Editor.tsx b/src/features/shared/markdown/editing/Editor.tsx index 939756867c..92e582db72 100644 --- a/src/features/shared/markdown/editing/Editor.tsx +++ b/src/features/shared/markdown/editing/Editor.tsx @@ -1,4 +1,3 @@ -import { styled } from "@linaria/react"; import { useMergedRef } from "@mantine/hooks"; import { ClipboardEvent, @@ -10,54 +9,22 @@ import { useRef, } from "react"; +import { cx } from "#/helpers/css"; import { preventModalSwipeOnTextSelection } from "#/helpers/ionic"; import { htmlToMarkdown } from "#/helpers/markdown"; import useKeyboardOpen from "#/helpers/useKeyboardOpen"; import useTextRecovery from "#/helpers/useTextRecovery"; import TextareaAutosizedForOnScreenKeyboard from "../../TextareaAutosizedForOnScreenKeyboard"; -import MarkdownToolbar, { - TOOLBAR_HEIGHT, - TOOLBAR_TARGET_ID, -} from "./MarkdownToolbar"; +import MarkdownToolbar, { TOOLBAR_TARGET_ID } from "./MarkdownToolbar"; import useEditorHelpers from "./useEditorHelpers"; import useUploadImage from "./useUploadImage"; +import styles from "./Editor.module.css"; + const ORDERED_LIST_REGEX = /^(\d)\. /; const UNORDERED_LIST_REGEX = /^(-|\*|\+) /; -export const Container = styled.div<{ keyboardOpen: boolean }>` - min-height: 100%; - - display: flex; - flex-direction: column; - - padding-bottom: ${TOOLBAR_HEIGHT}; - - html.ios:not(.ion-palette-dark) & { - background: var(--ion-item-background); - } - - @media screen and (max-width: 767px) { - padding-bottom: ${({ keyboardOpen }) => - keyboardOpen - ? TOOLBAR_HEIGHT - : `calc(${TOOLBAR_HEIGHT} + var(--ion-safe-area-bottom, env(safe-area-inset-bottom)))`}; - } -`; - -export const Textarea = styled(TextareaAutosizedForOnScreenKeyboard)` - border: 0; - background: none; - resize: none; - outline: 0; - padding: 16px; - - min-height: 200px; - - flex: 1 0 auto; -`; - export interface EditorProps { text: string; setText: Dispatch>; @@ -205,9 +172,12 @@ export default function Editor({ return ( <> {uploadImageJsx} - -