kbar follow up (#3361)

* added more routes to kbar

* added right direction for tooltip, moved search icon next to logo, added keyboard shortcuts to command bar

* added right direction for tooltip, moved search icon next to logo, added keyboard shortcuts to command bar

* fixed search icon for tablet

* fixed search icon for mobile

* hide keyboard shortcut legend on mobile

* extracted strings
pull/3363/head
Peer Richelsen 2022-07-14 13:32:28 +02:00 committed by GitHub
parent 6f073762fa
commit 7ec5f01647
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 93 additions and 50 deletions

View File

@ -1,3 +1,4 @@
import { SwitchVerticalIcon } from "@heroicons/react/outline";
import { SearchIcon } from "@heroicons/react/solid";
import {
KBarProvider,
@ -10,6 +11,7 @@ import {
useKBar,
} from "kbar";
import { useRouter } from "next/router";
import { Command, CornerDownLeft } from "react-feather";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { isMac } from "@calcom/lib/isMac";
@ -33,13 +35,14 @@ export const KBarRoot = ({ children }: { children: React.ReactNode }) => {
// 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: "workflows",
name: "Workflows",
section: "Workflows",
shortcut: ["w", "f"],
keywords: "workflows automation",
perform: () => router.push("/workflows"),
},
{
id: "event-types",
@ -57,10 +60,18 @@ export const KBarRoot = ({ children }: { children: React.ReactNode }) => {
keywords: "app store",
perform: () => router.push("/apps"),
},
{
id: "upcoming-bookings",
name: "Upcoming Bookings",
section: "Bookings",
shortcut: ["u", "b"],
keywords: "upcoming bookings",
perform: () => router.push("/bookings/upcoming"),
},
{
id: "recurring-bookings",
name: "Recurring Bookings",
section: "Booking",
section: "Bookings",
shortcut: ["r", "b"],
keywords: "recurring bookings",
perform: () => router.push("/bookings/recurring"),
@ -68,7 +79,7 @@ export const KBarRoot = ({ children }: { children: React.ReactNode }) => {
{
id: "past-bookings",
name: "Past Bookings",
section: "Booking",
section: "Bookings",
shortcut: ["p", "b"],
keywords: "past bookings",
perform: () => router.push("/bookings/past"),
@ -76,7 +87,7 @@ export const KBarRoot = ({ children }: { children: React.ReactNode }) => {
{
id: "cancelled-bookings",
name: "Cancelled Bookings",
section: "Booking",
section: "Bookings",
shortcut: ["c", "b"],
keywords: "cancelled bookings",
perform: () => router.push("/bookings/cancelled"),
@ -182,13 +193,27 @@ export const KBarRoot = ({ children }: { children: React.ReactNode }) => {
};
export const KBarContent = () => {
const { t } = useLocale();
return (
<KBarPortal>
<KBarPositioner>
<KBarAnimator className="bg-white shadow-lg">
<KBarSearch className="min-w-96 rounded-sm px-4 py-2.5 focus-visible:outline-none" />
<KBarAnimator className="z-10 w-full max-w-screen-sm overflow-hidden rounded-sm bg-white shadow-lg">
<div className="flex items-center justify-center border-b">
<SearchIcon className="mx-3 h-4 w-4 text-gray-500" />
<KBarSearch className="w-full rounded-sm py-2.5 focus-visible:outline-none" />
</div>
<RenderResults />
<div className="hidden items-center space-x-1 border-t px-2 py-1.5 text-xs text-gray-500 sm:flex">
<SwitchVerticalIcon className="h-4 w-4" /> <span className="pr-2">{t("navigate")}</span>
<CornerDownLeft className="h-4 w-4" />
<span className="pr-2">{t("open")}</span>
{isMac ? <Command className="h-3 w-3" /> : "CTRL"}
<span className="pr-1">+ K </span>
<span className="pr-2">{t("close")}</span>
</div>
</KBarAnimator>
<div className="z-1 fixed inset-0 bg-gray-600 bg-opacity-75" />
</KBarPositioner>
</KBarPortal>
);
@ -196,22 +221,17 @@ export const KBarContent = () => {
export const KBarTrigger = () => {
const { query } = useKBar();
const { t } = useLocale();
return (
<div className="flex">
<>
<Tooltip side="right" content={isMac ? "⌘ + K" : "CTRL + K"}>
<button
color="minimal"
onClick={query.toggle}
className="group flex w-full items-center rounded-sm px-2 py-2 text-sm font-medium text-neutral-500 hover:bg-gray-50 hover:text-neutral-900">
<span className="h-5 w-5 flex-shrink-0 text-neutral-400 group-hover:text-neutral-500 ltr:mr-3 rtl:ml-3">
<SearchIcon />
</span>
<Tooltip content={isMac ? "⌘ + K" : "CTRL + K"}>
<span className="hidden lg:inline">{t("commandbar")}</span>
</Tooltip>
className="group flex text-sm font-medium text-neutral-500 hover:text-neutral-900">
<SearchIcon className="h-5 w-5 flex-shrink-0 text-neutral-400 group-hover:text-neutral-500" />
</button>
</div>
</Tooltip>
</>
);
};
@ -222,7 +242,7 @@ const DisplayShortcuts = (item: shortcutArrayType) => {
<span className="space-x-1">
{shortcuts?.map((shortcut) => {
return (
<kbd key={shortcut} className="rounded-sm bg-gray-700 px-2 py-1 text-white">
<kbd key={shortcut} className="rounded-sm border bg-white px-2 py-1 text-black hover:bg-gray-100">
{shortcut}
</kbd>
);

View File

@ -202,11 +202,17 @@ const Layout = ({
<div className="flex w-14 flex-col lg:w-56">
<div className="flex h-0 flex-1 flex-col border-r border-gray-200 bg-white">
<div className="flex flex-1 flex-col overflow-y-auto pt-3 pb-4 lg:pt-5">
<div className="justify-between md:hidden lg:flex">
<Link href="/event-types">
<a className="px-4 md:hidden lg:inline">
<a className="px-4">
<Logo small />
</a>
</Link>
<div className="px-2">
<KBarTrigger />
</div>
</div>
{/* logo icon for tablet */}
<Link href="/event-types">
<a className="text-center md:inline lg:hidden">
@ -261,7 +267,9 @@ const Layout = ({
})}
</Fragment>
))}
<span className="group flex items-center rounded-sm px-2 py-2 text-sm font-medium text-neutral-500 hover:bg-gray-50 hover:text-neutral-900 lg:hidden">
<KBarTrigger />
</span>
</nav>
</div>
<TrialBanner />
@ -304,9 +312,13 @@ const Layout = ({
<Logo />
</a>
</Link>
<div className="flex items-center gap-3 self-center">
<div className="flex items-center gap-2 self-center">
<span className="group flex items-center rounded-full p-2.5 text-sm font-medium text-neutral-500 hover:bg-gray-50 hover:text-neutral-900 lg:hidden">
<KBarTrigger />
</span>
<button className="rounded-full bg-white p-2 text-gray-400 hover:bg-gray-50 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-black focus:ring-offset-2">
<span className="sr-only">{t("view_notifications")}</span>
<span className="sr-only">{t("settings")}</span>
<Link href="/settings/profile">
<a>
<CogIcon className="h-6 w-6" aria-hidden="true" />

View File

@ -91,7 +91,7 @@ export default function MemberListItem(props: Props) {
<div className="mt-2 flex ltr:mr-2 rtl:ml-2 sm:mt-0 sm:justify-center">
{/* Tooltip doesn't show... WHY????? */}
{props.member.isMissingSeat && (
<Tooltip content={t("hidden_team_member_message")}>
<Tooltip side="top" content={t("hidden_team_member_message")}>
<TeamPill color="red" text={t("hidden")} />
</Tooltip>
)}
@ -100,7 +100,7 @@ export default function MemberListItem(props: Props) {
</div>
</div>
<div className="flex">
<Tooltip content={t("team_view_user_availability")}>
<Tooltip side="top" content={t("team_view_user_availability")}>
<Button
// Disabled buttons don't trigger Tooltips
title={

View File

@ -143,7 +143,7 @@ export default function TeamListItem(props: Props) {
<div className="flex rtl:space-x-reverse">
<TeamRole role={team.role} />
<Tooltip content={t("copy_link_team")}>
<Tooltip side="top" content={t("copy_link_team")}>
<Button
onClick={() => {
navigator.clipboard.writeText(process.env.NEXT_PUBLIC_WEBSITE_URL + "/team/" + team.slug);

View File

@ -5,7 +5,7 @@ import { Tooltip } from "@calcom/ui/Tooltip";
export default function InfoBadge({ content }: { content: string }) {
return (
<>
<Tooltip content={content}>
<Tooltip side="top" content={content}>
<span title={content}>
<InformationCircleIcon className="relative top-px left-1 right-1 mt-px h-4 w-4 text-gray-500" />
</span>

View File

@ -51,7 +51,7 @@ export default function WebhookListItem(props: { webhook: TWebhook; onEditWebhoo
</div>
</div>
<div className="flex">
<Tooltip content={t("edit_webhook")}>
<Tooltip side="top" content={t("edit_webhook")}>
<Button
onClick={() => props.onEditWebhook()}
color="minimal"
@ -61,7 +61,7 @@ export default function WebhookListItem(props: { webhook: TWebhook; onEditWebhoo
/>
</Tooltip>
<Dialog>
<Tooltip content={t("delete_webhook")}>
<Tooltip side="top" content={t("delete_webhook")}>
<DialogTrigger asChild>
<Button
onClick={(e) => {

View File

@ -67,7 +67,7 @@ export default function ApiKeyDialogForm(props: {
<code className="my-2 mr-1 w-full truncate rounded-sm bg-gray-100 py-2 px-3 align-middle font-mono text-gray-800">
{apiKey}
</code>
<Tooltip content={t("copy_to_clipboard")}>
<Tooltip side="top" content={t("copy_to_clipboard")}>
<Button
onClick={() => {
navigator.clipboard.writeText(apiKey);

View File

@ -61,7 +61,7 @@ export default function ApiKeyListItem(props: { apiKey: TApiKeys; onEditApiKey:
</div>
</div>
<div className="flex">
<Tooltip content={t("edit_api_key")}>
<Tooltip side="top" content={t("edit_api_key")}>
<Button
onClick={() => props.onEditApiKey()}
color="minimal"
@ -71,7 +71,7 @@ export default function ApiKeyListItem(props: { apiKey: TApiKeys; onEditApiKey:
/>
</Tooltip>
<Dialog>
<Tooltip content={t("delete_api_key")}>
<Tooltip side="top" content={t("delete_api_key")}>
<DialogTrigger asChild>
<Button
onClick={(e) => {

View File

@ -97,6 +97,7 @@
"react-digit-input": "^2.1.0",
"react-dom": "^18.1.0",
"react-easy-crop": "^3.5.2",
"react-feather": "^2.0.10",
"react-hook-form": "^7.31.1",
"react-hot-toast": "^2.1.0",
"react-intl": "^5.25.1",

View File

@ -259,7 +259,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
"flex justify-between space-x-2 rtl:space-x-reverse ",
type.$disabled && "pointer-events-none cursor-not-allowed"
)}>
<Tooltip content={t("preview") as string}>
<Tooltip side="top" content={t("preview") as string}>
<a
href={`${CAL_URL}/${group.profile.slug}/${type.slug}`}
target="_blank"
@ -271,7 +271,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
</a>
</Tooltip>
<Tooltip content={t("copy_link") as string}>
<Tooltip side="top" content={t("copy_link") as string}>
<button
onClick={() => {
showToast(t("link_copied"), "success");

View File

@ -986,5 +986,7 @@
"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",
"commandbar": "Command Bar"
"navigate": "Navigate",
"open": "Open",
"close": "Close"
}

View File

@ -79,7 +79,7 @@ export default function ZapierSetup(props: IZapierSetupProps) {
<div className="mt-1 text-xl">{t("your_unique_api_key")}</div>
<div className="my-2 mt-3 flex">
<div className="mr-1 w-full rounded bg-gray-100 p-3 pr-5">{newApiKey}</div>
<Tooltip content="copy to clipboard">
<Tooltip side="top" content="copy to clipboard">
<Button
onClick={() => {
navigator.clipboard.writeText(newApiKey);

View File

@ -1,8 +1,11 @@
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
import React from "react";
import classNames from "@calcom/lib/classNames";
export function Tooltip({
children,
side,
content,
open,
defaultOpen,
@ -12,6 +15,7 @@ export function Tooltip({
children: React.ReactNode;
content: React.ReactNode;
open?: boolean;
side?: "top" | "right" | "bottom" | "left" | undefined;
defaultOpen?: boolean;
onOpenChange?: (open: boolean) => void;
}) {
@ -23,8 +27,12 @@ export function Tooltip({
onOpenChange={onOpenChange}>
<TooltipPrimitive.Trigger asChild>{children}</TooltipPrimitive.Trigger>
<TooltipPrimitive.Content
className="-mt-2 rounded-sm bg-black px-1 py-0.5 text-xs text-white shadow-lg"
side="top"
className={classNames(
side === "top" && "-mt-2",
side === "right" && "ml-2",
"rounded-sm bg-black px-1 py-0.5 text-xs text-white shadow-lg"
)}
side={side}
align="center"
{...props}>
{content}