Command Palette (#2228)

* bring it back

* move into folder

* fix shortcuts colliding

* tags

* fix key capture problems

* add 2 more actions + locations to cmd

* fix search navigation issue W @nikec

* fix saerch input

* improve scrollbar look and text on lightheme + fix edge view search showing

* useShortcut

* add cmdp to keybinds page

* killer i18n extension for vscode

* some missing keys and localized cmdk

* in lists that can change - it's better to use the id rather than index to avoid extra re-renders

* Update CMDKLocations.tsx

---------

Co-authored-by: ameer2468 <33054370+ameer2468@users.noreply.github.com>
This commit is contained in:
Utku 2024-03-26 09:05:46 -04:00 committed by GitHub
parent 94ca18925d
commit 6277c8cb5f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
37 changed files with 5548 additions and 3980 deletions

View file

@ -7,6 +7,7 @@
"bradlc.vscode-tailwindcss", // Provides Tailwind CSS IntelliSense
"prisma.prisma", // Prisma is an open-source database toolkit
"dbaeumer.vscode-eslint", // Integrates ESLint JavaScript into VS Code
"esbenp.prettier-vscode" // Code formatter using prettier
"esbenp.prettier-vscode", // Code formatter using prettier,
"lokalise.i18n-ally" // i18n-ally is an all-in-one i18n (internationalization) extension for VS Code
]
}

16
.vscode/settings.json vendored
View file

@ -88,5 +88,19 @@
"rust-analyzer.linkedProjects": [],
"rust-analyzer.cargo.extraEnv": {},
"rust-analyzer.check.targets": null,
"rust-analyzer.showUnlinkedFileNotification": false
"rust-analyzer.showUnlinkedFileNotification": false,
"i18n-ally.localesPaths": [
"interface/locales",
"apps/mobile/ios/Pods/RCT-Folly/folly/lang",
"apps/mobile/ios/Pods/boost/boost/locale",
"apps/mobile/ios/Pods/boost/boost/predef/language"
],
"i18n-ally.enabledParsers": ["ts", "json"],
// "i18n-ally.sortKeys": true,
"i18n-ally.namespace": true,
"i18n-ally.pathMatcher": "{locale}/common.json",
"i18n-ally.enabledFrameworks": ["react"],
"i18n-ally.keystyle": "flat",
// You need to add this to your locale settings file "i18n-ally.translate.google.apiKey": "xxx"
"i18n-ally.translate.engines": ["google"]
}

View file

@ -23,7 +23,7 @@ const FileItem = ({ data }: FileItemProps) => {
})}
>
<FileThumb data={data} />
<View style={tw`mt-1 px-1.5 py-[1px]`}>
<View style={tw`mt-1 px-1.5 py-px`}>
<Text numberOfLines={1} style={tw`text-center text-xs font-medium text-white`}>
{filePath?.name}
{filePath?.extension && `.${filePath.extension}`}

View file

@ -47,6 +47,7 @@ import ExplorerContextMenu, {
import { Conditional } from '../ContextMenu/ConditionalItem';
import { FileThumb } from '../FilePath/Thumb';
import { SingleItemMetadata } from '../Inspector';
import { explorerStore } from '../store';
import { ImageSlider } from './ImageSlider';
import { getQuickPreviewStore, useQuickPreviewStore } from './store';
@ -194,6 +195,7 @@ export const QuickPreview = () => {
//close quick preview
useShortcut('closeQuickPreview', (e) => {
if (explorerStore.isCMDPOpen) return;
e.preventDefault();
getQuickPreviewStore().open = false;
});

View file

@ -15,6 +15,7 @@ import { isNonEmptyObject } from '~/util';
import { useLayoutContext } from '../../../Layout/Context';
import { useExplorerContext } from '../../Context';
import { getQuickPreviewStore, useQuickPreviewStore } from '../../QuickPreview/store';
import { explorerStore } from '../../store';
import { uniqueId } from '../../util';
import { useExplorerViewContext } from '../Context';
import { useDragScrollable } from '../useDragScrollable';
@ -663,6 +664,7 @@ export const ListView = memo(() => {
useShortcut('explorerEscape', () => {
if (!explorerView.selectable || explorer.selectedItems.size === 0) return;
if (explorerStore.isCMDPOpen) return;
explorer.resetSelectedItems([]);
setRanges([]);
});

View file

@ -87,6 +87,7 @@ export const View = ({ emptyNotice, ...contextProps }: ExplorerViewProps) => {
useShortcut('explorerEscape', () => {
if (!selectable || explorer.selectedItems.size === 0) return;
if (explorerStore.isCMDPOpen) return;
explorer.resetSelectedItems([]);
});
@ -188,6 +189,7 @@ const useShortcuts = () => {
useShortcut('toggleQuickPreview', (e) => {
if (isRenaming || dialogManager.isAnyDialogOpen()) return;
if (explorerStore.isCMDPOpen) return;
e.preventDefault();
getQuickPreviewStore().open = !quickPreviewStore.open;
});

View file

@ -97,6 +97,8 @@ const state = {
drag: null as null | DragState,
isDragSelecting: false,
isRenaming: false,
// Used for disabling certain keyboard shortcuts when command palette is open
isCMDPOpen: false,
isContextMenuOpen: false,
quickRescanLastRun: Date.now() - 200
};

View file

@ -0,0 +1,676 @@
.command-palette {
position: relative;
z-index: 10;
}
.command-palette * {
padding: 0;
margin: 0;
box-sizing: border-box;
border: 0 solid;
}
.command-palette .command-palette-content {
line-height: 1.5;
-webkit-text-size-adjust: 100%;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
/* font-family:
ui-sans-serif,
system-ui,
-apple-system,
BlinkMacSystemFont,
Segoe UI,
Roboto,
Helvetica Neue,
Arial,
Noto Sans,
sans-serif,
Apple Color Emoji,
Segoe UI Emoji,
Segoe UI Symbol,
Noto Color Emoji; */
margin: 0;
line-height: inherit;
}
.command-palette :after,
.command-palette :before {
box-sizing: border-box;
border: 0 solid;
--tw-content: '';
}
.command-palette hr {
height: 0;
color: inherit;
border-top-width: 1px;
}
.command-palette abbr[title] {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
}
.command-palette h1,
.command-palette h2,
.command-palette h3,
.command-palette h4,
.command-palette h5,
.command-palette h6 {
font-size: inherit;
font-weight: inherit;
}
.command-palette a {
color: inherit;
text-decoration: inherit;
}
.command-palette b,
.command-palette strong {
font-weight: bolder;
}
.command-palette code,
.command-palette kbd,
.command-palette pre,
.command-palette samp {
font-family:
ui-monospace,
SFMono-Regular,
Menlo,
Monaco,
Consolas,
Liberation Mono,
Courier New,
monospace;
font-size: 1em;
}
.command-palette small {
font-size: 80%;
}
.command-palette sub,
.command-palette sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: initial;
}
.command-palette sub {
bottom: -0.25em;
}
.command-palette sup {
top: -0.5em;
}
.command-palette table {
text-indent: 0;
border-color: inherit;
border-collapse: collapse;
}
.command-palette button,
.command-palette input,
.command-palette optgroup,
.command-palette select,
.command-palette textarea {
font-family: inherit;
font-size: 100%;
line-height: inherit;
color: inherit;
margin: 0;
padding: 0;
}
.command-palette button,
.command-palette select {
text-transform: none;
}
.command-palette [type='button'],
.command-palette [type='reset'],
.command-palette [type='submit'],
.command-palette button {
-webkit-appearance: button;
background-color: initial;
background-image: none;
}
.command-palette :-moz-focusring {
outline: auto;
}
.command-palette :-moz-ui-invalid {
box-shadow: none;
}
.command-palette progress {
vertical-align: initial;
}
.command-palette ::-webkit-inner-spin-button,
.command-palette ::-webkit-outer-spin-button {
height: auto;
}
.command-palette [type='search'] {
-webkit-appearance: textfield;
outline-offset: -2px;
}
.command-palette ::-webkit-search-decoration {
-webkit-appearance: none;
}
.command-palette ::-webkit-file-upload-button {
-webkit-appearance: button;
font: inherit;
}
.command-palette summary {
display: list-item;
}
.command-palette blockquote,
.command-palette dd,
.command-palette dl,
.command-palette figure,
.command-palette h1,
.command-palette h2,
.command-palette h3,
.command-palette h4,
.command-palette h5,
.command-palette h6,
.command-palette hr,
.command-palette p,
.command-palette pre {
margin: 0;
}
.command-palette fieldset {
margin: 0;
padding: 0;
}
.command-palette legend {
padding: 0;
}
.command-palette menu,
.command-palette ol,
.command-palette ul {
list-style: none;
margin: 0;
padding: 0;
}
.command-palette textarea {
resize: vertical;
}
.command-palette input::-moz-placeholder,
.command-palette textarea::-moz-placeholder {
opacity: 1;
color: #9ca3af;
}
.command-palette input::placeholder,
.command-palette textarea::placeholder {
opacity: 1;
color: #9ca3af;
}
.command-palette [role='button'],
.command-palette button {
cursor: pointer;
}
.command-palette :disabled {
cursor: default;
}
.command-palette audio,
.command-palette canvas,
.command-palette embed,
.command-palette iframe,
.command-palette img,
.command-palette object,
.command-palette svg,
.command-palette video {
display: block;
vertical-align: middle;
}
.command-palette img,
.command-palette video {
max-width: 100%;
height: auto;
}
.command-palette [hidden] {
display: none;
}
.command-palette *,
.command-palette :after,
.command-palette :before {
--tw-translate-x: 0;
--tw-translate-y: 0;
--tw-rotate: 0;
--tw-skew-x: 0;
--tw-skew-y: 0;
--tw-scale-x: 1;
--tw-scale-y: 1;
--tw-transform: translateX(var(--tw-translate-x)) translateY(var(--tw-translate-y))
rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y))
scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
--tw-border-opacity: 1;
border-color: rgb(229 231 235 / var(--tw-border-opacity));
--tw-ring-inset: var(--tw-empty, /*!*/ /*!*/);
--tw-ring-offset-width: 0px;
--tw-ring-offset-color: #fff;
--tw-ring-color: rgba(59, 130, 246, 0.5);
--tw-ring-offset-shadow: 0 0 #0000;
--tw-ring-shadow: 0 0 #0000;
--tw-shadow: 0 0 #0000;
--tw-shadow-colored: 0 0 #0000;
--tw-blur: var(--tw-empty, /*!*/ /*!*/);
--tw-brightness: var(--tw-empty, /*!*/ /*!*/);
--tw-contrast: var(--tw-empty, /*!*/ /*!*/);
--tw-grayscale: var(--tw-empty, /*!*/ /*!*/);
--tw-hue-rotate: var(--tw-empty, /*!*/ /*!*/);
--tw-invert: var(--tw-empty, /*!*/ /*!*/);
--tw-saturate: var(--tw-empty, /*!*/ /*!*/);
--tw-sepia: var(--tw-empty, /*!*/ /*!*/);
--tw-drop-shadow: var(--tw-empty, /*!*/ /*!*/);
--tw-filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale)
var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
}
.command-palette .pointer-events-none {
pointer-events: none;
}
.command-palette .fixed {
position: fixed;
}
.command-palette .absolute {
position: absolute;
}
.command-palette .relative {
position: relative;
}
.command-palette .inset-0 {
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.command-palette .right-3 {
right: 0.75rem;
}
.command-palette .top-1\/2 {
top: 50%;
}
.command-palette .mt-1 {
margin-top: 0.25rem;
}
.command-palette .block {
display: block;
}
.command-palette .flex {
display: flex;
}
.command-palette .h-\[450px\] {
height: 450px;
}
.command-palette .h-5 {
height: 1.25rem;
}
.command-palette .max-h-full {
max-height: 100%;
}
.command-palette .w-full {
width: 100%;
}
.command-palette .w-5 {
width: 1.25rem;
}
.command-palette .w-4 {
width: 1rem;
}
.command-palette .max-w-xl {
max-width: 36rem;
}
.command-palette .max-w-md {
max-width: 28rem;
}
.command-palette .max-w-xs {
max-width: 20rem;
}
.command-palette .flex-1 {
flex: 1 1 0%;
}
.command-palette .-translate-y-1\/2 {
--tw-translate-y: -50%;
}
.command-palette .-translate-y-1\/2,
.command-palette .scale-95 {
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate))
skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x))
scaleY(var(--tw-scale-y));
}
.command-palette .scale-95 {
--tw-scale-x: 0.95;
--tw-scale-y: 0.95;
}
.command-palette .scale-100 {
--tw-scale-x: 1;
--tw-scale-y: 1;
}
.command-palette .scale-100,
.command-palette .transform {
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate))
skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x))
scaleY(var(--tw-scale-y));
}
.command-palette .cursor-default {
cursor: default;
}
.command-palette .cursor-pointer {
cursor: pointer;
}
.command-palette .flex-col {
flex-direction: column;
}
.command-palette .items-start {
align-items: flex-start;
}
.command-palette .items-center {
align-items: center;
}
.command-palette .justify-center {
justify-content: center;
}
.command-palette .justify-between {
justify-content: space-between;
}
.command-palette .space-y-4 > :not([hidden]) ~ :not([hidden]) {
--tw-space-y-reverse: 0;
margin-top: calc(1rem * (1 - var(--tw-space-y-reverse)));
margin-bottom: calc(1rem * var(--tw-space-y-reverse));
}
.command-palette .space-y-1 > :not([hidden]) ~ :not([hidden]) {
--tw-space-y-reverse: 0;
margin-top: calc(0.25rem * (1 - var(--tw-space-y-reverse)));
margin-bottom: calc(0.25rem * var(--tw-space-y-reverse));
}
.command-palette .space-x-2\.5 > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 0;
margin-right: calc(0.625rem * var(--tw-space-x-reverse));
margin-left: calc(0.625rem * (1 - var(--tw-space-x-reverse)));
}
.command-palette .space-x-2 > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 0;
margin-right: calc(0.5rem * var(--tw-space-x-reverse));
margin-left: calc(0.5rem * (1 - var(--tw-space-x-reverse)));
}
.command-palette .space-x-1\.5 > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 0;
margin-right: calc(0.375rem * var(--tw-space-x-reverse));
margin-left: calc(0.375rem * (1 - var(--tw-space-x-reverse)));
}
.command-palette .space-x-1 > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 0;
margin-right: calc(0.25rem * var(--tw-space-x-reverse));
margin-left: calc(0.25rem * (1 - var(--tw-space-x-reverse)));
}
.command-palette .divide-y > :not([hidden]) ~ :not([hidden]) {
--tw-divide-y-reverse: 0;
border-top-width: calc(1px * (1 - var(--tw-divide-y-reverse)));
border-bottom-width: calc(1px * var(--tw-divide-y-reverse));
}
.command-palette .overflow-hidden {
overflow: hidden;
}
.command-palette .overflow-y-auto {
overflow-y: auto;
}
.command-palette .truncate {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.command-palette .rounded-lg {
border-radius: 0.5rem;
}
.command-palette .rounded-md {
border-radius: 0.375rem;
}
.command-palette .border-t {
border-top-width: 1px;
}
.command-palette .border-b {
border-bottom-width: 1px;
}
.command-palette .border-none {
border-style: none;
}
.command-palette .border-indigo-500 {
--tw-border-opacity: 1;
border-color: rgb(99 102 241 / var(--tw-border-opacity));
}
.command-palette .bg-gray-900 {
--tw-bg-opacity: 1;
background-color: rgb(17 24 39 / var(--tw-bg-opacity));
}
.command-palette .bg-white {
--tw-bg-opacity: 1;
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
}
.command-palette .bg-gray-200\/50 {
background-color: rgba(229, 231, 235, 0.5);
}
.command-palette .bg-transparent {
background-color: initial;
}
.command-palette .bg-opacity-80 {
--tw-bg-opacity: 0.8;
}
.command-palette .bg-gradient-to-br {
background-image: linear-gradient(to bottom right, var(--tw-gradient-stops));
}
.command-palette .from-indigo-900 {
--tw-gradient-from: #312e81;
--tw-gradient-to: rgba(49, 46, 129, 0);
--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
}
.command-palette .via-indigo-800 {
--tw-gradient-to: rgba(55, 48, 163, 0);
--tw-gradient-stops: var(--tw-gradient-from), #3730a3, var(--tw-gradient-to);
}
.command-palette .to-indigo-400 {
--tw-gradient-to: #818cf8;
}
.command-palette .p-4 {
padding: 1rem;
}
.command-palette .p-2 {
padding: 0.5rem;
}
.command-palette .px-3\.5 {
padding-left: 0.875rem;
padding-right: 0.875rem;
}
.command-palette .px-3 {
padding-left: 0.75rem;
padding-right: 0.75rem;
}
.command-palette .py-2\.5 {
padding-top: 0.625rem;
padding-bottom: 0.625rem;
}
.command-palette .py-2 {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
}
.command-palette .py-4 {
padding-top: 1rem;
padding-bottom: 1rem;
}
.command-palette .px-0 {
padding-left: 0;
padding-right: 0;
}
.command-palette .pl-3 {
padding-left: 0.75rem;
}
.command-palette .text-left {
text-align: left;
}
.command-palette .text-sm {
font-size: 0.875rem;
line-height: 1.25rem;
}
.command-palette .text-lg {
font-size: 1.125rem;
line-height: 1.75rem;
}
.command-palette .font-semibold {
font-weight: 600;
}
.command-palette .font-medium {
font-weight: 500;
}
.command-palette .leading-tight {
line-height: 1.25;
}
.command-palette .text-gray-500 {
--tw-text-opacity: 1;
color: rgb(107 114 128 / var(--tw-text-opacity));
}
.command-palette .text-gray-400 {
--tw-text-opacity: 1;
color: rgb(156 163 175 / var(--tw-text-opacity));
}
.command-palette .text-gray-300 {
--tw-text-opacity: 1;
color: rgb(209 213 219 / var(--tw-text-opacity));
}
.command-palette .text-white {
--tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity));
}
.command-palette .text-white\/80 {
color: hsla(0, 0%, 100%, 0.8);
}
.command-palette .antialiased {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.command-palette .placeholder-gray-500::-moz-placeholder {
--tw-placeholder-opacity: 1;
color: rgb(107 114 128 / var(--tw-placeholder-opacity));
}
.command-palette .placeholder-gray-500::placeholder {
--tw-placeholder-opacity: 1;
color: rgb(107 114 128 / var(--tw-placeholder-opacity));
}
.command-palette .opacity-0 {
opacity: 0;
}
.command-palette .opacity-100 {
opacity: 1;
}
.command-palette .opacity-50 {
opacity: 0.5;
}
.command-palette .shadow-lg {
--tw-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);
--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color),
0 4px 6px -4px var(--tw-shadow-color);
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000),
var(--tw-shadow);
}
.command-palette .outline {
outline-style: solid;
}
.command-palette .filter {
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale)
var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
}
.command-palette .transition {
transition-property:
color,
background-color,
border-color,
fill,
stroke,
opacity,
box-shadow,
transform,
filter,
-webkit-text-decoration-color,
-webkit-backdrop-filter;
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke,
opacity, box-shadow, transform, filter, backdrop-filter;
transition-property:
color,
background-color,
border-color,
text-decoration-color,
fill,
stroke,
opacity,
box-shadow,
transform,
filter,
backdrop-filter,
-webkit-text-decoration-color,
-webkit-backdrop-filter;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 0.15s;
}
.command-palette .duration-300 {
transition-duration: 0.3s;
}
.command-palette .duration-200 {
transition-duration: 0.2s;
}
.command-palette .ease-out {
transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
}
.command-palette .ease-in {
transition-timing-function: cubic-bezier(0.4, 0, 1, 1);
}
.command-palette .hover\:bg-gray-100:hover {
--tw-bg-opacity: 1;
background-color: rgb(243 244 246 / var(--tw-bg-opacity));
}
.command-palette .hover\:text-gray-500:hover {
--tw-text-opacity: 1;
color: rgb(107 114 128 / var(--tw-text-opacity));
}
.command-palette .focus\:border-none:focus {
border-style: none;
}
.command-palette .focus\:outline-none:focus {
outline: 2px solid transparent;
outline-offset: 2px;
}
.command-palette .focus\:ring-1:focus {
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width)
var(--tw-ring-offset-color);
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width))
var(--tw-ring-color);
}
.command-palette .focus\:ring-0:focus,
.command-palette .focus\:ring-1:focus {
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
}
.command-palette .focus\:ring-0:focus {
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width)
var(--tw-ring-offset-color);
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(var(--tw-ring-offset-width))
var(--tw-ring-color);
}
.command-palette .focus\:ring-gray-300:focus {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(209 213 219 / var(--tw-ring-opacity));
}
@media (prefers-color-scheme: dark) {
.command-palette .dark\:divide-gray-800 > :not([hidden]) ~ :not([hidden]) {
--tw-divide-opacity: 1;
border-color: rgb(31 41 55 / var(--tw-divide-opacity));
}
.command-palette .dark\:bg-gray-900 {
--tw-bg-opacity: 1;
background-color: rgb(17 24 39 / var(--tw-bg-opacity));
}
.command-palette .dark\:bg-gray-800 {
--tw-bg-opacity: 1;
background-color: rgb(31 41 55 / var(--tw-bg-opacity));
}
.command-palette .dark\:text-white {
--tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity));
}
.command-palette .dark\:text-gray-600 {
--tw-text-opacity: 1;
color: rgb(75 85 99 / var(--tw-text-opacity));
}
.command-palette .dark\:hover\:bg-gray-800:hover {
--tw-bg-opacity: 1;
background-color: rgb(31 41 55 / var(--tw-bg-opacity));
}
.command-palette .dark\:hover\:text-gray-300:hover {
--tw-text-opacity: 1;
color: rgb(209 213 219 / var(--tw-text-opacity));
}
}

View file

@ -0,0 +1,68 @@
// This is bad but we need to override predefined styles, use "cmdk" for the full version
.command-palette-list-item {
@apply text-ink focus:ring-app-focus dark:hover:bg-app-hover #{!important};
}
.command-palette {
@apply bg-app-button text-sm text-ink #{!important};
}
.command-palette-list-item span:nth-child(1) {
@apply text-sm #{!important};
}
.command-palette-content h4 {
@apply text-sm text-ink-faint #{!important};
}
[id^='headlessui-dialog-panel-'] > div.flex-1.overflow-y-auto::-webkit-scrollbar {
@apply w-1 #{!important};
}
[id^='headlessui-dialog-panel-'] > div.flex-1.overflow-y-auto::-webkit-scrollbar-thumb {
@apply bg-app-explorerScrollbar w-10 rounded-full #{!important};
}
.command-palette-content ul a {
@apply hover:bg-app-darkBox #{!important};
}
.command-palette-content ul button {
@apply hover:bg-app-darkBox #{!important};
}
.command-palette-content ul a span {
@apply text-sm #{!important};
}
.command-palette-content #headlessui-dialog-panel div:nth-child(2) {
@apply bg-red-500 #{!important};
}
.command-palette-content ul button div > span {
@apply text-ink #{!important};
}
.command-palette-content ul button span {
@apply text-[12px] text-ink-faint #{!important};
}
// overlay
.command-palette .bg-gray-900 {
@apply bg-app/50 #{!important};
}
.command-palette .bg-gray-200\/50 {
@apply bg-app-darkBox #{!important};
}
// container background
.command-palette .dark\:bg-gray-900 {
@apply border border-app-darkBox bg-app-darkerBox/90 backdrop-blur-lg #{!important};
}
.command-palette .dark\:divide-gray-800 {
@apply divide-app-darkBox #{!important};
}

View file

@ -0,0 +1,282 @@
import './CMDK.css';
import './CMDK.scss';
import clsx from 'clsx';
import { useEffect, useState } from 'react';
import CommandPalette, { filterItems, getItemIndex } from 'react-cmdk';
import { useNavigate } from 'react-router';
import { createSearchParams } from 'react-router-dom';
import {
arraysEqual,
useCache,
useLibraryContext,
useLibraryQuery,
useNodes,
useOnlineLocations
} from '@sd/client';
import { dialogManager } from '@sd/ui';
import i18n from '~/app/I18n';
import { Icon } from '~/components';
import Sparkles from '~/components/Sparkles';
import { useLocale, useShortcut } from '~/hooks';
import { usePlatform } from '~/util/Platform';
import { explorerStore } from '../../Explorer/store';
import { AddLocationDialog } from '../../settings/library/locations/AddLocationDialog';
import { openDirectoryPickerDialog } from '../../settings/library/locations/openDirectoryPickerDialog';
import CreateDialog from '../../settings/library/tags/CreateDialog';
import CMDKLocations from './pages/CMDKLocations';
import CMDKTags from './pages/CMDKTags';
const CMDK = () => {
const [isOpen, setIsOpen] = useState<boolean>(false);
const platform = usePlatform();
const libraryId = useLibraryContext().library.uuid;
useShortcut('toggleCommandPalette', (e) => {
e.preventDefault();
e.stopPropagation();
setIsOpen((v) => !v);
});
useShortcut('closeCommandPalette', (e) => {
e.preventDefault();
e.stopPropagation();
if (isOpen) {
setIsOpen(false);
}
});
useEffect(() => {
explorerStore.isCMDPOpen = isOpen;
}, [isOpen]);
const [page, setPage] = useState<'root' | 'locations' | 'tags'>('root');
const [search, setSearch] = useState('');
const locationsQuery = useLibraryQuery(['locations.list'], { keepPreviousData: true });
useNodes(locationsQuery.data?.nodes);
const locations = useCache(locationsQuery.data?.items);
const onlineLocations = useOnlineLocations();
function handleClose(open: boolean) {
setIsOpen(open);
// Reset page and search
setPage('root');
setSearch('');
}
const navigate = useNavigate();
const { t } = useLocale();
const filteredItems = filterItems(
[
{
heading: i18n.t('coming_soon'),
id: 'top',
items: [
{
id: 'ask-spacedrive',
children: (
<Sparkles>
<span>{t('ask_spacedrive')}</span>
</Sparkles>
),
icon: 'SparklesIcon',
closeOnSelect: false,
disabled: true // Disabled for now
}
]
},
// Navigation
{
heading: 'Navigation',
id: 'navigation',
items: [
{
id: 'go-settings',
children: t('go_to_settings'),
icon: 'ArrowRightIcon',
closeOnSelect: true,
onClick: () => navigate('settings/client/general')
},
{
id: 'go-overview',
children: t('go_to_overview'),
icon: 'ArrowRightIcon',
closeOnSelect: true,
onClick: () => navigate('overview')
},
{
id: 'go-recents',
children: t('go_to_recents'),
icon: 'ArrowRightIcon',
closeOnSelect: true,
onClick: () => navigate('recents')
},
{
id: 'go-labels',
children: t('go_to_labels'),
icon: 'ArrowRightIcon',
closeOnSelect: true,
onClick: () => navigate('labels')
},
{
id: 'go-location',
children: t('go_to_location'),
icon: 'ArrowRightIcon',
closeOnSelect: false,
onClick: () => setPage('locations')
},
{
id: 'go-tag',
children: t('go_to_tag'),
icon: 'ArrowRightIcon',
closeOnSelect: false,
onClick: () => setPage('tags')
}
// {
// id: 'go-to-settings',
// children: 'Go to settings',
// icon: 'SettingsIcon',
// onClick: () => {}
// }
]
},
{
heading: 'Actions',
id: 'actions',
items: [
// {
// id: 'create-folder',
// children: 'Create folder',
// icon: 'FolderPlusIcon',
// onClick: () => {}
// },
{
id: 'create-tag',
children: t('create_tag'),
icon: 'TagIcon',
onClick: () => {
dialogManager.create((dp) => <CreateDialog {...dp} />);
}
},
{
id: 'add-location',
children: t('add_location'),
icon: 'FolderIcon',
onClick: async () => {
const path = await openDirectoryPickerDialog(platform);
if (path !== '') {
dialogManager.create((dp) => (
<AddLocationDialog
path={path ?? ''}
libraryId={libraryId}
{...dp}
/>
));
}
}
}
]
},
// TODO: Might look nice if we showed some items and maybe saved searches here
// {
// heading: `Searching for "${search}"`,
// id: 'search',
// items: [
// // objects.items
// // ? (objects.items.map((object, index) => {
// // const item = isPath(object);
// // return {
// // id: index,
// // children: isPath(object) && object.item.name,
// // icon: () => (
// // <div className="relative -mt-0.5 mr-1 shrink-0 grow-0">
// // <Icon name="Location" size={22} />
// // </div>
// // )
// // };
// // }) as any)
// // : ([] as any)
// ]
// }
// This is technically a duplicate of "Go to Location", but it looks cool.
{
heading: t('locations'),
id: 'locations',
items: locations
? locations.map((location) => ({
id: location.id,
children: location.name,
icon: () => (
<div className="relative -mt-0.5 mr-1 shrink-0 grow-0">
<Icon name="Folder" size={22} />
<div
className={clsx(
'absolute bottom-0.5 right-0 size-1.5 rounded-full',
onlineLocations.some((l) =>
arraysEqual(location.pub_id, l)
)
? 'bg-green-500'
: 'bg-red-500'
)}
/>
</div>
),
onClick: () => navigate(`location/${location.id}`)
}))
: ([] as any)
}
],
search
);
return (
<CommandPalette
onChangeSearch={setSearch}
onChangeOpen={handleClose}
search={search}
isOpen={isOpen}
page={page}
placeholder={t('search_for_files_and_actions')}
// footer
>
<CommandPalette.Page id="root" onEscape={() => setSearch('')}>
{filteredItems.length ? (
filteredItems.map((list) => (
<CommandPalette.List key={list.id} heading={list.heading}>
{list.items.map(({ id, ...rest }) => (
<CommandPalette.ListItem
key={id}
index={getItemIndex(filteredItems, id)}
{...rest}
/>
))}
</CommandPalette.List>
))
) : (
<CommandPalette.FreeSearchAction
onClick={(v) =>
navigate(
{
pathname: 'search',
search: createSearchParams({ search }).toString()
},
{ replace: true }
)
}
/>
)}
</CommandPalette.Page>
{page === 'locations' && <CMDKLocations />}
{page === 'tags' && <CMDKTags />}
</CommandPalette>
);
};
export default CMDK;

View file

@ -0,0 +1,44 @@
import clsx from 'clsx';
import CommandPalette from 'react-cmdk';
import { useNavigate } from 'react-router';
import { arraysEqual, useCache, useLibraryQuery, useNodes, useOnlineLocations } from '@sd/client';
import { Icon } from '~/components';
export default function CMDKLocations() {
const locationsQuery = useLibraryQuery(['locations.list'], { keepPreviousData: true });
useNodes(locationsQuery.data?.nodes);
const locations = useCache(locationsQuery.data?.items);
const onlineLocations = useOnlineLocations();
const navigate = useNavigate();
return (
<CommandPalette.Page id="locations">
<CommandPalette.List>
{locations?.map((location, index) => (
<CommandPalette.ListItem
key={location.id}
index={index}
onClick={() => navigate(`location/${location.id}`)}
closeOnSelect
>
<div className="relative mr-1 shrink-0 grow-0">
<Icon name="Folder" size={18} />
<div
className={clsx(
'absolute bottom-0.5 right-0 size-1.5 rounded-full',
onlineLocations.some((l) => arraysEqual(location.pub_id, l))
? 'bg-green-500'
: 'bg-red-500'
)}
/>
</div>
<span className="truncate">{location.name}</span>
</CommandPalette.ListItem>
))}
</CommandPalette.List>
</CommandPalette.Page>
);
}

View file

@ -0,0 +1,32 @@
import CommandPalette from 'react-cmdk';
import { useNavigate } from 'react-router';
import { useCache, useLibraryQuery, useNodes, type Tag } from '@sd/client';
export default function CMDKTags() {
const result = useLibraryQuery(['tags.list'], { keepPreviousData: true });
useNodes(result.data?.nodes);
const tags = useCache(result.data?.items);
const navigate = useNavigate();
return (
<CommandPalette.Page id="tags">
<CommandPalette.List>
{tags.map((tag, i) => (
<CommandPalette.ListItem
key={tag.id}
index={i}
onClick={() => navigate(`tag/${tag.id}`)}
closeOnSelect={true}
>
<div
className="size-[12px] shrink-0 rounded-full"
style={{ backgroundColor: tag.color || '#efefef' }}
/>
<span className="ml-1.5 truncate text-sm">{tag.name}</span>
</CommandPalette.ListItem>
))}
</CommandPalette.List>
</CommandPalette.Page>
);
}

View file

@ -26,6 +26,7 @@ import { usePlatform } from '~/util/Platform';
import { DragOverlay } from '../Explorer/DragOverlay';
import { QuickPreviewContextProvider } from '../Explorer/QuickPreview/Context';
import CMDK from './CMDK';
import { LayoutContext } from './Context';
import { DndContext } from './DndContext';
import Sidebar from './Sidebar';
@ -88,6 +89,7 @@ const Layout = () => {
fallback={<div className="h-screen w-screen bg-app" />}
>
<Outlet />
<CMDK />
<DragOverlay />
</Suspense>
</LibraryContextProvider>
@ -150,11 +152,7 @@ function usePlausible() {
useEffect(() => {
const interval = setInterval(() => {
plausibleEvent({
event: {
type: 'ping'
}
});
plausibleEvent({ event: { type: 'ping' } });
}, 270 * 1000);
return () => clearInterval(interval);

View file

@ -1,7 +1,7 @@
import { useMemo } from 'react';
import { ObjectOrder, useLibraryQuery } from '@sd/client';
import { Icon } from '~/components';
import { useRouteTitle } from '~/hooks';
import { useLocale, useRouteTitle } from '~/hooks';
import Explorer from './Explorer';
import { ExplorerContextProvider } from './Explorer/Context';
@ -53,6 +53,8 @@ export function Component() {
layouts: { media: false, list: false }
});
const { t } = useLocale();
return (
<ExplorerContextProvider explorer={explorer}>
<SearchContextProvider search={search}>
@ -60,7 +62,7 @@ export function Component() {
center={<SearchBar />}
left={
<div className="flex flex-row items-center gap-2">
<span className="truncate text-sm font-medium">Labels</span>
<span className="truncate text-sm font-medium">{t('labels')}</span>
</div>
}
right={<DefaultTopBarOptions />}
@ -78,7 +80,7 @@ export function Component() {
emptyNotice={
<EmptyNotice
icon={<Icon name="CollectionSparkle" size={128} />}
message="No labels"
message={t('no_labels')}
/>
}
/>

View file

@ -36,13 +36,14 @@ export default ({ redirectToSearch }: Props) => {
const blurHandler = useCallback((event: KeyboardEvent) => {
//condition prevents default search of webview
if (document.activeElement === searchRef.current) {
if (event.key === 'f' && event.ctrlKey) {
event.preventDefault();
}
if (event.key === 'Escape' && document.activeElement === searchRef.current) {
event.preventDefault();
if (event.key === 'Escape') {
// Check if element is in focus, then remove it
searchRef.current?.blur();
}
}
}, []);
useEffect(() => {

View file

@ -127,7 +127,9 @@ function useSearchWithFilters(explorerSettings: UseExplorerSettings<ObjectOrder>
},
{ replace: true }
);
}, [searchQuery, setSearchParams]);
// Do not add setSearchParams to the dependencies array, it will cause CMDK to not navigate to search page (multiple times)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [searchQuery]);
return search;
}

View file

@ -24,6 +24,8 @@ export const Component = () => {
name: t('general'),
description: t('general_shortcut_description'),
shortcuts: [
{ shortcut: 'toggleCommandPalette', description: t('toggle_command_palette') },
{ shortcut: 'closeCommandPalette', description: t('close_command_palette') },
{ shortcut: 'newTab', description: t('open_new_tab') },
{ shortcut: 'closeTab', description: t('close_current_tab') },
{ shortcut: 'newTab', description: t('switch_to_next_tab') },

View file

@ -399,3 +399,26 @@ body {
.wiggle {
animation: wiggle 200ms infinite;
}
// sparkles
@keyframes comeInOut {
0% {
transform: scale(0);
}
50% {
transform: scale(1);
}
100% {
transform: scale(0);
}
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(180deg);
}
}

View file

@ -0,0 +1,99 @@
'use client';
import { useState } from 'react';
import { usePrefersReducedMotion, useRandomInterval } from '~/hooks';
const DEFAULT_COLOR = '#FFC700';
const random = (min: number, max: number) => Math.floor(Math.random() * (max - min)) + min;
const range = (start: number, end?: number, step = 1) => {
const output = [];
if (typeof end === 'undefined') {
end = start;
start = 0;
}
for (let i = start; i < end; i += step) {
output.push(i);
}
return output;
};
const generateSparkle = (color: string) => {
const sparkle = {
id: String(random(10000, 99999)),
createdAt: Date.now(),
color,
size: random(10, 20),
style: {
top: random(0, 100) + '%',
left: random(0, 100) + '%'
}
};
return sparkle;
};
type SparklesProps = {
color?: string;
children: React.ReactNode;
};
const Sparkles = ({ color = DEFAULT_COLOR, children, ...props }: SparklesProps) => {
const [sparkles, setSparkles] = useState(() => {
return range(3).map(() => generateSparkle(color));
});
const prefersReducedMotion = usePrefersReducedMotion();
useRandomInterval(
() => {
const sparkle = generateSparkle(color);
const now = Date.now();
const nextSparkles = sparkles.filter((sp) => {
const delta = now - sp.createdAt;
return delta < 750;
});
nextSparkles.push(sparkle);
setSparkles(nextSparkles);
},
prefersReducedMotion ? null : 100,
prefersReducedMotion ? null : 1000
);
return (
<span className="relative inline-block" {...props}>
{sparkles.map((sparkle) => (
<span
key={sparkle.id}
className="z-10"
style={{
position: 'absolute',
display: 'block',
animation: prefersReducedMotion ? 'none' : 'comeInOut 700ms forwards',
...sparkle.style
}}
>
<svg
width={sparkle.size}
height={sparkle.size}
viewBox="0 0 68 68"
fill="none"
style={{
display: 'block',
animation: prefersReducedMotion ? 'none' : 'spin 1000ms linear'
}}
>
<path
d="M26.5 25.5C19.0043 33.3697 0 34 0 34C0 34 19.1013 35.3684 26.5 43.5C33.234 50.901 34 68 34 68C34 68 36.9884 50.7065 44.5 43.5C51.6431 36.647 68 34 68 34C68 34 51.6947 32.0939 44.5 25.5C36.5605 18.2235 34 0 34 0C34 0 33.6591 17.9837 26.5 25.5Z"
fill={sparkle.color}
/>
</svg>
</span>
))}
<strong style={{ position: 'relative', zIndex: 1, fontWeight: 'bold' }}>
{children}
</strong>
</span>
);
};
export default Sparkles;

View file

@ -27,3 +27,5 @@ export * from './useWindowSize';
export * from './useWindowState';
export * from './useZodRouteParams';
export * from './useZodSearchParams';
export * from './usePrefersReducedMotion';
export * from './useRandomInterval';

View file

@ -0,0 +1,37 @@
import { useEffect, useState } from 'react';
const QUERY = '(prefers-reduced-motion: no-preference)';
const isRenderingOnServer = typeof window === 'undefined';
const getInitialState = () => {
// For our initial server render, we won't know if the user
// prefers reduced motion, but it doesn't matter. This value
// will be overwritten on the client, before any animations
// occur.
return isRenderingOnServer ? true : !window.matchMedia(QUERY).matches;
};
export function usePrefersReducedMotion() {
const [prefersReducedMotion, setPrefersReducedMotion] = useState(getInitialState);
useEffect(() => {
const mediaQueryList = window.matchMedia(QUERY);
const listener = (event: { matches: any }) => {
setPrefersReducedMotion(!event.matches);
};
if (mediaQueryList.addEventListener) {
mediaQueryList.addEventListener('change', listener);
} else {
mediaQueryList.addListener(listener);
}
return () => {
if (mediaQueryList.removeEventListener) {
mediaQueryList.removeEventListener('change', listener);
} else {
mediaQueryList.removeListener(listener);
}
};
}, []);
return prefersReducedMotion;
}

View file

@ -0,0 +1,38 @@
import { useCallback, useEffect, useRef } from 'react';
// Utility helper for random number generation
const random = (min: number, max: number) => Math.floor(Math.random() * (max - min)) + min;
export const useRandomInterval = (
callback: () => void,
minDelay: number | null,
maxDelay: number | null
) => {
const timeoutId = useRef<number | null>(null);
const savedCallback = useRef(callback);
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
useEffect(() => {
const isEnabled = typeof minDelay === 'number' && typeof maxDelay === 'number';
if (isEnabled) {
const handleTick = () => {
const nextTickAt = random(minDelay, maxDelay);
timeoutId.current = window.setTimeout(() => {
savedCallback.current();
handleTick();
}, nextTickAt);
};
handleTick();
}
return () => window.clearTimeout(timeoutId.current!);
}, [minDelay, maxDelay]);
const cancel = useCallback(function () {
window.clearTimeout(timeoutId.current!);
}, []);
return cancel;
};

View file

@ -1,7 +1,7 @@
import { valtioPersist } from '@sd/client';
import { useMemo } from 'react';
import { useKeys } from 'rooks';
import { useSnapshot } from 'valtio';
import { valtioPersist } from '@sd/client';
import { useRoutingContext } from '~/RoutingContext';
import { OperatingSystem } from '~/util/Platform';
@ -22,6 +22,13 @@ const shortcuts = {
macOS: ['Meta', 'Alt', 'ArrowRight'],
all: ['Control', 'Alt', 'ArrowRight']
},
toggleCommandPalette: {
macOS: ['Meta', 'KeyK'],
all: ['Control', 'KeyK']
},
closeCommandPalette: {
all: ['Escape']
},
previousTab: {
macOS: ['Meta', 'Alt', 'ArrowLeft'],
all: ['Control', 'Alt', 'ArrowLeft']

View file

@ -437,5 +437,16 @@
"failed_to_download_update": "Не ўдалося загрузіць абнаўленне",
"updated_successfully": "Паспяхова абнавіліся, вы на версіі {{version}}",
"view_changes": "Праглядзець змены",
"update": "Абнаўленне"
"update": "Абнаўленне",
"ask_spacedrive": "Pergunte ao Spacedrive",
"close_command_palette": "Fechar paleta de comandos",
"go_to_labels": "Ir para etiquetas",
"go_to_location": "Ir para localização",
"go_to_overview": "Ir para visão geral",
"go_to_recents": "Ir para mensagens recentes",
"go_to_settings": "Ir para configurações",
"go_to_tag": "Ir para marcação",
"no_labels": "Sem etiquetas",
"search_for_files_and_actions": "Pesquisar por arquivos e ações...",
"toggle_command_palette": "Alternar paleta de comandos"
}

View file

@ -436,5 +436,17 @@
"failed_to_download_update": "Update konnte nicht heruntergeladen werden",
"updated_successfully": "Erfolgreich aktualisiert, Sie verwenden jetzt Version {{version}}",
"view_changes": "Änderungen anzeigen",
"update": "Aktualisieren"
"update": "Aktualisieren",
"ask_spacedrive": "Fragen Sie Spacedrive",
"close_command_palette": "Befehlspalette schließen",
"disconnected": "Getrennt",
"go_to_labels": "Gehen Sie zu Etiketten",
"go_to_location": "Gehen Sie zum Standort",
"go_to_overview": "Zur Übersicht gehen",
"go_to_recents": "Gehen Sie zu den letzten Nachrichten",
"go_to_settings": "Gehe zu den Einstellungen",
"go_to_tag": "Gehe zum Markieren",
"no_labels": "Keine Etiketten",
"search_for_files_and_actions": "Nach Dateien und Aktionen suchen...",
"toggle_command_palette": "Befehlspalette umschalten"
}

View file

@ -24,6 +24,7 @@
"archive_coming_soon": "Archiving locations is coming soon...",
"archive_info": "Extract data from Library as an archive, useful to preserve Location folder structure.",
"are_you_sure": "Are you sure?",
"ask_spacedrive": "Ask Spacedrive",
"assign_tag": "Assign tag",
"audio_preview_not_supported": "Audio preview is not supported.",
"back": "Back",
@ -42,6 +43,7 @@
"clear_finished_jobs": "Clear out finished jobs",
"client": "Client",
"close": "Close",
"close_command_palette": "Close command palette",
"close_current_tab": "Close current tab",
"clouds": "Clouds",
"color": "Color",
@ -112,6 +114,7 @@
"dont_show_again": "Don't show again",
"double_click_action": "Double click action",
"download": "Download",
"downloading_update": "Downloading Update",
"duplicate": "Duplicate",
"duplicate_object": "Duplicate object",
"duplicate_success": "Items duplicated",
@ -145,6 +148,7 @@
"failed_to_copy_file": "Failed to copy file",
"failed_to_copy_file_path": "Failed to copy file path",
"failed_to_cut_file": "Failed to cut file",
"failed_to_download_update": "Failed to download update",
"failed_to_duplicate_file": "Failed to duplicate file",
"failed_to_generate_checksum": "Failed to generate checksum",
"failed_to_generate_labels": "Failed to generate labels",
@ -179,6 +183,12 @@
"generatePreviewMedia_label": "Generate preview media for this Location",
"generate_checksums": "Generate Checksums",
"go_back": "Go Back",
"go_to_labels": "Go to labels",
"go_to_location": "Go to location",
"go_to_overview": "Go to overview",
"go_to_recents": "Go to recents",
"go_to_settings": "Go to settings",
"go_to_tag": "Go to tag",
"got_it": "Got it",
"grid_gap": "Gap",
"grid_view": "Grid View",
@ -288,12 +298,14 @@
"new_location_web_description": "As you are using the browser version of Spacedrive you will (for now) need to specify an absolute URL of a directory local to the remote node.",
"new_tab": "New Tab",
"new_tag": "New tag",
"new_update_available": "New Update Available!",
"no_files_found_here": "No files found here",
"no_jobs": "No jobs.",
"no_labels": "No labels",
"no_nodes_found": "No Spacedrive nodes were found.",
"no_tag_selected": "No Tag Selected",
"no_tags": "No tags",
"node_name": "Node Name",
"no_nodes_found": "No Spacedrive nodes were found.",
"nodes": "Nodes",
"nodes_description": "Manage the nodes connected to this library. A node is an instance of Spacedrive's backend, running on a device or server. Each node carries a copy of the database and synchronizes via peer-to-peer connections in realtime.",
"none": "None",
@ -357,6 +369,7 @@
"save_changes": "Save Changes",
"saved_searches": "Saved Searches",
"search_extensions": "Search extensions",
"search_for_files_and_actions": "Search for files and actions...",
"secure_delete": "Secure delete",
"security": "Security",
"security_description": "Keep your client safe.",
@ -382,8 +395,8 @@
"spacedrive_cloud": "Spacedrive Cloud",
"spacedrive_cloud_description": "Spacedrive is always local first, but we will offer our own optional cloud services in the future. For now, authentication is only used for the Feedback feature, otherwise it is not required.",
"spacedrop_a_file": "Spacedrop a File",
"spacedrop_description": "Share instantly with devices running Spacedrive on your network.",
"spacedrop_already_progress": "Spacedrop already in progress",
"spacedrop_description": "Share instantly with devices running Spacedrive on your network.",
"spacedrop_rejected": "Spacedrop rejected",
"square_thumbnails": "Square Thumbnails",
"star_on_github": "Star on GitHub",
@ -409,6 +422,7 @@
"thumbnailer_cpu_usage": "Thumbnailer CPU usage",
"thumbnailer_cpu_usage_description": "Limit how much CPU the thumbnailer can use for background processing.",
"toggle_all": "Toggle All",
"toggle_command_palette": "Toggle command palette",
"toggle_hidden_files": "Toggle hidden files",
"toggle_image_slider_within_quick_preview": "Toggle image slider within quick preview",
"toggle_inspector": "Toggle inspector",
@ -420,22 +434,19 @@
"ui_animations": "UI Animations",
"ui_animations_description": "Dialogs and other UI elements will animate when opening and closing.",
"unnamed_location": "Unnamed Location",
"update": "Update",
"update_downloaded": "Update Downloaded. Restart Spacedrive to install",
"updated_successfully": "Updated successfully, you're on version {{version}}",
"usage": "Usage",
"usage_description": "Your library usage and hardware information",
"value": "Value",
"version": "Version {{version}}",
"video_preview_not_supported": "Video preview is not supported.",
"view_changes": "View Changes",
"want_to_do_this_later": "Want to do this later?",
"website": "Website",
"your_account": "Your account",
"your_account_description": "Spacedrive account and information.",
"your_local_network": "Your Local Network",
"your_privacy": "Your Privacy",
"new_update_available": "New Update Available!",
"version": "Version {{version}}",
"downloading_update": "Downloading Update",
"update_downloaded": "Update Downloaded. Restart Spacedrive to install",
"failed_to_download_update": "Failed to download update",
"updated_successfully": "Updated successfully, you're on version {{version}}",
"view_changes": "View Changes",
"update": "Update"
"your_privacy": "Your Privacy"
}

View file

@ -436,5 +436,17 @@
"failed_to_download_update": "Error al descargar la actualización",
"updated_successfully": "Actualizado correctamente, estás en la versión {{version}}",
"view_changes": "Ver cambios",
"update": "Actualizar"
"update": "Actualizar",
"ask_spacedrive": "Pregúntale a SpaceDrive",
"close_command_palette": "Cerrar paleta de comandos",
"disconnected": "Desconectado",
"go_to_labels": "Ir a etiquetas",
"go_to_location": "Ir a la ubicación",
"go_to_overview": "Ir a la descripción general",
"go_to_recents": "Ir a recientes",
"go_to_settings": "Ir a la configuración",
"go_to_tag": "Ir a la etiqueta",
"no_labels": "Sin etiquetas",
"search_for_files_and_actions": "Buscar archivos y acciones...",
"toggle_command_palette": "Alternar paleta de comandos"
}

View file

@ -435,5 +435,18 @@
"failed_to_download_update": "Échec du téléchargement de la mise à jour",
"updated_successfully": "Mise à jour réussie, vous êtes en version {{version}}",
"view_changes": "Voir les changements",
"update": "Mettre à jour"
"update": "Mettre à jour",
"ask_spacedrive": "Demandez à Spacedrive",
"close_command_palette": "Fermer la palette de commandes",
"disconnected": "Débranché",
"failed_to_rescan_location": "Échec de la nouvelle analyse de l'emplacement",
"go_to_labels": "Aller aux étiquettes",
"go_to_location": "Aller à l'emplacement",
"go_to_overview": "Aller à l'aperçu",
"go_to_recents": "Aller aux récents",
"go_to_settings": "Aller aux paramètres",
"go_to_tag": "Aller au tag",
"no_labels": "Pas d'étiquettes",
"search_for_files_and_actions": "Rechercher des fichiers et des actions...",
"toggle_command_palette": "Basculer la palette de commandes"
}

View file

@ -199,7 +199,6 @@
"installed": "Installato",
"item_size": "Dimensione dell'elemento",
"item_with_count_one": "{{count}} elemento",
"item_with_count_many": "{{count}} elementi",
"item_with_count_other": "{{count}} elementi",
"job_has_been_canceled": "Il lavoro è stato annullato",
"job_has_been_paused": "Il lavoro è stato messo in pausa.",
@ -426,5 +425,28 @@
"your_account": "Il tuo account",
"your_account_description": "Account di Spacedrive e informazioni.",
"your_local_network": "La tua rete locale",
"your_privacy": "La tua Privacy"
"your_privacy": "La tua Privacy",
"ask_spacedrive": "Chiedi a Spacedrive",
"close_command_palette": "Chiudi la tavolozza dei comandi",
"copy_success": "Elementi copiati",
"cut_success": "Articoli tagliati",
"downloading_update": "Download dell'aggiornamento",
"duplicate_success": "Elementi duplicati",
"failed_to_download_update": "Impossibile scaricare l'aggiornamento",
"go_to_labels": "Vai alle etichette",
"go_to_location": "Vai alla posizione",
"go_to_overview": "Vai alla panoramica",
"go_to_recents": "Vai ai recenti",
"go_to_settings": "Vai alle impostazioni",
"go_to_tag": "Vai al tag",
"new_update_available": "Nuovo aggiornamento disponibile!",
"no_labels": "Nessuna etichetta",
"paste_success": "Elementi incollati",
"search_for_files_and_actions": "Cerca file e azioni...",
"toggle_command_palette": "Attiva/disattiva la tavolozza dei comandi",
"update": "Aggiornamento",
"update_downloaded": "Aggiornamento scaricato. Riavvia Spacedrive per eseguire l'installazione",
"updated_successfully": "Aggiornato con successo, sei sulla versione {{version}}",
"version": "Versione {{versione}}",
"view_changes": "Visualizza modifiche"
}

View file

@ -437,5 +437,16 @@
"failed_to_download_update": "アップデートのダウンロードに失敗",
"updated_successfully": "バージョン {{version}} へのアップデートが完了しました。",
"view_changes": "変更履歴を見る",
"update": "アップデート"
"update": "アップデート",
"ask_spacedrive": "スペースドライブに聞いてください",
"close_command_palette": "コマンドパレットを閉じる",
"go_to_labels": "ラベルに移動",
"go_to_location": "場所に行く",
"go_to_overview": "概要に移動",
"go_to_recents": "最近の履歴に移動",
"go_to_settings": "設定に移動",
"go_to_tag": "タグに移動",
"no_labels": "ラベルなし",
"search_for_files_and_actions": "ファイルとアクションを検索します...",
"toggle_command_palette": "コマンドパレットの切り替え"
}

View file

@ -436,5 +436,17 @@
"failed_to_download_update": "Update kon niet worden gedownload",
"updated_successfully": "Succesvol bijgewerkt, je gebruikt nu versie {{version}}",
"view_changes": "Bekijk wijzigingen",
"update": "Bijwerken"
"update": "Bijwerken",
"ask_spacedrive": "Vraag het aan Space Drive",
"close_command_palette": "Sluit het opdrachtpalet",
"disconnected": "Losgekoppeld",
"go_to_labels": "Ga naar etiketten",
"go_to_location": "Ga naar locatie",
"go_to_overview": "Ga naar overzicht",
"go_to_recents": "Ga naar recent",
"go_to_settings": "Ga naar Instellingen",
"go_to_tag": "Ga naar taggen",
"no_labels": "Geen etiketten",
"search_for_files_and_actions": "Zoeken naar bestanden en acties...",
"toggle_command_palette": "Schakel het opdrachtpalet in of uit"
}

View file

@ -437,5 +437,16 @@
"failed_to_download_update": "Не удалось загрузить обновление",
"updated_successfully": "Успешно обновлено, вы используете версию {{version}}",
"view_changes": "Просмотреть изменения",
"update": "Обновить"
"update": "Обновить",
"ask_spacedrive": "Спросите Спейсдрайв",
"close_command_palette": "Закрыть палитру команд",
"go_to_labels": "Перейти к ярлыкам",
"go_to_location": "Перейти к месту",
"go_to_overview": "Перейти к обзору",
"go_to_recents": "Перейти к недавним",
"go_to_settings": "Перейдите в настройки",
"go_to_tag": "Перейти к тегу",
"no_labels": "Нет ярлыков",
"search_for_files_and_actions": "Поиск файлов и действий...",
"toggle_command_palette": "Переключить палитру команд"
}

View file

@ -436,5 +436,17 @@
"failed_to_download_update": "Güncelleme indirme başarısız",
"updated_successfully": "Başarıyla güncellendi, şu anda {{version}} sürümündesiniz",
"view_changes": "Değişiklikleri Görüntüle",
"update": "Güncelleme"
"update": "Güncelleme",
"ask_spacedrive": "Spacedrive'a sor",
"close_command_palette": "Komut paletini kapat",
"disconnected": "Bağlantı kesildi",
"go_to_labels": "Etiketlere git",
"go_to_location": "Konuma git",
"go_to_overview": "Genel bakışa git",
"go_to_recents": "Son aramalara git",
"go_to_settings": "Ayarlara git",
"go_to_tag": "Etikete git",
"no_labels": "Etiket yok",
"search_for_files_and_actions": "Dosyaları ve eylemleri arayın...",
"toggle_command_palette": "Komut paletini değiştir"
}

View file

@ -436,5 +436,17 @@
"failed_to_download_update": "无法下载更新",
"updated_successfully": "成功更新,您当前使用的是版本 {{version}}",
"view_changes": "查看更改",
"update": "更新"
"update": "更新",
"ask_spacedrive": "询问 Spacedrive",
"close_command_palette": "关闭命令面板",
"disconnected": "已断开连接",
"go_to_labels": "转到标签",
"go_to_location": "前往地点",
"go_to_overview": "前往概览",
"go_to_recents": "转到最近的内容",
"go_to_settings": "前往设置",
"go_to_tag": "转到标签",
"no_labels": "无标签",
"search_for_files_and_actions": "搜索文件和操作...",
"toggle_command_palette": "切换命令面板"
}

View file

@ -435,5 +435,18 @@
"failed_to_download_update": "無法下載更新",
"updated_successfully": "成功更新,您目前使用的是版本 {{version}}",
"view_changes": "檢視變更",
"update": "更新"
"update": "更新",
"ask_spacedrive": "詢問 Spacedrive",
"close_command_palette": "關閉命令面板",
"disconnected": "已斷開連接",
"failed_to_rescan_location": "重新掃描位置失敗",
"go_to_labels": "轉到標籤",
"go_to_location": "前往地點",
"go_to_overview": "前往概覽",
"go_to_recents": "前往最近的內容",
"go_to_settings": "前往設定",
"go_to_tag": "轉到標籤",
"no_labels": "無標籤",
"search_for_files_and_actions": "搜尋文件和操作...",
"toggle_command_palette": "切換命令面板"
}

View file

@ -42,6 +42,7 @@
"immer": "^10.0.3",
"prismjs": "^1.29.0",
"react": "^18.2.0",
"react-cmdk": "^1.3.9",
"react-colorful": "^5.6.1",
"react-dom": "^18.2.0",
"react-error-boundary": "^4.0.11",

View file

@ -763,6 +763,9 @@ importers:
react:
specifier: ^18.2.0
version: 18.2.0
react-cmdk:
specifier: ^1.3.9
version: 1.3.9(react-dom@18.2.0)(react@18.2.0)
react-colorful:
specifier: ^5.6.1
version: 5.6.1(react-dom@18.2.0)(react@18.2.0)
@ -3089,6 +3092,10 @@ packages:
peerDependencies:
'@effect-ts/otel-node': '*'
peerDependenciesMeta:
'@effect-ts/core':
optional: true
'@effect-ts/otel':
optional: true
'@effect-ts/otel-node':
optional: true
dependencies:
@ -4748,6 +4755,14 @@ packages:
tailwindcss: 3.4.1
dev: true
/@heroicons/react@2.1.3(react@18.2.0):
resolution: {integrity: sha512-fEcPfo4oN345SoqdlCDdSa4ivjaKbk0jTd+oubcgNxnNgAfzysfwWfQUr+51wigiWHQQRiZNd1Ao0M5Y3M2EGg==}
peerDependencies:
react: '>= 16'
dependencies:
react: 18.2.0
dev: false
/@hookform/resolvers@3.3.4(react-hook-form@7.51.1):
resolution: {integrity: sha512-o5cgpGOuJYrd+iMKvkttOclgwRW86EsWJZZRC23prf0uU2i48Htq4PuT73AVb9ionFyZrwYEITuOFGF+BydEtQ==}
peerDependencies:
@ -10097,6 +10112,10 @@ packages:
'@types/unist': 3.0.2
dev: false
/@types/html-minifier-terser@6.1.0:
resolution: {integrity: sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==}
dev: false
/@types/http-errors@2.0.4:
resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==}
@ -12182,7 +12201,6 @@ packages:
engines: {node: '>= 10.0'}
dependencies:
source-map: 0.6.1
dev: true
/clean-stack@2.2.0:
resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==}
@ -12852,7 +12870,6 @@ packages:
domhandler: 4.3.1
domutils: 2.8.0
nth-check: 2.1.1
dev: true
/css-select@5.1.0:
resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==}
@ -13367,13 +13384,18 @@ packages:
resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==}
dev: false
/dom-converter@0.2.0:
resolution: {integrity: sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==}
dependencies:
utila: 0.4.0
dev: false
/dom-serializer@1.4.1:
resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==}
dependencies:
domelementtype: 2.3.0
domhandler: 4.3.1
entities: 2.2.0
dev: true
/dom-serializer@2.0.0:
resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
@ -13390,7 +13412,6 @@ packages:
engines: {node: '>= 4'}
dependencies:
domelementtype: 2.3.0
dev: true
/domhandler@5.0.3:
resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
@ -13404,7 +13425,6 @@ packages:
dom-serializer: 1.4.1
domelementtype: 2.3.0
domhandler: 4.3.1
dev: true
/domutils@3.1.0:
resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==}
@ -13418,7 +13438,6 @@ packages:
dependencies:
no-case: 3.0.4
tslib: 2.6.2
dev: true
/dot-object@2.1.4:
resolution: {integrity: sha512-7FXnyyCLFawNYJ+NhkqyP9Wd2yzuo+7n9pGiYpkmXCTYa8Ci2U0eUNDVg5OuO5Pm6aFXI2SWN8/N/w7SJWu1WA==}
@ -13554,7 +13573,6 @@ packages:
/entities@2.2.0:
resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==}
dev: true
/entities@4.5.0:
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
@ -16031,7 +16049,6 @@ packages:
/he@1.2.0:
resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
hasBin: true
dev: true
/hermes-estree@0.14.0:
resolution: {integrity: sha512-L6M67+0/eSEbt6Ha2XOBFXL++7MR34EOJMgm+j7YCaI4L/jZqrVAg6zYQKzbs1ZCFDLvEQpOgLlapTX4gpFriA==}
@ -16113,7 +16130,6 @@ packages:
param-case: 3.0.4
relateurl: 0.2.7
terser: 5.29.2
dev: true
/html-parse-stringify@3.0.1:
resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==}
@ -16137,6 +16153,25 @@ packages:
resolution: {integrity: sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==}
dev: false
/html-webpack-plugin@5.6.0:
resolution: {integrity: sha512-iwaY4wzbe48AfKLZ/Cc8k0L+FKG6oSNRaZ8x5A/T/IVDGyXcbHncM9TdDa93wn0FsSm82FhTKW7f3vS61thXAw==}
engines: {node: '>=10.13.0'}
peerDependencies:
'@rspack/core': 0.x || 1.x
webpack: ^5.20.0
peerDependenciesMeta:
'@rspack/core':
optional: true
webpack:
optional: true
dependencies:
'@types/html-minifier-terser': 6.1.0
html-minifier-terser: 6.1.0
lodash: 4.17.21
pretty-error: 4.0.0
tapable: 2.2.1
dev: false
/html2canvas@1.4.1:
resolution: {integrity: sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==}
engines: {node: '>=8.0.0'}
@ -16145,6 +16180,15 @@ packages:
text-segmentation: 1.0.3
dev: false
/htmlparser2@6.1.0:
resolution: {integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==}
dependencies:
domelementtype: 2.3.0
domhandler: 4.3.1
domutils: 2.8.0
entities: 2.2.0
dev: false
/http-errors@2.0.0:
resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
engines: {node: '>= 0.8'}
@ -19787,7 +19831,6 @@ packages:
dependencies:
dot-case: 3.0.4
tslib: 2.6.2
dev: true
/parent-module@1.0.1:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
@ -20315,6 +20358,13 @@ packages:
resolution: {integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==}
engines: {node: '>=6'}
/pretty-error@4.0.0:
resolution: {integrity: sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==}
dependencies:
lodash: 4.17.21
renderkid: 3.0.0
dev: false
/pretty-format@26.6.2:
resolution: {integrity: sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==}
engines: {node: '>= 10'}
@ -20616,6 +20666,22 @@ packages:
snapsvg-cjs: 0.0.6(eve@0.5.4)
dev: false
/react-cmdk@1.3.9(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-MSVmAQZ9iqY7hO3r++XP6yWSHzGfMDGMvY3qlDT8k5RiWoRFwO1CGPlsWzhvcUbPilErzsMKK7uB4McEcX4B6g==}
peerDependencies:
react: ^16.x || ^17.x || ^18.x
react-dom: ^16.x || ^17.x || ^18.x
dependencies:
'@headlessui/react': 1.7.18(react-dom@18.2.0)(react@18.2.0)
'@heroicons/react': 2.1.3(react@18.2.0)
html-webpack-plugin: 5.6.0
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
transitivePeerDependencies:
- '@rspack/core'
- webpack
dev: false
/react-colorful@5.6.1(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==}
peerDependencies:
@ -21629,7 +21695,6 @@ packages:
/relateurl@0.2.7:
resolution: {integrity: sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==}
engines: {node: '>= 0.10'}
dev: true
/remark-frontmatter@4.0.1:
resolution: {integrity: sha512-38fJrB0KnmD3E33a5jZC/5+gGAC2WKNiPw1/fdXJvijBlhA7RCsvJklrYJakS0HedninvaCYW8lQGf9C918GfA==}
@ -21744,6 +21809,16 @@ packages:
resolution: {integrity: sha512-o4S4Qh6L2jpnCy83ysZDau+VORNvnFw07CKSAymkd6ICNVEPisMyzlc00KlvvicsxKck94SEwhDnMNdICzO+tA==}
dev: false
/renderkid@3.0.0:
resolution: {integrity: sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==}
dependencies:
css-select: 4.3.0
dom-converter: 0.2.0
htmlparser2: 6.1.0
lodash: 4.17.21
strip-ansi: 6.0.1
dev: false
/repeat-string@1.6.1:
resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==}
engines: {node: '>=0.10'}
@ -24138,6 +24213,10 @@ packages:
is-typed-array: 1.1.13
which-typed-array: 1.1.15
/utila@0.4.0:
resolution: {integrity: sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==}
dev: false
/utility-types@3.11.0:
resolution: {integrity: sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==}
engines: {node: '>= 4'}
@ -24396,7 +24475,7 @@ packages:
debug: 4.3.4(supports-color@8.1.1)
globrex: 0.1.2
tsconfck: 3.0.3(typescript@5.4.2)
vite: 5.1.6(@types/node@20.11.29)
vite: 5.1.6(sass@1.72.0)
transitivePeerDependencies:
- supports-color
- typescript
@ -24407,7 +24486,7 @@ packages:
engines: {node: ^14.18.0 || >=16.0.0}
hasBin: true
peerDependencies:
'@types/node': '>18.18.x'
'@types/node': '>= 14'
less: '*'
lightningcss: ^1.21.0
sass: '*'
@ -24442,7 +24521,7 @@ packages:
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
peerDependencies:
'@types/node': '>18.18.x'
'@types/node': ^18.0.0 || >=20.0.0
less: '*'
lightningcss: ^1.21.0
sass: '*'
@ -24477,7 +24556,7 @@ packages:
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
peerDependencies:
'@types/node': '>18.18.x'
'@types/node': ^18.0.0 || >=20.0.0
less: '*'
lightningcss: ^1.21.0
sass: '*'