Skip to content

Commit

Permalink
feat: add focusable elements, add keyboard shortcuts for query input
Browse files Browse the repository at this point in the history
  • Loading branch information
invm committed Aug 12, 2023
1 parent 45fb652 commit 0c425df
Show file tree
Hide file tree
Showing 9 changed files with 190 additions and 89 deletions.
33 changes: 20 additions & 13 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import { ThemeSwitch } from "components/UI/ThemeSwitch";
import { Console } from "components/Screens/Console/Console";
import { Home } from "components/Screens/Home/Home";
import "tabulator-tables/dist/css/tabulator_midnight.min.css";
import { Root, CommandPalette } from 'solid-command-palette';
import { actions } from './actions';
import 'solid-command-palette/pkg-dist/style.css';
import { Root, CommandPalette } from "solid-command-palette";
import { actions } from "./actions";
import "solid-command-palette/pkg-dist/style.css";

function App() {
const {
Expand All @@ -19,15 +19,18 @@ function App() {
connectionStore,
setConnectionStore,
},
appService: { toggleThemeSwitcher },
} = useAppSelector();

const closeTab = async (id: string) => {
await removeTab(id);
};

const actionsContext = {
increment() {
console.log("increment count state by 1");
showThemeSwitcher() {
toggleThemeSwitcher();
// FIXME: focuses only on first render
document.getElementById("theme-switch")?.focus();
},
};

Expand All @@ -38,32 +41,36 @@ function App() {
<div class="px-2 pb-2 bg-base-300 tabs tabs-boxed rounded-none gap-2 flex justify-between items-center">
<div class="flex items-center">
<div class="flex items-center">
<div
<button
onClick={() => {
setConnectionStore("idx", 0);
}}
class="tab tab-md"
tabIndex={0}
classList={{ "tab-active": connectionStore.idx === 0 }}
>
<span class="text-md font-bold">Home</span>
</div>
</button>
</div>
<For each={connectionStore.tabs}>
{(tab, idx) => (
<div class="flex items-center">
<div
onClick={() => {
setConnectionStore("idx", idx() + 1);
}}
<button
onClick={() => setConnectionStore("idx", idx() + 1)}
class="tab tab-md"
classList={{
"tab-active": connectionStore.idx === idx() + 1,
}}
tabindex={0}
>
<span class="text-md font-bold">{tab.label}</span>
</div>
</button>
<Show when={connectionStore.idx === idx() + 1}>
<button onClick={() => closeTab(tab.id!)} class="pl-2 mb-1">
<button
tabindex={0}
onClick={() => closeTab(tab.id!)}
class="ml-2 mb-1"
>
<CloseIcon />
</button>
</Show>
Expand Down
35 changes: 18 additions & 17 deletions src/actions.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
import { defineAction } from 'solid-command-palette';
import { useAppSelector } from "services/Context";
import { ActionContext, defineAction } from "solid-command-palette";

const minimalAction = defineAction({
id: 'minimal',
title: 'Minimal Action',
run: () => {
console.log('ran minimal action');
},
});

const incrementCounterAction = defineAction({
id: 'increment-counter',
title: 'Increment Counter by 1',
subtitle: 'Press CMD + E to trigger this.',
shortcut: '$mod+e', // $mod = Command on Mac & Control on Windows.
const showThemeSwitcher = defineAction({
id: "toggle-theme-switcher",
title: "Toggle Theme Switcher",
run: ({ rootContext }) => {
rootContext.increment();
(rootContext as any).showThemeSwitcher();
},
});

// const incrementCounterAction = defineAction({
// id: "increment-counter",
// title: "Increment Counter by 1",
// subtitle: "Press CMD + E to trigger this.",
// shortcut: "$mod+e", // $mod = Command on Mac & Control on Windows.
// run: ({ rootContext }) => {
// (rootContext as ActionsContext).increment();
// },
// });

export const actions = {
[minimalAction.id]: minimalAction,
[incrementCounterAction.id]: incrementCounterAction,
[showThemeSwitcher.id]: showThemeSwitcher,
// [incrementCounterAction.id]: incrementCounterAction,
};

65 changes: 46 additions & 19 deletions src/components/Screens/Console/Content/Content.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { For, Match, Show, Switch } from "solid-js"
import { For, Match, Show, Switch } from "solid-js";
import { useAppSelector } from "services/Context";
import { AddIcon, CloseIcon } from "components/UI/Icons";
import { t } from "utils/i18n";
Expand All @@ -7,47 +7,74 @@ import { TableStructureTab } from "./TableStructureTab";
import { ContentComponent, NEW_QUERY_TAB } from "services/ConnectionTabs";

export const Content = () => {
const { connectionsService: { contentStore, setContentStore } } = useAppSelector()
const {
connectionsService: { contentStore, setContentStore },
} = useAppSelector();

const addTab = async () => {
setContentStore('tabs', [...contentStore.tabs, NEW_QUERY_TAB])
setContentStore('idx', contentStore.tabs.length - 1)
}
setContentStore("tabs", [...contentStore.tabs, NEW_QUERY_TAB]);
setContentStore("idx", contentStore.tabs.length - 1);
};

const closeTab = async (idx: number) => {
if (!idx) return;
setContentStore('tabs', contentStore.tabs.filter((_t, i) => i !== idx));
setContentStore('idx', 0)
}
setContentStore(
"tabs",
contentStore.tabs.filter((_t, i) => i !== idx)
);
setContentStore("idx", 0);
};

return (
<div class="flex flex-col h-full">
<div class="bg-base-300 tabs gap-1">
<For each={contentStore.tabs}>
{(_tab, idx) =>
<div onClick={() => setContentStore('idx', idx())} class="tab py-2 tab-md tab-lifted"
classList={{ 'tab-active': contentStore.idx === idx() }}
>{t('components.console.query')} #{idx() + 1}
{(_tab, idx) => (
<div
class="tab py-2 tab-md tab-lifted"
classList={{ "tab-active": contentStore.idx === idx() }}
>
<button
class="text-xs"
tabindex={0}
onClick={() => setContentStore("idx", idx())}
>
{t("components.console.query")} #{idx() + 1}
</button>
<Show when={idx() > 0}>
<button onClick={() => closeTab(idx())} class="pl-2 mb-1">
<button onClick={() => closeTab(idx())} class="ml-2 mb-1">
<CloseIcon />
</button>
</Show>
</div>
}
)}
</For>
<div onClick={() => addTab()} class="tab py-2 tab-sm tab-lifted tab-active" ><AddIcon /></div>
<div class="tab py-2 tab-sm tab-lifted tab-active">
<button onClick={() => addTab()}>
<AddIcon />
</button>
</div>
</div>
<div class="flex-1 overflow-hidden">
<Switch>
<Match when={contentStore.tabs[contentStore.idx]?.key === ContentComponent.QueryTab}>
<Match
when={
contentStore.tabs[contentStore.idx]?.key ===
ContentComponent.QueryTab
}
>
<QueryTab />
</Match>
<Match when={contentStore.tabs[contentStore.idx]?.key === ContentComponent.TableStructureTab}>
<Match
when={
contentStore.tabs[contentStore.idx]?.key ===
ContentComponent.TableStructureTab
}
>
<TableStructureTab />
</Match>
</Switch>
</div>
</div>
)
}
);
};
18 changes: 13 additions & 5 deletions src/components/Screens/Console/Content/QueryTab/QueryTextArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ export const QueryTextArea = () => {
connId: activeConnection.id,
query: code(),
});
console.log(result);
setActiveContentQueryTabData({ query: code(), results: result });
};

Expand All @@ -74,27 +73,36 @@ export const QueryTextArea = () => {
);
});

const handleKeyDown = async (e: KeyboardEvent) => {
if (e.key === 'f' && e.ctrlKey) {
onFormat();
} else if (e.key === 'e' && e.ctrlKey) {
console.log('execute')
await onExecute();
}
};

return (
<div class="flex-1 flex flex-col">
<div class="w-full p-1 bg-base-100">
<div class="w-full p-2 bg-base-100">
<div
class="tooltip tooltip-primary tooltip-bottom"
data-tip={t("components.console.actions.format")}
>
<button class="btn btn-ghost btn-sm mr-2" onClick={() => onFormat()}>
<button class="btn btn-ghost btn-xs mr-2" onClick={() => onFormat()}>
<EditIcon />
</button>
</div>
<div
class="tooltip tooltip-primary tooltip-bottom"
data-tip={t("components.console.actions.execute")}
>
<button class="btn btn-ghost btn-sm mr-2" onClick={() => onExecute()}>
<button class="btn btn-ghost btn-xs mr-2" onClick={() => onExecute()}>
<FireIcon />
</button>
</div>
</div>
<div class="overflow-hidden w-full h-full">
<div class="overflow-hidden w-full h-full" onKeyDown={handleKeyDown}>
<div ref={ref} class="w-full h-full" />
</div>
</div>
Expand Down
4 changes: 2 additions & 2 deletions src/components/UI/Collapse.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export const Collapse = (props: { title: string, children: JSXElement }) => {
const [open, setOpen] = createSignal(false)
return (
<div class="w-full">
<div onClick={() => setOpen(!open())} class="collapse flex items-center rounded-sm text-sm font-semibold cursor-pointer border-b-2 border-base-300">
<button onClick={() => setOpen(!open())} class="collapse button-ghost flex items-center rounded-sm text-sm font-semibold cursor-pointer border-b-2 border-base-300">
<label class={`swap text-6xl ${open() ? 'swap-active' : ''}`}>
<svg class="w-2 h-2 swap-off" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 6 10">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 9 4-4-4-4" />
Expand All @@ -16,7 +16,7 @@ export const Collapse = (props: { title: string, children: JSXElement }) => {
<span class="ml-2">
{props.title}
</span>
</div>
</button>
{open() && props.children}
</div>
)
Expand Down
68 changes: 47 additions & 21 deletions src/components/UI/ThemeSwitch.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,54 @@
import { For } from "solid-js"
import { titleCase } from "../../utils/formatters"
const THEMES = ["light", "dark", "aqua", "synthwave", "dracula", "night", "cupcake"] as const;
import { onMount } from 'solid-js'
import { For, Show } from "solid-js";
import { titleCase } from "../../utils/formatters";
const THEMES = [
"light",
"dark",
"aqua",
"synthwave",
"dracula",
"night",
"cupcake",
] as const;
import { onMount } from "solid-js";
import { t } from "i18next";
import { useAppSelector } from "services/Context";

export const ThemeSwitch = () => {
const {
appService: { appStore },
} = useAppSelector();
onMount(async () => {
const theme = localStorage.getItem("theme") || "dark"
document.documentElement.dataset.theme = theme
})
const theme = localStorage.getItem("theme") || "dark";
document.documentElement.dataset.theme = theme;
});

const select = (theme: typeof THEMES[number]) => {
document.documentElement.dataset.theme = theme
localStorage.setItem("theme", theme)
}
const select = (theme: (typeof THEMES)[number]) => {
document.documentElement.dataset.theme = theme;
localStorage.setItem("theme", theme);
};

return (
<div class="dropdown dropdown-left">
<label tabindex="0" class="m-1 btn btn-xs">{t('components.theme_switch.theme')}</label>
<ul tabindex="0" class="p-2 shadow menu dropdown-content z-[1] bg-base-100 rounded-box w-52">
<For each={THEMES}>
{(theme) => <li class="py-1"><a onClick={() => select(theme)}>{titleCase(theme)}</a></li>}
</For>
</ul>
</div>
)
}
<Show when={appStore.showThemeSwitcher}>
<div class="dropdown dropdown-left">
<label id="theme-switch" tabindex="0" class="m-1 btn btn-xs">
{t("components.theme_switch.theme")}
</label>
<ul
tabindex={0}
class="p-2 shadow menu dropdown-content z-[1]
bg-base-100 rounded-box w-52"
>
<For each={THEMES}>
{(theme) => (
<li class="py-1">
<button onClick={() => select(theme)}>
{titleCase(theme)}
</button>
</li>
)}
</For>
</ul>
</div>
</Show>
);
};
6 changes: 6 additions & 0 deletions src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ input[type=number] {
border-width: 0px;
}

.tabs-boxed .tab-active:not(.tab-disabled):not([disabled]) {
@apply bg-accent;
}

dialog {
color: inherit;
}
Expand All @@ -110,6 +114,8 @@ dialog {
cursor: col-resize;
}

/* Tabulator */

.tabulator-page {
@apply text-base-content !important;
}
Expand Down
Loading

0 comments on commit 0c425df

Please sign in to comment.