From 318ec316d5420ce19eea79f4b9b58f10b5f61508 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 14 Jul 2022 12:15:07 +0530 Subject: [PATCH] Adds a fully extensible command(ctrl)+k interface for Cal (#3346) * init * action function added * kbar trigger placed * UI improvements to KBar, added command + K tooltip * renamed quick find to commandbar * replaced window router with nextjs router * keyboard up n down nav shows up Co-authored-by: Peer Richelsen Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- apps/web/components/Kbar.tsx | 259 ++++++++++++++++++ apps/web/components/Shell.tsx | 7 +- apps/web/package.json | 1 + apps/web/public/static/locales/en/common.json | 3 +- packages/lib/isMac.ts | 1 + 5 files changed, 268 insertions(+), 3 deletions(-) create mode 100644 apps/web/components/Kbar.tsx create mode 100644 packages/lib/isMac.ts diff --git a/apps/web/components/Kbar.tsx b/apps/web/components/Kbar.tsx new file mode 100644 index 0000000000..432fc41a49 --- /dev/null +++ b/apps/web/components/Kbar.tsx @@ -0,0 +1,259 @@ +import { SearchIcon } from "@heroicons/react/solid"; +import { + KBarProvider, + KBarPortal, + KBarPositioner, + KBarAnimator, + KBarSearch, + KBarResults, + useMatches, + useKBar, +} from "kbar"; +import { useRouter } from "next/router"; + +import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { isMac } from "@calcom/lib/isMac"; +import { Tooltip } from "@calcom/ui"; + +type shortcutArrayType = { + shortcuts?: string[]; +}; + +export const KBarRoot = ({ children }: { children: React.ReactNode }) => { + const router = useRouter(); + + // grab link to events + // quick nested actions would be extremely useful + const actions = [ + // { + // id: "toggle-idle", + // name: "Test Function", + // section: "Status", + // shortcut: ["t", "f"], + // keywords: "set yourself away bookings", + // perform: () => alert("Hello World"), + // }, + { + id: "upcoming-bookings", + name: "Upcoming Bookings", + section: "Booking", + shortcut: ["u", "b"], + keywords: "upcoming bookings", + perform: () => router.push("/bookings/upcoming"), + }, + { + id: "event-types", + name: "Event Types", + section: "Event Types", + shortcut: ["e", "t"], + keywords: "event types", + perform: () => router.push("/event-types"), + }, + { + id: "app-store", + name: "App Store", + section: "Apps", + shortcut: ["a", "s"], + keywords: "app store", + perform: () => router.push("/apps"), + }, + { + id: "recurring-bookings", + name: "Recurring Bookings", + section: "Booking", + shortcut: ["r", "b"], + keywords: "recurring bookings", + perform: () => router.push("/bookings/recurring"), + }, + { + id: "past-bookings", + name: "Past Bookings", + section: "Booking", + shortcut: ["p", "b"], + keywords: "past bookings", + perform: () => router.push("/bookings/past"), + }, + { + id: "cancelled-bookings", + name: "Cancelled Bookings", + section: "Booking", + shortcut: ["c", "b"], + keywords: "cancelled bookings", + perform: () => router.push("/bookings/cancelled"), + }, + { + id: "schedule", + name: "Schedule", + section: "Availability", + shortcut: ["s", "a"], + keywords: "schedule availability", + perform: () => router.push("/availability"), + }, + { + id: "profile", + name: "Profile", + section: "Profile Settings", + shortcut: ["p", "s"], + keywords: "setting profile", + perform: () => router.push("/settings"), + }, + { + id: "avatar", + name: "Change Avatar", + section: "Profile Settings", + shortcut: ["c", "a"], + keywords: "remove change modify avatar", + perform: () => router.push("/settings"), + }, + { + id: "timezone", + name: "Change Timezone", + section: "Profile Settings", + shortcut: ["c", "t"], + keywords: "change modify timezone", + perform: () => router.push("/settings"), + }, + { + id: "brand-color", + name: "Change Brand Color", + section: "Profile Settings", + shortcut: ["b", "c"], + keywords: "change modify brand color", + perform: () => router.push("/settings"), + }, + { + id: "teams", + name: "Teams", + shortcut: ["t", "s"], + keywords: "add manage modify team", + perform: () => router.push("/settings/teams"), + }, + { + id: "password", + name: "Change Password", + section: "Security Settings", + shortcut: ["c", "p"], + keywords: "change modify password", + perform: () => router.push("/settings/security"), + }, + { + id: "two-factor", + name: "Two Factor Authentication", + section: "Security Settings", + shortcut: ["t", "f", "a"], + keywords: "two factor authentication", + perform: () => router.push("/settings/security"), + }, + { + id: "impersonation", + name: "User Impersonation", + section: "Security Settings", + shortcut: ["u", "i"], + keywords: "user impersonation", + perform: () => router.push("/settings/security"), + }, + { + id: "webhooks", + name: "Webhook", + section: "Developer Settings", + shortcut: ["w", "h"], + keywords: "webhook automation", + perform: () => router.push("/settings/developer"), + }, + { + id: "api-keys", + name: "API Keys", + section: "Developer Settings", + shortcut: ["a", "p", "i"], + keywords: "api keys", + perform: () => router.push("/settings/developer"), + }, + { + id: "billing", + name: "View and Manage Billing", + section: "Billing", + shortcut: ["m", "b"], + keywords: "billing view manage", + perform: () => router.push("/settings/billing"), + }, + ]; + + return {children}; +}; + +export const KBarContent = () => { + return ( + + + + + + + + + ); +}; + +export const KBarTrigger = () => { + const { query } = useKBar(); + const { t } = useLocale(); + + return ( +
+ +
+ ); +}; + +const DisplayShortcuts = (item: shortcutArrayType) => { + const shortcuts = item.shortcuts; + + return ( + + {shortcuts?.map((shortcut) => { + return ( + + {shortcut} + + ); + })} + + ); +}; + +function RenderResults() { + const { results } = useMatches(); + console.log(results); + + return ( + + typeof item === "string" ? ( +
{item}
+ ) : ( +
+ {item.name} + +
+ ) + } + /> + ); +} diff --git a/apps/web/components/Shell.tsx b/apps/web/components/Shell.tsx index f0b5234a18..0a5b935828 100644 --- a/apps/web/components/Shell.tsx +++ b/apps/web/components/Shell.tsx @@ -42,6 +42,7 @@ import useTheme from "@lib/hooks/useTheme"; import { trpc } from "@lib/trpc"; import CustomBranding from "@components/CustomBranding"; +import { KBarRoot, KBarContent, KBarTrigger } from "@components/Kbar"; import Loader from "@components/Loader"; import { HeadSeo } from "@components/seo/head-seo"; import Badge from "@components/ui/Badge"; @@ -260,6 +261,7 @@ const Layout = ({ })} ))} + @@ -454,11 +456,12 @@ export default function Shell(props: LayoutProps) { if (!session && !props.isPublic) return null; return ( - <> + - + + ); } diff --git a/apps/web/package.json b/apps/web/package.json index 791389c86e..edf82fc523 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -75,6 +75,7 @@ "ical.js": "^1.4.0", "ics": "^2.31.0", "jimp": "^0.16.1", + "kbar": "^0.1.0-beta.36", "libphonenumber-js": "^1.9.53", "lodash": "^4.17.21", "memory-cache": "^0.2.0", diff --git a/apps/web/public/static/locales/en/common.json b/apps/web/public/static/locales/en/common.json index 3418146d5c..265656b7ec 100644 --- a/apps/web/public/static/locales/en/common.json +++ b/apps/web/public/static/locales/en/common.json @@ -985,5 +985,6 @@ "no_active_event_types": "No active event types", "new_seat_subject": "New Attendee {{name}} on {{eventType}} at {{date}}", "new_seat_title": "Someone has added themselves to an event", - "invalid_number": "Invalid phone number" + "invalid_number": "Invalid phone number", + "commandbar": "Command Bar" } diff --git a/packages/lib/isMac.ts b/packages/lib/isMac.ts new file mode 100644 index 0000000000..ac16547c6f --- /dev/null +++ b/packages/lib/isMac.ts @@ -0,0 +1 @@ +export const isMac = typeof window !== "undefined" ? navigator.userAgent.indexOf("Mac") != -1 : false;