diff --git a/package.json b/package.json index 9b6394fa9..00ee4d146 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,9 @@ "private": true, "dependencies": { "@codemirror/lang-javascript": "^6.1.1", + "@fortawesome/fontawesome-svg-core": "^6.4.0", + "@fortawesome/free-solid-svg-icons": "^6.4.0", + "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^1.7.13", "@tauri-apps/api": "^1.3.0", "@testing-library/jest-dom": "^5.14.1", @@ -19,8 +22,10 @@ "http-server": "^14.1.1", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-hot-toast": "^2.4.1", "react-json-view": "^1.21.3", "react-modal-promise": "^1.0.2", + "react-router-dom": "^6.14.1", "react-scripts": "5.0.1", "sketch-helpers": "^0.0.3", "swr": "^2.0.4", diff --git a/public/kitt-8bit-winking.svg b/public/kitt-8bit-winking.svg new file mode 100644 index 000000000..0501e2067 --- /dev/null +++ b/public/kitt-8bit-winking.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/kitt-arcade-winking.svg b/public/kitt-arcade-winking.svg new file mode 100644 index 000000000..5e1ef86e3 --- /dev/null +++ b/public/kitt-arcade-winking.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/App.test.tsx b/src/App.test.tsx index cd373d517..9728dcd27 100644 --- a/src/App.test.tsx +++ b/src/App.test.tsx @@ -1,5 +1,6 @@ import { render, screen } from '@testing-library/react' import { App } from './App' +import { BrowserRouter } from 'react-router-dom'; let listener: ((rect: any) => void) | undefined = undefined ;(global as any).ResizeObserver = class ResizeObserver { @@ -12,7 +13,9 @@ let listener: ((rect: any) => void) | undefined = undefined } test('renders learn react link', () => { - render() + render( + + ) const linkElement = screen.getByText(/Variables/i) expect(linkElement).toBeInTheDocument() }) diff --git a/src/App.tsx b/src/App.tsx index 500cd2d28..6f7f8f6ae 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -21,6 +21,7 @@ import ModalContainer from 'react-modal-promise' import { EngineCommandManager } from './lang/std/engineConnection' import { isOverlap } from './lib/utils' import { SetToken } from './components/TokenInput' +import { AppHeader } from './components/AppHeader' export function App() { const cam = useRef() @@ -253,6 +254,7 @@ export function App() { }, [code, isStreamReady]) return (
+ @@ -285,9 +287,6 @@ export function App() { -
- -
diff --git a/src/Auth.tsx b/src/Auth.tsx index 362f62e26..e9a506cb8 100644 --- a/src/Auth.tsx +++ b/src/Auth.tsx @@ -4,6 +4,24 @@ import withBaseUrl from './lib/withBaseURL' import { App } from './App' import { SetToken } from './components/TokenInput' import { useStore } from './useStore' +import { + createBrowserRouter, + RouterProvider, +} from "react-router-dom" +import { ErrorPage } from './components/ErrorPage' +import { Settings } from './routes/Settings' + +const router = createBrowserRouter([ + { + path: "/", + element: , + errorElement: , + }, + { + path: "/settings", + element: , + } +]) export const Auth = () => { const { data: user } = useSWR(withBaseUrl('/user'), fetcher) as any @@ -37,5 +55,5 @@ export const Auth = () => { ) } - return + return } diff --git a/src/colors.css b/src/colors.css new file mode 100644 index 000000000..43f59280b --- /dev/null +++ b/src/colors.css @@ -0,0 +1,263 @@ +:root { + /* + Generated using Catmosphere Theme Builder + by KittyCAD + https://catmosphere-theme-builder.vercel.app/?colors=%5B%7B%22from%22:%7B%22l%22:1,%22c%22:0.01,%22h%22:78%7D,%22to%22:%7B%22l%22:0.065,%22c%22:0.05,%22h%22:182.6%7D,%22stops%22:10,%22steps%22:12%7D,%7B%22from%22:%7B%22l%22:1,%22c%22:0.45,%22h%22:122.4%7D,%22to%22:%7B%22l%22:0.13,%22c%22:0.031,%22h%22:137.2%7D,%22stops%22:10,%22steps%22:12%7D,%7B%22from%22:%7B%22l%22:1,%22c%22:0.13,%22h%22:176%7D,%22to%22:%7B%22l%22:0.116,%22c%22:0.097,%22h%22:213.1%7D,%22stops%22:10,%22steps%22:12%7D,%7B%22from%22:%7B%22l%22:1,%22c%22:0.169,%22h%22:144.4%7D,%22to%22:%7B%22l%22:0.12,%22c%22:0.45,%22h%22:132.7%7D,%22steps%22:12%7D,%7B%22from%22:%7B%22l%22:1,%22c%22:0.087,%22h%22:261.6%7D,%22to%22:%7B%22l%22:0.22,%22c%22:0.084,%22h%22:275.5%7D,%22steps%22:12,%22uuid%22:%227tpx9pf1zd6%22%7D,%7B%22from%22:%7B%22l%22:0.954,%22c%22:0.108,%22h%22:280.6%7D,%22to%22:%7B%22l%22:0.166,%22c%22:0.188,%22h%22:263.8%7D,%22steps%22:12,%22uuid%22:%22vu652mebd3%22%7D,%7B%22from%22:%7B%22l%22:1,%22c%22:0.115,%22h%22:0%7D,%22to%22:%7B%22l%22:0.096,%22c%22:0.261,%22h%22:302%7D,%22steps%22:12%7D,%7B%22from%22:%7B%22l%22:1,%22c%22:0.185,%22h%22:19.8%7D,%22to%22:%7B%22l%22:0.368,%22c%22:0.45,%22h%22:9.4%7D,%22steps%22:8,%22uuid%22:%22g05inkd34l%22%7D,%7B%22from%22:%7B%22l%22:0.912,%22c%22:0.139,%22h%22:87%7D,%22to%22:%7B%22l%22:0.502,%22c%22:0.45,%22h%22:97.7%7D,%22steps%22:8,%22uuid%22:%22l892hcw4ef%22%7D,%7B%22from%22:%7B%22l%22:0.89,%22c%22:0.16,%22h%22:143.4%7D,%22to%22:%7B%22l%22:0.466,%22c%22:0.208,%22h%22:147.7%7D,%22steps%22:8,%22uuid%22:%22hkd09y9ov4h%22%7D%5D + */ + /* Chalkboard */ + --chalkboard-10: oklch(99.70% 0.008766 102.8deg); + --chalkboard-20: oklch(91.34% 0.009353 109.0deg); + --chalkboard-30: oklch(82.99% 0.009940 115.2deg); + --chalkboard-40: oklch(74.63% 0.01053 121.4deg); + --chalkboard-50: oklch(66.27% 0.01111 127.6deg); + --chalkboard-60: oklch(57.92% 0.01170 133.9deg); + --chalkboard-70: oklch(49.56% 0.01229 140.1deg); + --chalkboard-80: oklch(41.21% 0.01288 146.3deg); + --chalkboard-90: oklch(32.85% 0.01346 152.5deg); + --chalkboard-100: oklch(24.49% 0.01405 158.7deg); + --chalkboard-110: oklch(16.14% 0.01464 164.9deg); + --chalkboard-120: oklch(7.783% 0.01522 171.1deg); + + /* Energy */ + --energy-10: oklch(93.31% 0.2270 122.3deg); + --energy-20: oklch(86.01% 0.2092 123.6deg); + --energy-30: oklch(78.71% 0.1914 125.0deg); + --energy-40: oklch(71.41% 0.1736 126.3deg); + --energy-50: oklch(64.10% 0.1557 127.7deg); + --energy-60: oklch(56.80% 0.1379 129.1deg); + --energy-70: oklch(49.50% 0.1201 130.4deg); + --energy-80: oklch(42.20% 0.1023 131.8deg); + --energy-90: oklch(34.90% 0.08446 133.1deg); + --energy-100: oklch(27.60% 0.06664 134.5deg); + --energy-110: oklch(20.30% 0.04882 135.8deg); + --energy-120: oklch(13.00% 0.03100 137.2deg); + + /* Liquid */ + --liquid-10: oklch(93.45% 0.1002 193.1deg); + --liquid-20: oklch(86.21% 0.09511 198.7deg); + --liquid-30: oklch(78.97% 0.09003 204.2deg); + --liquid-40: oklch(71.74% 0.08495 209.8deg); + --liquid-50: oklch(64.50% 0.07988 215.3deg); + --liquid-60: oklch(57.26% 0.07480 220.9deg); + --liquid-70: oklch(50.03% 0.06972 226.4deg); + --liquid-80: oklch(42.79% 0.06465 232.0deg); + --liquid-90: oklch(35.56% 0.05957 237.5deg); + --liquid-100: oklch(28.32% 0.05450 243.1deg); + --liquid-110: oklch(21.08% 0.04942 248.6deg); + --liquid-120: oklch(13.85% 0.04434 254.2deg); + + /* Fern */ + --fern-10: oklch(93.22% 0.1243 144.8deg); + --fern-20: oklch(86.59% 0.1193 144.6deg); + --fern-30: oklch(79.97% 0.1143 144.4deg); + --fern-40: oklch(73.34% 0.1093 144.2deg); + --fern-50: oklch(66.71% 0.1043 144.0deg); + --fern-60: oklch(60.09% 0.09927 143.8deg); + --fern-70: oklch(53.46% 0.09425 143.6deg); + --fern-80: oklch(46.83% 0.08924 143.3deg); + --fern-90: oklch(40.21% 0.08422 143.1deg); + --fern-100: oklch(33.58% 0.07920 142.9deg); + --fern-110: oklch(26.95% 0.07419 142.7deg); + --fern-120: oklch(20.33% 0.06917 142.5deg); + + /* Cool */ + --cool-10: oklch(97.71% 0.03321 196.6deg); + --cool-20: oklch(90.82% 0.03783 203.8deg); + --cool-30: oklch(83.94% 0.04245 211.0deg); + --cool-40: oklch(77.06% 0.04706 218.1deg); + --cool-50: oklch(70.18% 0.05168 225.3deg); + --cool-60: oklch(63.29% 0.05630 232.5deg); + --cool-70: oklch(56.41% 0.06091 239.6deg); + --cool-80: oklch(49.53% 0.06553 246.8deg); + --cool-90: oklch(42.65% 0.07015 254.0deg); + --cool-100: oklch(35.76% 0.07477 261.2deg); + --cool-110: oklch(28.88% 0.07938 268.3deg); + --cool-120: oklch(22.00% 0.08400 275.5deg); + + /* River */ + --river-10: oklch(93.35% 0.03169 273.4deg); + --river-20: oklch(86.91% 0.04221 273.1deg); + --river-30: oklch(80.46% 0.05274 272.7deg); + --river-40: oklch(74.01% 0.06326 272.4deg); + --river-50: oklch(67.57% 0.07378 272.0deg); + --river-60: oklch(61.12% 0.08430 271.7deg); + --river-70: oklch(54.67% 0.09483 271.4deg); + --river-80: oklch(48.22% 0.1053 271.0deg); + --river-90: oklch(41.78% 0.1159 270.7deg); + --river-100: oklch(35.33% 0.1264 270.4deg); + --river-110: oklch(28.88% 0.1369 270.0deg); + --river-120: oklch(22.44% 0.1474 269.7deg); + + /* Berry */ + --berry-10: oklch(93.77% 0.05212 329.0deg); + --berry-20: oklch(87.30% 0.05912 325.3deg); + --berry-30: oklch(80.82% 0.06612 321.6deg); + --berry-40: oklch(74.34% 0.07313 317.8deg); + --berry-50: oklch(67.86% 0.08013 314.1deg); + --berry-60: oklch(61.39% 0.08713 310.3deg); + --berry-70: oklch(54.91% 0.09413 306.6deg); + --berry-80: oklch(48.43% 0.1011 302.8deg); + --berry-90: oklch(41.95% 0.1081 299.1deg); + --berry-100: oklch(35.47% 0.1151 295.4deg); + --berry-110: oklch(29.00% 0.1221 291.6deg); + --berry-120: oklch(22.52% 0.1291 287.9deg); + + /* Destroy */ + --destroy-10: oklch(88.21% 0.06281 14.85deg); + --destroy-20: oklch(83.23% 0.08511 16.91deg); + --destroy-30: oklch(78.25% 0.1074 18.96deg); + --destroy-40: oklch(73.27% 0.1297 21.01deg); + --destroy-50: oklch(68.29% 0.1520 23.07deg); + --destroy-60: oklch(63.31% 0.1743 25.12deg); + --destroy-70: oklch(58.33% 0.1966 27.18deg); + --destroy-80: oklch(53.35% 0.2189 29.23deg); + + /* Warn */ + --warn-10: oklch(90.19% 0.1361 92.00deg); + --warn-20: oklch(84.60% 0.1388 84.84deg); + --warn-30: oklch(79.01% 0.1414 77.68deg); + --warn-40: oklch(73.42% 0.1440 70.52deg); + --warn-50: oklch(67.83% 0.1466 63.36deg); + --warn-60: oklch(62.24% 0.1492 56.20deg); + --warn-70: oklch(56.65% 0.1518 49.04deg); + --warn-80: oklch(51.06% 0.1544 41.88deg); + + /* Succeed */ + --succeed-10: oklch(89.00% 0.1600 143.4deg); + --succeed-20: oklch(83.23% 0.1608 143.3deg); + --succeed-30: oklch(77.46% 0.1616 143.1deg); + --succeed-40: oklch(71.69% 0.1623 143.0deg); + --succeed-50: oklch(65.92% 0.1631 142.9deg); + --succeed-60: oklch(60.16% 0.1639 142.8deg); + --succeed-70: oklch(54.39% 0.1647 142.6deg); + --succeed-80: oklch(48.62% 0.1654 142.5deg); + + /* Base values for use with Tailwind. */ + /* Chalkboard */ + --_chalkboard-10: 99.70% 0.008766 102.8deg; + --_chalkboard-20: 91.34% 0.009353 109.0deg; + --_chalkboard-30: 82.99% 0.009940 115.2deg; + --_chalkboard-40: 74.63% 0.01053 121.4deg; + --_chalkboard-50: 66.27% 0.01111 127.6deg; + --_chalkboard-60: 57.92% 0.01170 133.9deg; + --_chalkboard-70: 49.56% 0.01229 140.1deg; + --_chalkboard-80: 41.21% 0.01288 146.3deg; + --_chalkboard-90: 32.85% 0.01346 152.5deg; + --_chalkboard-100: 24.49% 0.01405 158.7deg; + --_chalkboard-110: 16.14% 0.01464 164.9deg; + --_chalkboard-120: 7.783% 0.01522 171.1deg; + + /* Energy */ + --_energy-10: 93.31% 0.2270 122.3deg; + --_energy-20: 86.01% 0.2092 123.6deg; + --_energy-30: 78.71% 0.1914 125.0deg; + --_energy-40: 71.41% 0.1736 126.3deg; + --_energy-50: 64.10% 0.1557 127.7deg; + --_energy-60: 56.80% 0.1379 129.1deg; + --_energy-70: 49.50% 0.1201 130.4deg; + --_energy-80: 42.20% 0.1023 131.8deg; + --_energy-90: 34.90% 0.08446 133.1deg; + --_energy-100: 27.60% 0.06664 134.5deg; + --_energy-110: 20.30% 0.04882 135.8deg; + --_energy-120: 13.00% 0.03100 137.2deg; + + /* Liquid */ + --_liquid-10: 93.45% 0.1002 193.1deg; + --_liquid-20: 86.21% 0.09511 198.7deg; + --_liquid-30: 78.97% 0.09003 204.2deg; + --_liquid-40: 71.74% 0.08495 209.8deg; + --_liquid-50: 64.50% 0.07988 215.3deg; + --_liquid-60: 57.26% 0.07480 220.9deg; + --_liquid-70: 50.03% 0.06972 226.4deg; + --_liquid-80: 42.79% 0.06465 232.0deg; + --_liquid-90: 35.56% 0.05957 237.5deg; + --_liquid-100: 28.32% 0.05450 243.1deg; + --_liquid-110: 21.08% 0.04942 248.6deg; + --_liquid-120: 13.85% 0.04434 254.2deg; + + /* Fern */ + --_fern-10: 93.22% 0.1243 144.8deg; + --_fern-20: 86.59% 0.1193 144.6deg; + --_fern-30: 79.97% 0.1143 144.4deg; + --_fern-40: 73.34% 0.1093 144.2deg; + --_fern-50: 66.71% 0.1043 144.0deg; + --_fern-60: 60.09% 0.09927 143.8deg; + --_fern-70: 53.46% 0.09425 143.6deg; + --_fern-80: 46.83% 0.08924 143.3deg; + --_fern-90: 40.21% 0.08422 143.1deg; + --_fern-100: 33.58% 0.07920 142.9deg; + --_fern-110: 26.95% 0.07419 142.7deg; + --_fern-120: 20.33% 0.06917 142.5deg; + + /* Cool */ + --_cool-10: 97.71% 0.03321 196.6deg; + --_cool-20: 90.82% 0.03783 203.8deg; + --_cool-30: 83.94% 0.04245 211.0deg; + --_cool-40: 77.06% 0.04706 218.1deg; + --_cool-50: 70.18% 0.05168 225.3deg; + --_cool-60: 63.29% 0.05630 232.5deg; + --_cool-70: 56.41% 0.06091 239.6deg; + --_cool-80: 49.53% 0.06553 246.8deg; + --_cool-90: 42.65% 0.07015 254.0deg; + --_cool-100: 35.76% 0.07477 261.2deg; + --_cool-110: 28.88% 0.07938 268.3deg; + --_cool-120: 22.00% 0.08400 275.5deg; + + /* River */ + --_river-10: 93.35% 0.03169 273.4deg; + --_river-20: 86.91% 0.04221 273.1deg; + --_river-30: 80.46% 0.05274 272.7deg; + --_river-40: 74.01% 0.06326 272.4deg; + --_river-50: 67.57% 0.07378 272.0deg; + --_river-60: 61.12% 0.08430 271.7deg; + --_river-70: 54.67% 0.09483 271.4deg; + --_river-80: 48.22% 0.1053 271.0deg; + --_river-90: 41.78% 0.1159 270.7deg; + --_river-100: 35.33% 0.1264 270.4deg; + --_river-110: 28.88% 0.1369 270.0deg; + --_river-120: 22.44% 0.1474 269.7deg; + + /* Berry */ + --_berry-10: 93.77% 0.05212 329.0deg; + --_berry-20: 87.30% 0.05912 325.3deg; + --_berry-30: 80.82% 0.06612 321.6deg; + --_berry-40: 74.34% 0.07313 317.8deg; + --_berry-50: 67.86% 0.08013 314.1deg; + --_berry-60: 61.39% 0.08713 310.3deg; + --_berry-70: 54.91% 0.09413 306.6deg; + --_berry-80: 48.43% 0.1011 302.8deg; + --_berry-90: 41.95% 0.1081 299.1deg; + --_berry-100: 35.47% 0.1151 295.4deg; + --_berry-110: 29.00% 0.1221 291.6deg; + --_berry-120: 22.52% 0.1291 287.9deg; + + /* Destroy */ + --_destroy-10: 88.21% 0.06281 14.85deg; + --_destroy-20: 83.23% 0.08511 16.91deg; + --_destroy-30: 78.25% 0.1074 18.96deg; + --_destroy-40: 73.27% 0.1297 21.01deg; + --_destroy-50: 68.29% 0.1520 23.07deg; + --_destroy-60: 63.31% 0.1743 25.12deg; + --_destroy-70: 58.33% 0.1966 27.18deg; + --_destroy-80: 53.35% 0.2189 29.23deg; + + /* Warn */ + --_warn-10: 90.19% 0.1361 92.00deg; + --_warn-20: 84.60% 0.1388 84.84deg; + --_warn-30: 79.01% 0.1414 77.68deg; + --_warn-40: 73.42% 0.1440 70.52deg; + --_warn-50: 67.83% 0.1466 63.36deg; + --_warn-60: 62.24% 0.1492 56.20deg; + --_warn-70: 56.65% 0.1518 49.04deg; + --_warn-80: 51.06% 0.1544 41.88deg; + + /* Succeed */ + --_succeed-10: 89.00% 0.1600 143.4deg; + --_succeed-20: 83.23% 0.1608 143.3deg; + --_succeed-30: 77.46% 0.1616 143.1deg; + --_succeed-40: 71.69% 0.1623 143.0deg; + --_succeed-50: 65.92% 0.1631 142.9deg; + --_succeed-60: 60.16% 0.1639 142.8deg; + --_succeed-70: 54.39% 0.1647 142.6deg; + --_succeed-80: 48.62% 0.1654 142.5deg; +} \ No newline at end of file diff --git a/src/components/ActionButton.tsx b/src/components/ActionButton.tsx new file mode 100644 index 000000000..09aff5bf3 --- /dev/null +++ b/src/components/ActionButton.tsx @@ -0,0 +1,35 @@ +import { Link } from 'react-router-dom' +import { ActionIcon, ActionIconProps } from './ActionIcon' + +interface ActionButtonProps extends React.PropsWithChildren { + icon?: ActionIconProps + className?: string + onClick?: () => void + to?: string + as?: 'button' | 'link' +} + +export const ActionButton = ({ + icon, + className, + onClick, + to = '/', + as = 'button', + children, +}: ActionButtonProps) => { + const classNames = `group mono flex items-center gap-2 text-chalkboard-110 rounded-sm border border-chalkboard-40 hover:border-liquid-40 p-[3px] ${ + icon ? 'pr-2' : 'px-2' + } ${className}` + + return as === 'button' ? ( + + ) : ( + + {icon && } + {children} + + ) +} diff --git a/src/components/ActionIcon.tsx b/src/components/ActionIcon.tsx new file mode 100644 index 000000000..b6fdfb69e --- /dev/null +++ b/src/components/ActionIcon.tsx @@ -0,0 +1,48 @@ +import { + IconDefinition, + faCircleExclamation, +} from '@fortawesome/free-solid-svg-icons' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' + +const iconSizes = { + sm: 12, + md: 14.4, + lg: 18, +} + +export interface ActionIconProps extends React.PropsWithChildren { + icon?: IconDefinition + bgClassName?: string + iconClassName?: string + size?: keyof typeof iconSizes +} + +export const ActionIcon = ({ + icon, + bgClassName, + iconClassName, + size = 'md', + children, +}: ActionIconProps) => { + return ( +
+ {children || ( + + )} +
+ ) +} diff --git a/src/components/AppHeader.tsx b/src/components/AppHeader.tsx new file mode 100644 index 000000000..efd529529 --- /dev/null +++ b/src/components/AppHeader.tsx @@ -0,0 +1,37 @@ +import { faGear } from '@fortawesome/free-solid-svg-icons' +import { Toolbar } from '../Toolbar' +import { ActionButton } from './ActionButton' + +interface AppHeaderProps extends React.PropsWithChildren { + showToolbar?: boolean +} + +export const AppHeader = ({ showToolbar = true, children }: AppHeaderProps) => { + return ( +
+ + KittyCAD App + KittyCAD App + + {/* Toolbar if the context deems it */} + {showToolbar && ( +
+ +
+ )} + {/* If there are children, show them, otherwise... */} + {children || ( + // TODO: If signed out, show the token paste field + + // If signed in, show the account avatar + + Settings + + )} +
+ ) +} diff --git a/src/components/ErrorPage.tsx b/src/components/ErrorPage.tsx new file mode 100644 index 000000000..83564a87b --- /dev/null +++ b/src/components/ErrorPage.tsx @@ -0,0 +1,8 @@ +export const ErrorPage = () => { + return ( +
+

404

+

Page not found

+
+ ) +} diff --git a/src/index.css b/src/index.css index 2f1e8afda..557a8ff1e 100644 --- a/src/index.css +++ b/src/index.css @@ -3,6 +3,7 @@ @tailwind utilities; @import '../node_modules/allotment/dist/style.css'; +@import './colors.css'; body { margin: 0; @@ -13,6 +14,11 @@ body { -moz-osx-font-smoothing: grayscale; } +.mono { + font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', + monospace; +} + code { font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; diff --git a/src/index.tsx b/src/index.tsx index 128716319..b5a7d8c7e 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -2,11 +2,13 @@ import ReactDOM from 'react-dom/client' import './index.css' import { Auth } from './Auth' import reportWebVitals from './reportWebVitals' +import { Toaster } from 'react-hot-toast' const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement) -root.render( +root.render(<> -) + +) // If you want to start measuring performance in your app, pass a function // to log results (for example: reportWebVitals(console.log)) diff --git a/src/routes/Settings.tsx b/src/routes/Settings.tsx new file mode 100644 index 000000000..1bfd38e73 --- /dev/null +++ b/src/routes/Settings.tsx @@ -0,0 +1,143 @@ +import { faCheck, faFolder, faXmark } from '@fortawesome/free-solid-svg-icons' +import { ActionButton } from '../components/ActionButton' +import { AppHeader } from '../components/AppHeader' +import { open } from '@tauri-apps/api/dialog' +import { useStore } from '../useStore' +import { useState } from 'react' +import { toast } from 'react-hot-toast' + +export const Settings = () => { + const { + defaultDir: originalDefaultDir, + setDefaultDir: saveDefaultDir, + defaultProjectName: originalDefaultProjectName, + setDefaultProjectName: saveDefaultProjectName, + } = useStore((s) => ({ + defaultDir: s.defaultDir, + setDefaultDir: s.setDefaultDir, + defaultProjectName: s.defaultProjectName, + setDefaultProjectName: s.setDefaultProjectName, + })) + const [defaultDir, setDefaultDir] = useState(originalDefaultDir) + const [defaultProjectName, setDefaultProjectName] = useState( + originalDefaultProjectName + ) + + async function handleDirectorySelection() { + const newDirectory = await open({ + directory: true, + defaultPath: (defaultDir.base || '') + (defaultDir.dir || '/'), + title: 'Choose a new default directory', + }) + + if (newDirectory && newDirectory !== null && !Array.isArray(newDirectory)) { + setDefaultDir({ base: defaultDir.base, dir: newDirectory }) + } + } + + const handleSaveClick = () => { + saveDefaultDir(defaultDir) + saveDefaultProjectName(defaultProjectName) + toast.success('Settings saved!') + } + + return ( + <> + + + Close + + +
+

User Settings

+ {(window as any).__TAURI__ && ( + +
+ + setDefaultDir({ + base: originalDefaultDir.base, + dir: e.target.value, + }) + } + /> + + Choose a folder + +
+
+ )} + + setDefaultProjectName(e.target.value)} + /> + + + Save Settings + +
+ + ) +} + +interface SettingsSectionProps extends React.PropsWithChildren { + title: string + description?: string +} + +function SettingsSection({ + title, + description, + children, +}: SettingsSectionProps) { + return ( +
+
+

{title}

+

{description}

+
+ {children} +
+ ) +} diff --git a/src/useStore.ts b/src/useStore.ts index 1feb75abc..192f34ab7 100644 --- a/src/useStore.ts +++ b/src/useStore.ts @@ -155,6 +155,8 @@ export interface StoreState { // tauri specific app settings defaultDir: DefaultDir setDefaultDir: (dir: DefaultDir) => void + defaultProjectName: string + setDefaultProjectName: (defaultProjectName: string) => void showHomeMenu: boolean setHomeShowMenu: (showMenu: boolean) => void homeMenuItems: { @@ -310,9 +312,11 @@ export const useStore = create()( // tauri specific app settings defaultDir: { - dir: '', + dir: '~/Documents/', }, setDefaultDir: (dir) => set({ defaultDir: dir }), + defaultProjectName: 'new-project-$n', + setDefaultProjectName: (defaultProjectName) => set({ defaultProjectName }), showHomeMenu: true, setHomeShowMenu: (showHomeMenu) => set({ showHomeMenu }), homeMenuItems: [], @@ -324,7 +328,12 @@ export const useStore = create()( name: 'store', partialize: (state) => Object.fromEntries( - Object.entries(state).filter(([key]) => ['code', 'defaultDir', 'token'].includes(key)) + Object.entries(state).filter(([key]) => [ + 'code', + 'defaultDir', + 'defaultProjectName', + 'token', + ].includes(key)) ), } ) diff --git a/tailwind.config.js b/tailwind.config.js index 1490793a2..814c69f32 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,10 +1,42 @@ +const themeColorRamps = [ + { name: 'chalkboard', stops: 12 }, + { name: 'energy', stops: 12 }, + { name: 'liquid', stops: 12 }, + { name: 'fern', stops: 12 }, + { name: 'cool', stops: 12 }, + { name: 'river', stops: 12 }, + { name: 'berry', stops: 12 }, + { name: 'destroy', stops: 8 }, + { name: 'warn', stops: 8 }, + { name: 'succeed', stops: 8 }, +] +const toOKLCHVar = val => `oklch(var(${val}) / ) ` + +const themeColors = Object.fromEntries( + themeColorRamps.map(({name, stops}) => [ + name, + Object.fromEntries( + new Array(stops) + .fill(0) + .map((_, i) => [ + (i + 1) * 10, + toOKLCHVar(`--_${name}-${(i + 1) * 10}`), + ]) + ), + ]) +) + /** @type {import('tailwindcss').Config} */ module.exports = { content: [ "./src/**/*.{js,jsx,ts,tsx}", ], theme: { - extend: {}, + extend: { + colors: { + ...themeColors, + }, + }, }, plugins: [], } diff --git a/yarn.lock b/yarn.lock index a6e500615..824ec44b2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1539,6 +1539,32 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" +"@fortawesome/fontawesome-common-types@6.4.0": + version "6.4.0" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.0.tgz#88da2b70d6ca18aaa6ed3687832e11f39e80624b" + integrity sha512-HNii132xfomg5QVZw0HwXXpN22s7VBHQBv9CeOu9tfJnhsWQNd2lmTNi8CSrnw5B+5YOmzu1UoPAyxaXsJ6RgQ== + +"@fortawesome/fontawesome-svg-core@^6.4.0": + version "6.4.0" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.4.0.tgz#3727552eff9179506e9203d72feb5b1063c11a21" + integrity sha512-Bertv8xOiVELz5raB2FlXDPKt+m94MQ3JgDfsVbrqNpLU9+UE2E18GKjLKw+d3XbeYPqg1pzyQKGsrzbw+pPaw== + dependencies: + "@fortawesome/fontawesome-common-types" "6.4.0" + +"@fortawesome/free-solid-svg-icons@^6.4.0": + version "6.4.0" + resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.4.0.tgz#48c0e790847fa56299e2f26b82b39663b8ad7119" + integrity sha512-kutPeRGWm8V5dltFP1zGjQOEAzaLZj4StdQhWVZnfGFCvAPVvHh8qk5bRrU4KXnRRRNni5tKQI9PBAdI6MP8nQ== + dependencies: + "@fortawesome/fontawesome-common-types" "6.4.0" + +"@fortawesome/react-fontawesome@^0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz#d90dd8a9211830b4e3c08e94b63a0ba7291ddcf4" + integrity sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw== + dependencies: + prop-types "^15.8.1" + "@headlessui/react@^1.7.13": version "1.7.13" resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-1.7.13.tgz#fd150b394954e9f1d86ed2340cffd1217d6e7628" @@ -1958,6 +1984,11 @@ schema-utils "^3.0.0" source-map "^0.7.3" +"@remix-run/router@1.7.1": + version "1.7.1" + resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.7.1.tgz#fea7ac35ae4014637c130011f59428f618730498" + integrity sha512-bgVQM4ZJ2u2CM8k1ey70o1ePFXsEzYVZoWghh6WjM8p59jQ7HxzbHW4SbnWFG7V9ig9chLawQxDTZ3xzOF8MkQ== + "@rollup/plugin-babel@^5.2.0": version "5.3.1" resolved "https://registry.yarnpkg.com/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz#04bc0608f4aa4b2e4b1aebf284344d0f68fda283" @@ -5568,6 +5599,11 @@ globby@^11.0.4, globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" +goober@^2.1.10: + version "2.1.13" + resolved "https://registry.yarnpkg.com/goober/-/goober-2.1.13.tgz#e3c06d5578486212a76c9eba860cbc3232ff6d7c" + integrity sha512-jFj3BQeleOoy7t93E9rZ2de+ScC4lQICLwiAQmKMg9F6roKGaLSHoCDYKkWlSafg138jejvq/mTdvmnwDQgqoQ== + gopd@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" @@ -8802,6 +8838,13 @@ react-error-overlay@^6.0.11: resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.11.tgz#92835de5841c5cf08ba00ddd2d677b6d17ff9adb" integrity sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg== +react-hot-toast@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/react-hot-toast/-/react-hot-toast-2.4.1.tgz#df04295eda8a7b12c4f968e54a61c8d36f4c0994" + integrity sha512-j8z+cQbWIM5LY37pR6uZR6D4LfseplqnuAO4co4u8917hBUvXlEqyP1ZzqVLcqoyUesZZv/ImreoCeHVDpE5pQ== + dependencies: + goober "^2.1.10" + react-is@^16.13.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" @@ -8842,6 +8885,21 @@ react-refresh@^0.11.0: resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.11.0.tgz#77198b944733f0f1f1a90e791de4541f9f074046" integrity sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A== +react-router-dom@^6.14.1: + version "6.14.1" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.14.1.tgz#0ad7ba7abdf75baa61169d49f096f0494907a36f" + integrity sha512-ssF6M5UkQjHK70fgukCJyjlda0Dgono2QGwqGvuk7D+EDGHdacEN3Yke2LTMjkrpHuFwBfDFsEjGVXBDmL+bWw== + dependencies: + "@remix-run/router" "1.7.1" + react-router "6.14.1" + +react-router@6.14.1: + version "6.14.1" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.14.1.tgz#5e82bcdabf21add859dc04b1859f91066b3a5810" + integrity sha512-U4PfgvG55LdvbQjg5Y9QRWyVxIdO1LlpYT7x+tMAxd9/vmiPuJhIwdxZuIQLN/9e3O4KFDHYfR9gzGeYMasW8g== + dependencies: + "@remix-run/router" "1.7.1" + react-scripts@5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-5.0.1.tgz#6285dbd65a8ba6e49ca8d651ce30645a6d980003"