From b45ef9a5102c169714996d3c3b47bb0cd9194ca1 Mon Sep 17 00:00:00 2001 From: Frank Lyder Bredland Date: Sun, 18 Feb 2024 11:24:22 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=80=20CMDK=20setup?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 5 +- src/cmdk/cmdk.css.ts | 167 +++++++++++++++++++++++++++ src/cmdk/index.jsx | 47 ++++++++ src/pages/index.tsx | 12 ++ yarn.lock | 264 ++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 476 insertions(+), 19 deletions(-) create mode 100644 src/cmdk/cmdk.css.ts create mode 100644 src/cmdk/index.jsx diff --git a/package.json b/package.json index 293761d..ef87c43 100644 --- a/package.json +++ b/package.json @@ -11,13 +11,14 @@ "dependencies": { "@iconify/react-with-api": "^1.0.0-rc.7", "@mdx-js/runtime": "^1.6.22", + "cmdk": "^0.2.1", "cross-fetch": "^3.1.4", "inter-ui": "^3.15.1", "next": "^10.1.2", "node-docker-api": "^1.1.22", "path-browserify": "^1.0.1", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": "^18.2.0", + "react-dom": "^18.2.0" }, "devDependencies": { "@testing-library/react": "^11.2.6", diff --git a/src/cmdk/cmdk.css.ts b/src/cmdk/cmdk.css.ts new file mode 100644 index 0000000..d80743a --- /dev/null +++ b/src/cmdk/cmdk.css.ts @@ -0,0 +1,167 @@ +import { + createThemeContract, + createTheme, + style, + globalStyle, +} from '@vanilla-extract/css'; + +// Inspired by https://github.com/pacocoursey/cmdk/blob/main/website/styles/cmdk/vercel.scss + +const gray1 = 'hsl(0, 0%, 99%)'; +const grayA3 = 'hsla(0, 0%, 0%, 0.047)'; +const gray4 = 'hsl(0, 0%, 93%)'; +const gray5 = 'hsl(0, 0%, 90.9%)'; +const gray6 = 'hsl(0, 0%, 88.7%)'; +const gray8 = 'hsl(0, 0%, 78%)'; +const gray9 = 'hsl(0, 0%, 56.1%)'; +const gray11 = 'hsl(0, 0%, 43.5%)'; +const gray12 = 'hsl(0, 0%, 9%)'; + +const fontSans = `'Inter', --apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif`; +const cmdkShadow = `0 16px 70px rgb(0 0 0 / 20%)`; +const appBg = gray1; + +export const cmdk = style({ + position: 'fixed', + zIndex: 100, + top: '50%', + left: '50%', + transform: 'translate(-50%, -50%)', +}); + +globalStyle(`${cmdk} [cmdk-root]`, { + maxWidth: '640px', + width: '100%', + padding: '8px', + background: '#ffffff', + borderRadius: '12px', + overflow: 'hidden', + fontFamily: fontSans, + border: `1px solid ${gray6}`, + boxShadow: cmdkShadow, + transition: 'transform 100ms ease', +}); + +globalStyle(`${cmdk} [cmdk-root] .dark &`, { + background: 'rgba(22, 22, 22, 0.7)', +}); + +globalStyle(`${cmdk} [cmdk-input]`, { + fontFamily: fontSans, + border: 'none', + width: '100%', + fontSize: '17px', + padding: '8px 8px 16px 8px', + outline: 'none', + background: appBg, + color: gray12, + borderBottom: `1px solid ${gray6}`, + marginBottom: '16px', + borderRadius: '0', +}); + +globalStyle(`${cmdk} [cmdk-input]::placeholder`, { + color: gray9, +}); + +globalStyle(`${cmdk} [cmdk-item]`, { + contentVisibility: 'auto', + cursor: 'pointer', + height: '48px', + borderRadius: '8px', + fontSize: '14px', + display: 'flex', + alignItems: 'center', + gap: '8px', + padding: '0 16px', + color: gray11, + userSelect: 'none', + willChange: 'background, color', + transition: 'all 150ms ease', + transitionProperty: 'none', +}); + +globalStyle(`${cmdk} [cmdk-item][aria-selected='true']`, { + background: grayA3, + color: gray12, +}); + +globalStyle(`${cmdk} [cmdk-item][aria-disabled='true']`, { + color: gray8, + cursor: 'not-allowed', +}); + +globalStyle(`${cmdk} [cmdk-item]:active`, { + transitionProperty: 'background', + background: gray4, +}); + +globalStyle(`${cmdk} [cmdk-item] + [cmdk-item]`, { + marginTop: '4px', +}); + +globalStyle(`${cmdk} [cmdk-item] svg`, { + width: '18px', + height: '18px', +}); + +globalStyle(`${cmdk} [cmdk-list]`, { + height: 'min(330px, calc(var(--cmdk-list-height)))', + maxHeight: '400px', + overflow: 'auto', + overscrollBehavior: 'contain', + transition: '100ms ease', + transitionProperty: 'height', +}); + +globalStyle(`${cmdk} [cmdk-vercel-shortcuts]`, { + display: 'flex', + marginLeft: 'auto', + gap: '8px', +}); + +globalStyle(`${cmdk} [cmdk-vercel-shortcuts] kbd`, { + fontFamily: fontSans, + fontSize: '12px', + minWidth: '20px', + padding: '4px', + height: '20px', + borderRadius: '4px', + color: gray11, + background: gray4, + display: 'inline-flex', + alignItems: 'center', + justifyContent: 'center', + textTransform: 'uppercase', +}); + +globalStyle(`${cmdk} [cmdk-separator]`, { + height: '1px', + width: '100%', + background: gray5, + margin: '4px 0', +}); + +globalStyle(`${cmdk} *:not([hidden]) + [cmdk-group]`, { + marginTop: '8px', +}); + +globalStyle(`${cmdk} [cmdk-group-heading]`, { + userSelect: 'none', + fontSize: '12px', + color: gray11, + padding: '0 8px', + display: 'flex', + alignItems: 'center', + marginBottom: '8px', +}); + +globalStyle(`${cmdk} [cmdk-empty]`, { + fontSize: '14px', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + height: '48px', + whiteSpace: 'pre-wrap', + color: gray11, +}); diff --git a/src/cmdk/index.jsx b/src/cmdk/index.jsx new file mode 100644 index 0000000..3b44a37 --- /dev/null +++ b/src/cmdk/index.jsx @@ -0,0 +1,47 @@ +import React, { useState, useEffect, useRef } from 'react'; +import { Command } from 'cmdk'; +import { cmdk } from './cmdk.css.ts'; + +const CommandMenu = ({ children }) => { + const [open, setOpen] = useState(false); + const containerElement = useRef(null) + + // Toggle the menu when ⌘K is pressed + useEffect(() => { + const down = (e) => { + if (e.key === 'k' && e.metaKey) { + e.preventDefault() + setOpen((open) => !open); + } + } + + document.addEventListener('keydown', down); + return () => document.removeEventListener('keydown', down); + }, []) + + const onKeyDown = (e) => { + if(e.keyCode === 13 /* enter */) { + setOpen(false); + } + } + + return ( + <> +
+ + + + No results found. + {children} + + + + ); +}; + +export default CommandMenu; diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 93be778..fbc62b0 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -8,6 +8,8 @@ import { getContainersWithLabels, AppProps } from '../docker'; import { themeVars } from '../styles/index.css'; import 'inter-ui/Inter (web)/inter.css'; import { createInlineTheme } from '@vanilla-extract/dynamic'; +import CMDK from '../cmdk'; +import { Command } from 'cmdk'; interface Colors { background?: string; @@ -71,7 +73,17 @@ const Home : React.FC = ({ colors, mdx, appData, forceHttps }) => { }); } + const gotoApp = (app) => { + window.location.href = app.href; + }; + return <> + + { (apps || []).map((app) => ( + gotoApp(app)}>{ app.name } + )) } + +