mirror of
https://github.com/linsa-io/linsa.git
synced 2026-01-12 12:20:23 +01:00
feat: navigation for command palette (#150)
* feat: add dotenv to dev dep * chore: jest use env * feat * feat: command palette navigation
This commit is contained in:
@@ -1,12 +1,14 @@
|
||||
import { icons } from "lucide-react"
|
||||
import { useCommandActions } from "./hooks/use-command-actions"
|
||||
import { LaAccount } from "@/lib/schema"
|
||||
import { HTMLLikeElement } from "@/lib/utils"
|
||||
|
||||
export type CommandAction = string | (() => void)
|
||||
|
||||
export type CommandItemType = {
|
||||
icon?: keyof typeof icons
|
||||
label: string
|
||||
value: string
|
||||
label: HTMLLikeElement | string
|
||||
action: CommandAction
|
||||
payload?: any
|
||||
shortcut?: string
|
||||
@@ -25,9 +27,16 @@ export const createCommandGroups = (
|
||||
{
|
||||
heading: "General",
|
||||
items: [
|
||||
{ icon: "SunMoon", label: "Change Theme...", action: "CHANGE_PAGE", payload: "changeTheme" },
|
||||
{
|
||||
icon: "SunMoon",
|
||||
value: "Change Theme...",
|
||||
label: "Change Theme...",
|
||||
action: "CHANGE_PAGE",
|
||||
payload: "changeTheme"
|
||||
},
|
||||
{
|
||||
icon: "Copy",
|
||||
value: "Copy Current URL",
|
||||
label: "Copy Current URL",
|
||||
action: actions.copyCurrentURL
|
||||
}
|
||||
@@ -36,20 +45,88 @@ export const createCommandGroups = (
|
||||
{
|
||||
heading: "Personal Links",
|
||||
items: [
|
||||
{ icon: "TextSearch", label: "Search Links...", action: "CHANGE_PAGE", payload: "searchLinks" },
|
||||
{ icon: "Plus", label: "Create New Link...", action: () => actions.navigateTo("/") }
|
||||
{
|
||||
icon: "TextSearch",
|
||||
value: "Search Links...",
|
||||
label: "Search Links...",
|
||||
action: "CHANGE_PAGE",
|
||||
payload: "searchLinks"
|
||||
},
|
||||
{
|
||||
icon: "Plus",
|
||||
value: "Create New Link...",
|
||||
label: "Create New Link...",
|
||||
action: () => actions.navigateTo("/")
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
heading: "Personal Pages",
|
||||
items: [
|
||||
{ icon: "FileSearch", label: "Search Pages...", action: "CHANGE_PAGE", payload: "searchPages" },
|
||||
{
|
||||
icon: "FileSearch",
|
||||
value: "Search Pages...",
|
||||
label: "Search Pages...",
|
||||
action: "CHANGE_PAGE",
|
||||
payload: "searchPages"
|
||||
},
|
||||
{
|
||||
icon: "Plus",
|
||||
value: "Create New Page...",
|
||||
label: "Create New Page...",
|
||||
action: () => actions.createNewPage(me)
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
heading: "Navigation",
|
||||
items: [
|
||||
{
|
||||
icon: "ArrowRight",
|
||||
value: "Go to Links",
|
||||
label: {
|
||||
tag: "span",
|
||||
children: ["Go to ", { tag: "span", attributes: { className: "font-semibold" }, children: ["links"] }]
|
||||
},
|
||||
action: () => actions.navigateTo("/links")
|
||||
},
|
||||
{
|
||||
icon: "ArrowRight",
|
||||
value: "Go to Pages",
|
||||
label: {
|
||||
tag: "span",
|
||||
children: ["Go to ", { tag: "span", attributes: { className: "font-semibold" }, children: ["pages"] }]
|
||||
},
|
||||
action: () => actions.navigateTo("/pages")
|
||||
},
|
||||
{
|
||||
icon: "ArrowRight",
|
||||
value: "Go to Search",
|
||||
label: {
|
||||
tag: "span",
|
||||
children: ["Go to ", { tag: "span", attributes: { className: "font-semibold" }, children: ["search"] }]
|
||||
},
|
||||
action: () => actions.navigateTo("/search")
|
||||
},
|
||||
{
|
||||
icon: "ArrowRight",
|
||||
value: "Go to Profile",
|
||||
label: {
|
||||
tag: "span",
|
||||
children: ["Go to ", { tag: "span", attributes: { className: "font-semibold" }, children: ["profile"] }]
|
||||
},
|
||||
action: () => actions.navigateTo("/profile")
|
||||
},
|
||||
{
|
||||
icon: "ArrowRight",
|
||||
value: "Go to Settings",
|
||||
label: {
|
||||
tag: "span",
|
||||
children: ["Go to ", { tag: "span", attributes: { className: "font-semibold" }, children: ["settings"] }]
|
||||
},
|
||||
action: () => actions.navigateTo("/settings")
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
searchLinks: [],
|
||||
@@ -58,9 +135,24 @@ export const createCommandGroups = (
|
||||
changeTheme: [
|
||||
{
|
||||
items: [
|
||||
{ icon: "Moon", label: "Change Theme to Dark", action: () => actions.changeTheme("dark") },
|
||||
{ icon: "Sun", label: "Change Theme to Light", action: () => actions.changeTheme("light") },
|
||||
{ icon: "Monitor", label: "Change Theme to System", action: () => actions.changeTheme("system") }
|
||||
{
|
||||
icon: "Moon",
|
||||
value: "Change Theme to Dark",
|
||||
label: "Change Theme to Dark",
|
||||
action: () => actions.changeTheme("dark")
|
||||
},
|
||||
{
|
||||
icon: "Sun",
|
||||
value: "Change Theme to Light",
|
||||
label: "Change Theme to Light",
|
||||
action: () => actions.changeTheme("light")
|
||||
},
|
||||
{
|
||||
icon: "Monitor",
|
||||
value: "changeThemeToSystem",
|
||||
label: "Change Theme to System",
|
||||
action: () => actions.changeTheme("system")
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -2,16 +2,21 @@ import { Command } from "cmdk"
|
||||
import { CommandSeparator, CommandShortcut } from "@/components/ui/command"
|
||||
import { LaIcon } from "../la-icon"
|
||||
import { CommandItemType, CommandAction } from "./command-data"
|
||||
import { HTMLLikeElement, renderHTMLLikeElement } from "@/lib/utils"
|
||||
|
||||
export interface CommandItemProps extends Omit<CommandItemType, "action"> {
|
||||
action: CommandAction
|
||||
handleAction: (action: CommandAction, payload?: any) => void
|
||||
}
|
||||
|
||||
const HTMLLikeRenderer: React.FC<{ content: HTMLLikeElement | string }> = ({ content }) => {
|
||||
return <>{renderHTMLLikeElement(content)}</>
|
||||
}
|
||||
|
||||
export const CommandItem: React.FC<CommandItemProps> = ({ icon, label, action, payload, shortcut, handleAction }) => (
|
||||
<Command.Item onSelect={() => handleAction(action, payload)}>
|
||||
{icon && <LaIcon name={icon} />}
|
||||
<span>{label}</span>
|
||||
<HTMLLikeRenderer content={label} />
|
||||
{shortcut && <CommandShortcut>{shortcut}</CommandShortcut>}
|
||||
</Command.Item>
|
||||
)
|
||||
|
||||
@@ -14,7 +14,7 @@ import { useCommandActions } from "./hooks/use-command-actions"
|
||||
let graph_data_promise = import("@/components/routes/public/graph-data.json").then(a => a.default)
|
||||
|
||||
const filterItems = (items: CommandItemType[], searchRegex: RegExp) =>
|
||||
items.filter(item => searchRegex.test(item.label)).slice(0, 6)
|
||||
items.filter(item => searchRegex.test(item.value)).slice(0, 6)
|
||||
|
||||
export function CommandPalette() {
|
||||
const { me } = useAccount({ root: { personalLinks: [], personalPages: [] } })
|
||||
@@ -81,6 +81,7 @@ export function CommandPalette() {
|
||||
heading: "Topics",
|
||||
items: raw_graph_data.map(topic => ({
|
||||
icon: "Circle" as const,
|
||||
value: topic?.prettyName || "",
|
||||
label: topic?.prettyName || "",
|
||||
action: () => actions.navigateTo(`/${topic?.name}`)
|
||||
}))
|
||||
@@ -94,6 +95,7 @@ export function CommandPalette() {
|
||||
items:
|
||||
me?.root.personalLinks?.map(link => ({
|
||||
icon: "Link" as const,
|
||||
value: link?.title || "Untitled",
|
||||
label: link?.title || "Untitled",
|
||||
action: () => actions.openLinkInNewTab(link?.url || "#")
|
||||
})) || []
|
||||
@@ -107,6 +109,7 @@ export function CommandPalette() {
|
||||
items:
|
||||
me?.root.personalPages?.map(page => ({
|
||||
icon: "FileText" as const,
|
||||
value: page?.title || "Untitled",
|
||||
label: page?.title || "Untitled",
|
||||
action: () => actions.navigateTo(`/pages/${page?.id}`)
|
||||
})) || []
|
||||
|
||||
Reference in New Issue
Block a user