) => {
93 | return args.find((array = []) => array.length > 0) || [];
94 | };
95 |
96 | const camelCaseToDash = (str: string) => str.replace(/([a-zA-Z])(?=[A-Z])/g, '$1-').toLowerCase();
97 |
98 | const toCssString = (props: Properties = {}) =>
99 | props
100 | ? // eslint-disable-next-line @typescript-eslint/ban-ts-comment
101 | // @ts-ignore
102 | Object.keys(props).reduce((str, key) => `${str}; ${camelCaseToDash(key)}: ${props[key]}`, '')
103 | : '';
104 |
105 | export {
106 | noop,
107 | defineActions,
108 | formatResults,
109 | runAction,
110 | createFuse,
111 | updatePaletteStoreAfterActionExec,
112 | getNonEmptyArray,
113 | camelCaseToDash,
114 | toCssString
115 | };
116 |
--------------------------------------------------------------------------------
/src/routes/__layout-doc.svelte:
--------------------------------------------------------------------------------
1 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/src/routes/__layout.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/routes/code/code.json.js:
--------------------------------------------------------------------------------
1 | export async function get({ url }) {
2 | const file = url.searchParams.get('file');
3 | const allFiles = import.meta.glob('./*.html', { as: 'raw' });
4 | const fileToGet = Object.keys(allFiles).find((name) => {
5 | const fileName = name.split('/').pop();
6 | return fileName === file;
7 | });
8 | return {
9 | body: {
10 | html: allFiles[fileToGet]
11 | },
12 | headers: {
13 | 'Content-type': 'application/json'
14 | }
15 | };
16 | }
17 |
--------------------------------------------------------------------------------
/src/routes/code/command-palette.html:
--------------------------------------------------------------------------------
1 | <script>
2 | import CommandPalette, { defineActions, createStoreMethods } from 'svelte-command-palette';
3 | {/* Render command palette at the root of your application */}
4 |
5 | // define actions using the defineActions API
6 |
7 | const paletteMethods = createStoreMethods();
8 |
9 | <button on:click={() => paletteMethods.openPalette()}>Open Command Palette</button>
10 |
11 | <CommandPalette
12 |
13 | actions={defineActions([
14 | {
15 | // Unique identifier for your action
16 | id: '1',
17 | // title for you action
18 | title: 'Go to github',
19 | // subtitle for the action
20 | subTitle: 'Press to redirect to github',
21 | // description of the action
22 | description: '1. something going here idk about?',
23 | // called when the action is triggered along with palette state and methods
24 | onRun: ({ action, storeProps, storeMethods }) => {
25 | console.log('do something');
26 | },
27 | // decide whether to run the action based on your palette state
28 | canActionRun: ({ action, storeProps, storeMethods }) => {
29 | return true;
30 | },
31 | // keyboard shortcut to call the action
32 | shortcut: 'G G',
33 | // allows searching for actions via keywords
34 | keywords: ['git', 'github']
35 | }
36 | ])}
37 | />
38 | </script>
39 |
--------------------------------------------------------------------------------
/src/routes/code/paletteStore.html:
--------------------------------------------------------------------------------
1 | import { paletteStore } from 'svelte-command-palette';
2 |
3 | // Update your paletteStore from anywhere in the application
4 |
5 | paletteStore.update((storeValue) => {
6 | return {
7 | ...storeValue,
8 | customValue: 'new value!'
9 | }
10 | })
11 |
12 | // You can use this custom value in your onRun / canActionRun
13 |
14 | <CommandPalette
15 | actions={defineActions([
16 | {
17 | // ..............................
18 |
19 | // called when the action is triggered along with palette state and methods
20 | onRun: ({ action, storeProps, storeMethods }) => {
21 | console.log(storeProps.customValue)
22 | // new value!
23 | },
24 | // decide whether to run the action based on your palette state
25 | canActionRun: ({ action, storeProps, storeMethods }) => {
26 | if(storeProps.customValue === 'old value') {
27 | return false
28 | }
29 | return true
30 | },
31 |
32 | }
33 | ])}
34 | />
--------------------------------------------------------------------------------
/src/routes/code/styling.html:
--------------------------------------------------------------------------------
1 | <CommandPalette
2 | unstyled={false}
3 | placeholder={paletteTheme.placeholder}
4 | commands={actions}
5 | keyboardButtonClass="bg-red-500"
6 | inputClass="bg-blue-200"
7 | overlayClass="bg-gray-200"
8 | paletteWrapperInnerClass="w-full"
9 | resultsContainerClass="h-max"
10 | resultContainerClass="bg-black"
11 | optionSelectedClass="text-blue-200"
12 | subtitleClass="text-red-200"
13 | titleClass="text-red-500"
14 | descriptionClass=""
15 | overlayStyle={{ width: "200px", height: '500px' }}
16 | paletteWrapperInnerStyle={{ width: "200px", height: '500px' }}
17 | inputStyle={paletteTheme.inputStyles}
18 | resultsContainerStyle={paletteTheme.resultsContainerStyle}
19 | resultContainerStyle={paletteTheme.resultContainerStyle}
20 | titleStyle={paletteTheme.titleStyle}
21 | descriptionStyle={paletteTheme.descriptionStyle}
22 | subtitleStyle={paletteTheme.subtitleStyle}
23 | optionSelectedStyle={currentTheme === 'light'
24 | ? { background: 'skyblue' }
25 | : { background: 'blue' }}
26 | keyboardButtonStyle={{}}
27 | />
--------------------------------------------------------------------------------
/src/routes/docs/__layout@doc.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/routes/docs/command-palette-api.svelte:
--------------------------------------------------------------------------------
1 |
12 |
13 |
17 |
18 |
19 |
Command Palette API
20 |
21 | Actions can be defined with the defineActions API.
22 |
23 |
24 | These actions can then be passed to CommandPalette
25 |
26 | Render CommandPalette at the root of your application.
27 |
28 |
29 | {@html html}
30 |
31 |
37 |
--------------------------------------------------------------------------------
/src/routes/docs/define-actions.svelte:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/routes/docs/index.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/routes/docs/palette-store.svelte:
--------------------------------------------------------------------------------
1 |
12 |
13 |
16 |
17 |
Palette Store
18 |
19 | Palette store is a normal svelte store, you can update or subscribe to paletteStore like any svelte store.
20 |
21 |
22 |
23 | {@html html}
24 |
25 |
31 |
--------------------------------------------------------------------------------
/src/routes/docs/styling.svelte:
--------------------------------------------------------------------------------
1 |
12 |
13 |
16 |
17 |
18 |
Styling
19 |
20 | You have complete control over the styling of the command palette
21 |
22 |
23 |
24 | You can use classes (tailwind too) to style the command palette. Note that svelte applies the
25 | scoped classes with priority, to overwrite this, pass unstyled={true}
26 |
27 |
28 |
29 | Or just directly pass css styles to completely change the look and feel of the command palette
30 |
31 |
32 |
33 | {@html html}
34 |
35 |
41 |
--------------------------------------------------------------------------------
/src/routes/index.svelte:
--------------------------------------------------------------------------------
1 |
159 |
160 |
175 |
176 |
177 |
178 |
179 |
186 |
--------------------------------------------------------------------------------
/src/store/themeStore.ts:
--------------------------------------------------------------------------------
1 | import { writable } from 'svelte/store';
2 |
3 | type Theme = string | null;
4 |
5 | const themeStore = writable(null);
6 |
7 | export default themeStore;
8 |
--------------------------------------------------------------------------------
/src/utils/switchTheme.js:
--------------------------------------------------------------------------------
1 | import themeStore from '../store/themeStore';
2 | const LIGHT = 'light';
3 | const DARK = 'dark';
4 |
5 | const handleThemeSwitch = () => {
6 | const theme = localStorage.getItem('theme') || 'light';
7 | const root = window.document.documentElement;
8 | const isDark = theme === DARK;
9 | root.classList.remove(theme);
10 | root.classList.add(isDark ? LIGHT : DARK);
11 | localStorage.setItem('theme', isDark ? LIGHT : DARK);
12 | themeStore.set(isDark ? LIGHT : DARK);
13 | };
14 |
15 | export default handleThemeSwitch;
16 |
--------------------------------------------------------------------------------
/static/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rohitpotato/svelte-command-palette/c8f0e297e61c2e65908350463e782e1917cf0005/static/favicon.png
--------------------------------------------------------------------------------
/static/tailwind.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rohitpotato/svelte-command-palette/c8f0e297e61c2e65908350463e782e1917cf0005/static/tailwind.png
--------------------------------------------------------------------------------
/svelte.config.js:
--------------------------------------------------------------------------------
1 | import adapter from '@sveltejs/adapter-auto';
2 | import preprocess from 'svelte-preprocess';
3 |
4 | /** @type {import('@sveltejs/kit').Config} */
5 | const config = {
6 | // Consult https://github.com/sveltejs/svelte-preprocess
7 | // for more information about preprocessors
8 | preprocess: preprocess({
9 | postcss: true
10 | }),
11 |
12 | kit: {
13 | adapter: adapter(),
14 | vite: {
15 | serve: {
16 | fs: {
17 | allow: ['./package']
18 | }
19 | }
20 | }
21 | }
22 | };
23 |
24 | export default config;
25 |
--------------------------------------------------------------------------------
/tailwind.config.cjs:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | darkMode: 'class',
4 | content: ['./src/**/*.{html,js,svelte,ts}'],
5 | theme: {
6 | extend: {
7 | colors: {
8 | 'svelte-brand': '#e44c1c',
9 | 'dark-mode-black': '#121212',
10 | 'light-gray': '#ECEDF3',
11 | 'dark-mode-gray': '#212121',
12 | 'dark-text-gray': '#313654'
13 | }
14 | }
15 | },
16 | plugins: []
17 | };
18 |
--------------------------------------------------------------------------------
/tests/test.ts:
--------------------------------------------------------------------------------
1 | import { expect, test } from '@playwright/test';
2 |
3 | test('index page has expected h1', async ({ page }) => {
4 | await page.goto('/');
5 | expect(await page.textContent('h1')).toBe('Welcome to SvelteKit');
6 | });
7 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./.svelte-kit/tsconfig.json",
3 | "compilerOptions": {
4 | "allowJs": true,
5 | "lib": ["dom"],
6 | "checkJs": true,
7 | "esModuleInterop": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "resolveJsonModule": true,
10 | "skipLibCheck": true,
11 | "sourceMap": true,
12 | "strict": true
13 | }
14 | }
15 |
--------------------------------------------------------------------------------