main
tsx 123 lines 4.78 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 import {RefreshIcon, ShareIcon} from '@heroicons/react/outline';
9 import {CheckIcon} from '@heroicons/react/solid';
10 import clsx from 'clsx';
11 import Link from 'next/link';
12 import {useSnackbar} from 'notistack';
13 import {
14 useState,
15 startTransition,
16 unstable_addTransitionType as addTransitionType,
17 } from 'react';
18 import {defaultStore} from '../lib/defaultStore';
19 import {IconGitHub} from './Icons/IconGitHub';
20 import Logo from './Logo';
21 import {useStore, useStoreDispatch} from './StoreContext';
22 import {TOGGLE_INTERNALS_TRANSITION} from '../lib/transitionTypes';
23
24 export default function Header(): JSX.Element {
25 const [showCheck, setShowCheck] = useState(false);
26 const store = useStore();
27 const dispatchStore = useStoreDispatch();
28 const {enqueueSnackbar, closeSnackbar} = useSnackbar();
29
30 const handleReset: () => void = () => {
31 if (confirm('Are you sure you want to reset the playground?')) {
32 /**
33 * Close open snackbars if any. This is necessary because when displaying
34 * outputs (Preview or not), we only close previous snackbars if we received
35 * new messages, which is needed in order to display "Bad URL" or success
36 * messages when loading Playground for the first time. Otherwise, messages
37 * such as "Bad URL" will be closed by the outputs calling `closeSnackbar`.
38 */
39 closeSnackbar();
40 dispatchStore({type: 'setStore', payload: {store: defaultStore}});
41 }
42 };
43
44 const handleShare: () => void = () => {
45 navigator.clipboard.writeText(location.href).then(() => {
46 enqueueSnackbar('URL copied to clipboard');
47 setShowCheck(true);
48 // Show the check mark icon briefly after URL is copied
49 setTimeout(() => setShowCheck(false), 1000);
50 });
51 };
52
53 return (
54 <div className="fixed z-10 flex items-center justify-between w-screen px-5 py-3 bg-white border-b border-gray-200 h-14">
55 <div className="flex items-center flex-none h-full gap-2 text-lg">
56 <Logo
57 className={clsx(
58 'w-8 h-8 text-link',
59 process.env.NODE_ENV === 'development' && 'text-yellow-600',
60 )}
61 />
62 <p className="hidden select-none sm:block">React Compiler Playground</p>
63 </div>
64 <div className="flex items-center text-[15px] gap-4">
65 <div className="flex items-center gap-2">
66 <label className="show-internals relative inline-block w-[34px] h-5">
67 <input
68 type="checkbox"
69 checked={store.showInternals}
70 onChange={() =>
71 startTransition(() => {
72 addTransitionType(TOGGLE_INTERNALS_TRANSITION);
73 dispatchStore({type: 'toggleInternals'});
74 })
75 }
76 className="absolute opacity-0 cursor-pointer h-full w-full m-0"
77 />
78 <span
79 className={clsx(
80 'absolute inset-0 rounded-full cursor-pointer transition-all duration-250',
81 "before:content-[''] before:absolute before:w-4 before:h-4 before:left-0.5 before:bottom-0.5",
82 'before:bg-white before:rounded-full before:transition-transform before:duration-250',
83 'focus-within:shadow-[0_0_1px_#2196F3]',
84 store.showInternals
85 ? 'bg-link before:translate-x-3.5'
86 : 'bg-gray-300',
87 )}></span>
88 </label>
89 <span className="text-secondary">Show Internals</span>
90 </div>
91 <button
92 title="Reset Playground"
93 aria-label="Reset Playground"
94 className="flex items-center gap-1 transition-colors duration-150 ease-in text-secondary hover:text-link"
95 onClick={handleReset}>
96 <RefreshIcon className="w-5 h-5" />
97 <p className="hidden sm:block">Reset</p>
98 </button>
99 <button
100 title="Copy sharable URL"
101 aria-label="Copy sharable URL"
102 className="flex items-center gap-1 transition-colors duration-150 ease-in text-secondary hover:text-link"
103 onClick={handleShare}
104 disabled={showCheck}>
105 {!showCheck ? (
106 <ShareIcon className="w-5 h-5" />
107 ) : (
108 <CheckIcon className="w-5 h-5 fill-blue-50" />
109 )}
110 <p className="hidden sm:block">Share</p>
111 </button>
112 <Link
113 href="https://github.com/facebook/react"
114 target="_blank"
115 rel="noreferrer noopener"
116 aria-label="Open on GitHub"
117 className="flex items-center gap-1 transition-colors duration-150 ease-in text-secondary hover:text-link">
118 <IconGitHub />
119 </Link>
120 </div>
121 </div>
122 );
123 }