mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
feat(wip): ai command panel
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
<script lang="ts">
|
||||
import { afterNavigate } from '$app/navigation';
|
||||
import { Root } from './panels';
|
||||
import { last } from '$lib/helpers/array';
|
||||
import { addSubPanel, clearSubPanels, subPanels } from './subPanels';
|
||||
import { commandCenterKeyDownHandler, disableCommands, registerCommands } from './commands';
|
||||
|
||||
$: $registerCommands([
|
||||
{
|
||||
callback: () => {
|
||||
if ($subPanels.length > 0) {
|
||||
clearSubPanels();
|
||||
} else {
|
||||
addSubPanel({
|
||||
name: 'commandPanel',
|
||||
component: Root
|
||||
});
|
||||
}
|
||||
},
|
||||
keys: ['k'],
|
||||
ctrl: true,
|
||||
forceEnable: true
|
||||
}
|
||||
]);
|
||||
|
||||
$: openSubPanel = last($subPanels) ?? null;
|
||||
$: $disableCommands(!!openSubPanel);
|
||||
|
||||
$: if (openSubPanel) {
|
||||
document.documentElement.classList.add('u-overflow-hidden');
|
||||
} else {
|
||||
document.documentElement.classList.remove('u-overflow-hidden');
|
||||
}
|
||||
|
||||
afterNavigate(() => {
|
||||
clearSubPanels();
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:window on:keydown={$commandCenterKeyDownHandler} />
|
||||
|
||||
{#if openSubPanel}
|
||||
<svelte:component this={openSubPanel.component} />
|
||||
{/if}
|
||||
@@ -1,7 +1,8 @@
|
||||
import { debounce } from '$lib/helpers/debounce';
|
||||
import { isMac } from '$lib/helpers/platform';
|
||||
import { derived, writable } from 'svelte/store';
|
||||
import { debounce } from './debounce';
|
||||
import { isMac } from './platform';
|
||||
|
||||
// Store
|
||||
export type Command = {
|
||||
keys: string[];
|
||||
/* Ctrl on Windows/Linux, Meta on Mac */
|
||||
@@ -15,73 +16,27 @@ export type Command = {
|
||||
forceEnable?: boolean;
|
||||
};
|
||||
|
||||
type CommandCenterState = {
|
||||
commandMap: Map<string, Command[]>;
|
||||
disabledMap: Map<string, boolean>;
|
||||
};
|
||||
export const commandMap = writable<Map<string, Command[]>>(new Map());
|
||||
export const disabledMap = writable<Map<string, boolean>>(new Map());
|
||||
|
||||
export const commandCenter = writable<CommandCenterState>({
|
||||
commandMap: new Map(),
|
||||
disabledMap: new Map()
|
||||
// Derived stores
|
||||
export const commands = derived(commandMap, ($commandMap) => {
|
||||
return Array.from($commandMap.values()).flat();
|
||||
});
|
||||
|
||||
export const commands = derived(commandCenter, ($commandCenter) => {
|
||||
return Array.from($commandCenter.commandMap.values()).flat();
|
||||
});
|
||||
|
||||
const commandsEnabled = derived(commandCenter, ($commandCenter) => {
|
||||
const commandsEnabled = derived(disabledMap, ($disabledMap) => {
|
||||
// If there's an item on the disabledMap that's true, then disable the command center
|
||||
return Array.from($commandCenter.disabledMap.values()).every((disabled) => !disabled);
|
||||
return Array.from($disabledMap.values()).every((disabled) => !disabled);
|
||||
});
|
||||
|
||||
export const registerCommands = {
|
||||
subscribe(runner: (cb: (newCommands: Command[]) => void) => void) {
|
||||
const uuid = crypto.randomUUID();
|
||||
|
||||
runner((newCommands: Command[]) => {
|
||||
commandCenter.update((curr) => {
|
||||
curr.commandMap.set(uuid, newCommands);
|
||||
return curr;
|
||||
});
|
||||
});
|
||||
|
||||
return () => {
|
||||
commandCenter.update((curr) => {
|
||||
curr.commandMap.delete(uuid);
|
||||
return curr;
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export const disableCommands = {
|
||||
subscribe(runner: (cb: (disabled: boolean) => void) => void) {
|
||||
const uuid = crypto.randomUUID();
|
||||
|
||||
runner((disabled: boolean) => {
|
||||
commandCenter.update((curr) => {
|
||||
curr.disabledMap.set(uuid, disabled);
|
||||
return curr;
|
||||
});
|
||||
});
|
||||
|
||||
return () => {
|
||||
commandCenter.update((curr) => {
|
||||
curr.disabledMap.delete(uuid);
|
||||
return curr;
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
function isInputEvent(event: KeyboardEvent) {
|
||||
return ['INPUT', 'TEXTAREA', 'SELECT'].includes((event.target as HTMLElement).tagName);
|
||||
}
|
||||
|
||||
export const commandCenterKeyDownHandler = derived(
|
||||
[commandCenter, commandsEnabled],
|
||||
([{ commandMap }, enabled]) => {
|
||||
const commandsArr = Array.from(commandMap.values()).flat();
|
||||
[commandMap, commandsEnabled],
|
||||
([$commandMap, enabled]) => {
|
||||
const commandsArr = Array.from($commandMap.values()).flat();
|
||||
let recentKeyCodes: number[] = [];
|
||||
|
||||
return (event: KeyboardEvent) => {
|
||||
@@ -113,3 +68,44 @@ export const commandCenterKeyDownHandler = derived(
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
// Methods
|
||||
export const registerCommands = {
|
||||
subscribe(runner: (cb: (newCommands: Command[]) => void) => void) {
|
||||
const uuid = crypto.randomUUID();
|
||||
|
||||
runner((newCommands: Command[]) => {
|
||||
commandMap.update((curr) => {
|
||||
curr.set(uuid, newCommands);
|
||||
return curr;
|
||||
});
|
||||
});
|
||||
|
||||
return () => {
|
||||
commandMap.update((curr) => {
|
||||
curr.delete(uuid);
|
||||
return curr;
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export const disableCommands = {
|
||||
subscribe(runner: (cb: (disabled: boolean) => void) => void) {
|
||||
const uuid = crypto.randomUUID();
|
||||
|
||||
runner((disabled: boolean) => {
|
||||
disabledMap.update((curr) => {
|
||||
curr.set(uuid, disabled);
|
||||
return curr;
|
||||
});
|
||||
});
|
||||
|
||||
return () => {
|
||||
disabledMap.update((curr) => {
|
||||
curr.delete(uuid);
|
||||
return curr;
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from './commands';
|
||||
export * from './subPanels';
|
||||
import CommandCenter from './commandCenter.svelte';
|
||||
export { CommandCenter };
|
||||
@@ -0,0 +1,5 @@
|
||||
<script lang="ts">
|
||||
import Template from './template.svelte';
|
||||
</script>
|
||||
|
||||
<Template>Ask AI yaaaay</Template>
|
||||
@@ -0,0 +1,4 @@
|
||||
import AI from './ai.svelte';
|
||||
import Root from './root.svelte';
|
||||
import Template from './template.svelte';
|
||||
export { AI, Root, Template };
|
||||
@@ -0,0 +1,54 @@
|
||||
<!--
|
||||
This is the root command panel. It precedes all other command panels.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { commands } from '../commands';
|
||||
import { isMac } from '$lib/helpers/platform';
|
||||
import Template from './template.svelte';
|
||||
|
||||
let search = '';
|
||||
|
||||
$: results = $commands.filter((command) => {
|
||||
return (
|
||||
!command.disabled &&
|
||||
command.label &&
|
||||
command.label.toLowerCase().includes(search.toLowerCase())
|
||||
);
|
||||
});
|
||||
</script>
|
||||
|
||||
<Template options={results}>
|
||||
<div slot="option" class="u-flex u-main-space-between content" let:option={command}>
|
||||
<span>
|
||||
{command.label}
|
||||
</span>
|
||||
<div class="u-flex u-gap-4 u-cross-center">
|
||||
{#if command.ctrl}
|
||||
<kbd class="kbd"> {isMac() ? '⌘' : 'ctrl'} </kbd>
|
||||
{/if}
|
||||
{#if command.shift}
|
||||
<kbd class="kbd"> {isMac() ? '⇧' : 'shift'} </kbd>
|
||||
{/if}
|
||||
{#if command.alt}
|
||||
<kbd class="kbd"> {isMac() ? '⌥' : 'alt'} </kbd>
|
||||
{/if}
|
||||
{#each command.keys as key, i}
|
||||
{@const hasNext = command.keys.length - 1 !== i}
|
||||
|
||||
<kbd class="kbd">
|
||||
{key.toUpperCase()}
|
||||
</kbd>
|
||||
{#if hasNext}
|
||||
<span class="u-margin-inline-4" style:opacity={0.5}>then</span>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
<svelte:fragment slot="no-options">No commands found</svelte:fragment>
|
||||
</Template>
|
||||
|
||||
<style>
|
||||
.kbd {
|
||||
padding-inline: 0.25rem;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,130 @@
|
||||
<!--
|
||||
This is the template for all panels used in the command center.
|
||||
Use this component when you want to create a new panel.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { popSubPanel, subPanels } from '../subPanels';
|
||||
|
||||
import Dialog from '$lib/components/dialog.svelte';
|
||||
import { quadOut } from 'svelte/easing';
|
||||
import { crossfade } from 'svelte/transition';
|
||||
|
||||
type BaseOption = { callback: () => void };
|
||||
type Option = $$Generic<BaseOption>;
|
||||
export let options: Option[] | null = null;
|
||||
export let search = '';
|
||||
|
||||
let selected = 0;
|
||||
|
||||
function handleKeyDown(event: KeyboardEvent) {
|
||||
if (!open) return;
|
||||
if (event.key === 'ArrowDown') {
|
||||
event.preventDefault();
|
||||
if (event.metaKey) {
|
||||
selected = options.length - 1;
|
||||
} else {
|
||||
selected = selected === options.length - 1 ? options.length - 1 : selected + 1;
|
||||
}
|
||||
} else if (event.key === 'ArrowUp') {
|
||||
event.preventDefault();
|
||||
if (event.metaKey) {
|
||||
selected = 0;
|
||||
} else {
|
||||
selected = selected === 0 ? 0 : selected - 1;
|
||||
}
|
||||
} else if (event.key === 'Enter') {
|
||||
event.preventDefault();
|
||||
if (options[selected]) {
|
||||
options[selected].callback();
|
||||
}
|
||||
} else if (event.key === 'Home') {
|
||||
event.preventDefault();
|
||||
selected = 0;
|
||||
} else if (event.key === 'End') {
|
||||
event.preventDefault();
|
||||
selected = options.length - 1;
|
||||
}
|
||||
}
|
||||
|
||||
$: {
|
||||
options;
|
||||
selected = 0;
|
||||
}
|
||||
|
||||
const [send, receive] = crossfade({
|
||||
duration: 150,
|
||||
easing: quadOut
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:window on:keydown={handleKeyDown} />
|
||||
|
||||
<Dialog on:close={popSubPanel}>
|
||||
<div class="u-flex u-flex-vertical u-width-full-line">
|
||||
{#if $subPanels.length}
|
||||
aaa
|
||||
{/if}
|
||||
<input type="text" placeholder="type here..." autofocus bind:value={search} />
|
||||
|
||||
{#if options}
|
||||
<ul class="u-margin-block-start-16 u-flex u-flex-vertical u-gap-8">
|
||||
{#each options as option, i}
|
||||
<li class="result" data-selected={selected === i ? true : undefined}>
|
||||
{#if selected === i}
|
||||
<div
|
||||
class="bg"
|
||||
in:send|local={{ key: 'bg' }}
|
||||
out:receive|local={{ key: 'bg' }} />
|
||||
{/if}
|
||||
<div class="option">
|
||||
<slot name="option" {option} />
|
||||
</div>
|
||||
</li>
|
||||
{:else}
|
||||
<li class="result">
|
||||
<slot name="no-options">
|
||||
<span class="text">No options found</span>
|
||||
</slot>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
{:else}
|
||||
<slot />
|
||||
{/if}
|
||||
</div>
|
||||
</Dialog>
|
||||
|
||||
<style>
|
||||
input {
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.result {
|
||||
padding: 0.5rem 0.75rem;
|
||||
transition: 150ms;
|
||||
position: relative;
|
||||
|
||||
opacity: 0.65;
|
||||
transition: 75ms cubic-bezier(0.5, 1, 0.89, 1);
|
||||
}
|
||||
|
||||
.result[data-selected] {
|
||||
opacity: 1;
|
||||
transition: 150ms cubic-bezier(0.5, 1, 0.89, 1);
|
||||
}
|
||||
|
||||
.result .bg {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background-color: hsl(var(--color-neutral-200));
|
||||
border-radius: 0.75rem;
|
||||
translate: 0 -1px;
|
||||
}
|
||||
|
||||
.result .option {
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,32 @@
|
||||
import type { SvelteComponentDev } from 'svelte/internal';
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
export type SubPanel = {
|
||||
name: string;
|
||||
component: typeof SvelteComponentDev;
|
||||
};
|
||||
|
||||
type CastSubPanel = Omit<SubPanel, 'component'> & {
|
||||
component: unknown;
|
||||
};
|
||||
|
||||
export const subPanels = writable<Array<SubPanel>>([]);
|
||||
|
||||
//
|
||||
export function addSubPanel(subPanel: CastSubPanel) {
|
||||
subPanels.update((curr) => {
|
||||
curr.push(subPanel as SubPanel);
|
||||
return curr;
|
||||
});
|
||||
}
|
||||
|
||||
export function popSubPanel() {
|
||||
subPanels.update((curr) => {
|
||||
curr = curr.slice(0, -1);
|
||||
return curr;
|
||||
});
|
||||
}
|
||||
|
||||
export function clearSubPanels() {
|
||||
subPanels.set([]);
|
||||
}
|
||||
@@ -1,28 +1,12 @@
|
||||
<script lang="ts">
|
||||
import { trackEvent } from '$lib/actions/analytics';
|
||||
import { createEventDispatcher, onDestroy, onMount } from 'svelte';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import { fade, scale } from 'svelte/transition';
|
||||
|
||||
export let show = false;
|
||||
export let size: 'small' | 'big' = null;
|
||||
export let error: string = null;
|
||||
export let closable = true;
|
||||
export let headerDivider = true;
|
||||
export let animate = true;
|
||||
|
||||
let dialog: HTMLDivElement;
|
||||
let alert: HTMLElement;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
onMount(() => {
|
||||
if (show) openModal();
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
if (show) closeModal();
|
||||
});
|
||||
|
||||
function handleBLur(event: MouseEvent) {
|
||||
if (event.target === dialog) {
|
||||
trackEvent('click_close_modal', {
|
||||
@@ -31,16 +15,9 @@
|
||||
closeModal();
|
||||
}
|
||||
}
|
||||
function openModal() {
|
||||
document.documentElement.classList.add('u-overflow-hidden');
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
if (closable) {
|
||||
dispatch('close');
|
||||
show = false;
|
||||
document.documentElement.classList.remove('u-overflow-hidden');
|
||||
}
|
||||
dispatch('close');
|
||||
}
|
||||
|
||||
function handleKeydown(event: KeyboardEvent) {
|
||||
@@ -52,34 +29,15 @@
|
||||
closeModal();
|
||||
}
|
||||
}
|
||||
|
||||
$: if (show) {
|
||||
openModal();
|
||||
} else {
|
||||
closeModal();
|
||||
}
|
||||
|
||||
$: if (error) {
|
||||
alert?.scrollIntoView({ behavior: 'smooth', block: 'start', inline: 'nearest' });
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window on:mousedown={handleBLur} on:keydown={handleKeydown} />
|
||||
|
||||
{#if show}
|
||||
<div
|
||||
class="dialog"
|
||||
class:is-small={size === 'small'}
|
||||
class:is-big={size === 'big'}
|
||||
class:is-separate-header={headerDivider}
|
||||
on:cancel|preventDefault
|
||||
bind:this={dialog}
|
||||
transition:fade={{ duration: animate ? 150 : 0 }}>
|
||||
<div class="card" transition:scale={{ duration: animate ? 150 : 0, start: 0.9 }}>
|
||||
<slot />
|
||||
</div>
|
||||
<div class="dialog" bind:this={dialog} transition:fade={{ duration: 150 }}>
|
||||
<div class="card" transition:scale={{ duration: 150, start: 0.9 }}>
|
||||
<slot />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.dialog {
|
||||
|
||||
@@ -16,10 +16,22 @@
|
||||
import Create from './createOrganization.svelte';
|
||||
|
||||
import { goto } from '$app/navigation';
|
||||
import { registerCommands, commandCenterKeyDownHandler } from '$lib/helpers/commandCenter';
|
||||
import CommandCenter from './commandCenter.svelte';
|
||||
|
||||
import { addSubPanel } from '$lib/commandCenter/subPanels';
|
||||
import { registerCommands, CommandCenter } from '$lib/commandCenter';
|
||||
import { AI } from '$lib/commandCenter/panels';
|
||||
|
||||
$: $registerCommands([
|
||||
{
|
||||
label: 'Ask AI',
|
||||
callback: () => {
|
||||
addSubPanel({
|
||||
name: 'Ask AI',
|
||||
component: AI
|
||||
});
|
||||
},
|
||||
keys: ['a', 'i']
|
||||
},
|
||||
{
|
||||
label: 'Go to Account',
|
||||
callback: () => {
|
||||
@@ -69,8 +81,6 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window on:keydown={$commandCenterKeyDownHandler} />
|
||||
|
||||
<CommandCenter />
|
||||
|
||||
<Shell
|
||||
|
||||
@@ -1,166 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { afterNavigate } from '$app/navigation';
|
||||
import Dialog from '$lib/components/dialog.svelte';
|
||||
import { commands, disableCommands, registerCommands } from '$lib/helpers/commandCenter';
|
||||
import { isMac } from '$lib/helpers/platform';
|
||||
import { quadOut } from 'svelte/easing';
|
||||
import { crossfade } from 'svelte/transition';
|
||||
|
||||
let open = false;
|
||||
let search = '';
|
||||
let selected = 0;
|
||||
|
||||
$: $registerCommands([
|
||||
{
|
||||
callback: () => {
|
||||
open = !open;
|
||||
},
|
||||
keys: ['k'],
|
||||
ctrl: true,
|
||||
forceEnable: true
|
||||
}
|
||||
]);
|
||||
|
||||
$: results = $commands.filter((command) => {
|
||||
return (
|
||||
!command.disabled &&
|
||||
command.label &&
|
||||
command.label.toLowerCase().includes(search.toLowerCase())
|
||||
);
|
||||
});
|
||||
|
||||
function handleKeyDown(event: KeyboardEvent) {
|
||||
if (!open) return;
|
||||
if (event.key === 'ArrowDown') {
|
||||
event.preventDefault();
|
||||
if (event.metaKey) {
|
||||
selected = results.length - 1;
|
||||
} else {
|
||||
selected = selected === results.length - 1 ? results.length - 1 : selected + 1;
|
||||
}
|
||||
} else if (event.key === 'ArrowUp') {
|
||||
event.preventDefault();
|
||||
if (event.metaKey) {
|
||||
selected = 0;
|
||||
} else {
|
||||
selected = selected === 0 ? 0 : selected - 1;
|
||||
}
|
||||
} else if (event.key === 'Enter') {
|
||||
event.preventDefault();
|
||||
if (results[selected]) {
|
||||
results[selected].callback();
|
||||
open = false;
|
||||
search = '';
|
||||
}
|
||||
} else if (event.key === 'Home') {
|
||||
event.preventDefault();
|
||||
selected = 0;
|
||||
} else if (event.key === 'End') {
|
||||
event.preventDefault();
|
||||
selected = results.length - 1;
|
||||
}
|
||||
}
|
||||
|
||||
$: {
|
||||
results;
|
||||
selected = 0;
|
||||
}
|
||||
|
||||
$: $disableCommands(open);
|
||||
|
||||
const [send, receive] = crossfade({
|
||||
duration: 150,
|
||||
easing: quadOut
|
||||
});
|
||||
|
||||
afterNavigate(() => {
|
||||
open = false;
|
||||
search = '';
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:window on:keydown={handleKeyDown} />
|
||||
|
||||
<Dialog bind:show={open}>
|
||||
<div class="u-flex u-flex-vertical u-width-full-line">
|
||||
<input type="text" placeholder="type here..." autofocus bind:value={search} />
|
||||
|
||||
<ul class="u-margin-block-start-16 u-flex u-flex-vertical u-gap-8">
|
||||
{#each results as command, i}
|
||||
<li class="result" data-selected={selected === i ? true : undefined}>
|
||||
{#if selected === i}
|
||||
<div class="bg" in:send={{ key: 'bg' }} out:receive={{ key: 'bg' }} />
|
||||
{/if}
|
||||
<div class="u-flex u-main-space-between content">
|
||||
<span>
|
||||
{command.label}
|
||||
</span>
|
||||
<div class="u-flex u-gap-4 u-cross-center">
|
||||
{#if command.ctrl}
|
||||
<kbd class="kbd"> {isMac() ? '⌘' : 'ctrl'} </kbd>
|
||||
{/if}
|
||||
{#if command.shift}
|
||||
<kbd class="kbd"> {isMac() ? '⇧' : 'shift'} </kbd>
|
||||
{/if}
|
||||
{#if command.alt}
|
||||
<kbd class="kbd"> {isMac() ? '⌥' : 'alt'} </kbd>
|
||||
{/if}
|
||||
{#each command.keys as key, i}
|
||||
{@const hasNext = command.keys.length - 1 !== i}
|
||||
|
||||
<kbd class="kbd">
|
||||
{key.toUpperCase()}
|
||||
</kbd>
|
||||
{#if hasNext}
|
||||
<span class="u-margin-inline-4" style:opacity={0.5}>then</span>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{:else}
|
||||
<li class="result">
|
||||
<span class="text">No commands found</span>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
</Dialog>
|
||||
|
||||
<style>
|
||||
input {
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.result {
|
||||
padding: 0.5rem 0.75rem;
|
||||
transition: 150ms;
|
||||
position: relative;
|
||||
|
||||
opacity: 0.65;
|
||||
transition: 75ms cubic-bezier(0.5, 1, 0.89, 1);
|
||||
}
|
||||
|
||||
.result[data-selected] {
|
||||
opacity: 1;
|
||||
transition: 150ms cubic-bezier(0.5, 1, 0.89, 1);
|
||||
}
|
||||
|
||||
.result .content {
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.result .bg {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background-color: hsl(var(--color-neutral-200));
|
||||
border-radius: 0.75rem;
|
||||
translate: 0 -1px;
|
||||
}
|
||||
|
||||
.kbd {
|
||||
padding-inline: 0.25rem;
|
||||
}
|
||||
</style>
|
||||
@@ -2,10 +2,11 @@
|
||||
import { goto } from '$app/navigation';
|
||||
import { base } from '$app/paths';
|
||||
import { page } from '$app/stores';
|
||||
import { registerCommands } from '$lib/commandCenter';
|
||||
import { CardContainer, Empty, GridItem1, Heading, PaginationWithLimit } from '$lib/components';
|
||||
import { Pill } from '$lib/elements';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { registerCommands } from '$lib/helpers/commandCenter';
|
||||
|
||||
import { Container } from '$lib/layout';
|
||||
import CreateOrganization from '../createOrganization.svelte';
|
||||
import type { PageData } from './$types';
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { onMount } from 'svelte';
|
||||
import { project, stats } from './store';
|
||||
import { registerCommands } from '$lib/helpers/commandCenter';
|
||||
|
||||
import { goto } from '$app/navigation';
|
||||
import { registerCommands } from '$lib/commandCenter';
|
||||
|
||||
onMount(async () => {
|
||||
return sdk.forConsole.client.subscribe(['project', 'console'], (response) => {
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
import { project } from '../store';
|
||||
import type { PageData } from './$types';
|
||||
import Create from './createUser.svelte';
|
||||
import { registerCommands } from '$lib/helpers/commandCenter';
|
||||
import { registerCommands } from '$lib/commandCenter';
|
||||
|
||||
export let data: PageData;
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
import Grid from './grid.svelte';
|
||||
import { columns } from './store';
|
||||
import Table from './table.svelte';
|
||||
import { registerCommands } from '$lib/helpers/commandCenter';
|
||||
import { registerCommands } from '$lib/commandCenter';
|
||||
|
||||
export let data: PageData;
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
import type { PageData } from './$types';
|
||||
import Create from './createFunction.svelte';
|
||||
|
||||
import { registerCommands } from '$lib/helpers/commandCenter';
|
||||
import { registerCommands } from '$lib/commandCenter';
|
||||
|
||||
export let data: PageData;
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
import { toLocaleDateTime } from '$lib/helpers/date';
|
||||
import { app } from '$lib/stores/app';
|
||||
import type { PageData } from './$types';
|
||||
import { registerCommands } from '$lib/helpers/commandCenter';
|
||||
import { registerCommands } from '$lib/commandCenter';
|
||||
|
||||
export let data: PageData;
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { Container } from '$lib/layout';
|
||||
import type { Models } from '@appwrite.io/console';
|
||||
import { registerCommands } from '$lib/helpers/commandCenter';
|
||||
import { registerCommands } from '$lib/commandCenter';
|
||||
import type { PageData } from './$types';
|
||||
import Create from './create.svelte';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user