Compare commits
40 Commits
feature/in
...
feat/add-g
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a0303ecfa4 | ||
|
|
5a79e07c2d | ||
|
|
1107bb8196 | ||
|
|
405aafed7e | ||
|
|
03156474f3 | ||
|
|
7982209732 | ||
|
|
0f9963b972 | ||
|
|
650243279a | ||
|
|
6f183049d5 | ||
|
|
48706effc1 | ||
|
|
c9740b1e8a | ||
|
|
166300b8d5 | ||
|
|
99968855e0 | ||
|
|
a62a9c3700 | ||
|
|
4e971ce119 | ||
|
|
72ba2072ec | ||
|
|
bd8d3c39c2 | ||
|
|
7142f5b5e2 | ||
|
|
37516c602d | ||
|
|
cfa7a3bd30 | ||
|
|
266e4c3e6c | ||
|
|
4cf6d376f0 | ||
|
|
b2f49625db | ||
|
|
0b9fd172ce | ||
|
|
2582981d85 | ||
|
|
a0eda59982 | ||
|
|
9ae9db984d | ||
|
|
8f2c78b08b | ||
|
|
460412d3d7 | ||
|
|
1a182858b4 | ||
|
|
baac750e43 | ||
|
|
74979decbe | ||
|
|
db50d86921 | ||
|
|
19741add40 | ||
|
|
d79d013238 | ||
|
|
6d8ce9158d | ||
|
|
c6102c2e6a | ||
|
|
25cd64f8f6 | ||
|
|
33ef84c73e | ||
|
|
1c7e2998f5 |
88
components/AlertDialog.tsx
Normal file
88
components/AlertDialog.tsx
Normal file
@@ -0,0 +1,88 @@
|
||||
import React from "react";
|
||||
import { blackA } from "@radix-ui/colors";
|
||||
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
|
||||
import { styled, keyframes } from "../stitches.config";
|
||||
|
||||
const overlayShow = keyframes({
|
||||
"0%": { opacity: 0 },
|
||||
"100%": { opacity: 1 },
|
||||
});
|
||||
|
||||
const contentShow = keyframes({
|
||||
"0%": { opacity: 0, transform: "translate(-50%, -48%) scale(.96)" },
|
||||
"100%": { opacity: 1, transform: "translate(-50%, -50%) scale(1)" },
|
||||
});
|
||||
|
||||
const StyledOverlay = styled(AlertDialogPrimitive.Overlay, {
|
||||
zIndex: 1000,
|
||||
backgroundColor: blackA.blackA9,
|
||||
position: "fixed",
|
||||
inset: 0,
|
||||
"@media (prefers-reduced-motion: no-preference)": {
|
||||
animation: `${overlayShow} 150ms cubic-bezier(0.16, 1, 0.3, 1)`,
|
||||
},
|
||||
".dark &": {
|
||||
backgroundColor: blackA.blackA11,
|
||||
},
|
||||
});
|
||||
|
||||
const Root: React.FC<AlertDialogPrimitive.AlertDialogProps> = ({
|
||||
children,
|
||||
...rest
|
||||
}) => {
|
||||
return (
|
||||
<AlertDialogPrimitive.Root {...rest}>
|
||||
<StyledOverlay />
|
||||
{children}
|
||||
</AlertDialogPrimitive.Root>
|
||||
);
|
||||
};
|
||||
|
||||
const StyledContent = styled(AlertDialogPrimitive.Content, {
|
||||
zIndex: 1000,
|
||||
backgroundColor: "$mauve2",
|
||||
color: "$mauve12",
|
||||
borderRadius: "$md",
|
||||
boxShadow:
|
||||
"0px 10px 38px -5px rgba(22, 23, 24, 0.25), 0px 10px 20px -5px rgba(22, 23, 24, 0.2)",
|
||||
position: "fixed",
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
width: "90vw",
|
||||
maxWidth: "450px",
|
||||
maxHeight: "85vh",
|
||||
padding: 25,
|
||||
"@media (prefers-reduced-motion: no-preference)": {
|
||||
animation: `${contentShow} 150ms cubic-bezier(0.16, 1, 0.3, 1)`,
|
||||
},
|
||||
"&:focus": { outline: "none" },
|
||||
".dark &": {
|
||||
backgroundColor: "$mauve5",
|
||||
boxShadow:
|
||||
"0px 10px 38px 0px rgba(0, 0, 0, 0.85), 0px 10px 20px 0px rgba(0, 0, 0, 0.6)",
|
||||
},
|
||||
});
|
||||
|
||||
const StyledTitle = styled(AlertDialogPrimitive.Title, {
|
||||
margin: 0,
|
||||
color: "$mauve12",
|
||||
fontWeight: 500,
|
||||
fontSize: "$lg",
|
||||
});
|
||||
|
||||
const StyledDescription = styled(AlertDialogPrimitive.Description, {
|
||||
marginBottom: 20,
|
||||
color: "$mauve11",
|
||||
lineHeight: 1.5,
|
||||
fontSize: "$sm",
|
||||
});
|
||||
|
||||
// Exports
|
||||
export const AlertDialog = Root;
|
||||
export const AlertDialogTrigger = AlertDialogPrimitive.Trigger;
|
||||
export const AlertDialogContent = StyledContent;
|
||||
export const AlertDialogTitle = StyledTitle;
|
||||
export const AlertDialogDescription = StyledDescription;
|
||||
export const AlertDialogAction = AlertDialogPrimitive.Action;
|
||||
export const AlertDialogCancel = AlertDialogPrimitive.Cancel;
|
||||
@@ -1,6 +1,9 @@
|
||||
import React from "react";
|
||||
import { styled } from "../stitches.config";
|
||||
import Flex from "./Flex";
|
||||
import Spinner from "./Spinner";
|
||||
|
||||
const Button = styled("button", {
|
||||
export const StyledButton = styled("button", {
|
||||
// Reset
|
||||
all: "unset",
|
||||
appereance: "none",
|
||||
@@ -27,14 +30,21 @@ const Button = styled("button", {
|
||||
fontSize: "$2",
|
||||
fontWeight: 500,
|
||||
fontVariantNumeric: "tabular-nums",
|
||||
backgroundColor: "red",
|
||||
cursor: "pointer",
|
||||
width: "max-content",
|
||||
"&:disabled": {
|
||||
opacity: 0.8,
|
||||
opacity: 0.6,
|
||||
pointerEvents: "none",
|
||||
cursor: "not-allowed",
|
||||
},
|
||||
variants: {
|
||||
size: {
|
||||
xs: {
|
||||
borderRadius: "$sm",
|
||||
height: "$5",
|
||||
px: "$2",
|
||||
fontSize: "$xs",
|
||||
},
|
||||
sm: {
|
||||
borderRadius: "$sm",
|
||||
height: "$7",
|
||||
@@ -56,27 +66,27 @@ const Button = styled("button", {
|
||||
},
|
||||
variant: {
|
||||
default: {
|
||||
backgroundColor: "$slate12",
|
||||
boxShadow: "inset 0 0 0 1px $colors$slate12",
|
||||
color: "$slate1",
|
||||
backgroundColor: "$mauve12",
|
||||
boxShadow: "inset 0 0 0 1px $colors$mauve12",
|
||||
color: "$mauve1",
|
||||
"@hover": {
|
||||
"&:hover": {
|
||||
backgroundColor: "$slate12",
|
||||
boxShadow: "inset 0 0 0 1px $colors$slate12",
|
||||
backgroundColor: "$mauve12",
|
||||
boxShadow: "inset 0 0 0 1px $colors$mauve12",
|
||||
},
|
||||
},
|
||||
"&:active": {
|
||||
backgroundColor: "$slate10",
|
||||
boxShadow: "inset 0 0 0 1px $colors$slate11",
|
||||
backgroundColor: "$mauve10",
|
||||
boxShadow: "inset 0 0 0 1px $colors$mauve11",
|
||||
},
|
||||
"&:focus": {
|
||||
boxShadow:
|
||||
"inset 0 0 0 1px $colors$slate12, 0 0 0 1px $colors$slate12",
|
||||
"inset 0 0 0 1px $colors$mauve12, inset 0 0 0 2px $colors$mauve12",
|
||||
},
|
||||
'&[data-radix-popover-trigger][data-state="open"], &[data-radix-dropdown-menu-trigger][data-state="open"]':
|
||||
{
|
||||
backgroundColor: "$slate4",
|
||||
boxShadow: "inset 0 0 0 1px $colors$slate8",
|
||||
backgroundColor: "$mauve4",
|
||||
boxShadow: "inset 0 0 0 1px $colors$mauve8",
|
||||
},
|
||||
},
|
||||
primary: {
|
||||
@@ -94,11 +104,11 @@ const Button = styled("button", {
|
||||
boxShadow: "inset 0 0 0 1px $colors$pink8",
|
||||
},
|
||||
"&:focus": {
|
||||
boxShadow: "inset 0 0 0 1px $colors$pink8",
|
||||
boxShadow: "inset 0 0 0 2px $colors$pink12",
|
||||
},
|
||||
'&[data-radix-popover-trigger][data-state="open"], &[data-radix-dropdown-menu-trigger][data-state="open"]':
|
||||
{
|
||||
backgroundColor: "$slate4",
|
||||
backgroundColor: "$mauve4",
|
||||
boxShadow: "inset 0 0 0 1px $colors$pink8",
|
||||
},
|
||||
},
|
||||
@@ -113,19 +123,24 @@ const Button = styled("button", {
|
||||
textTransform: "uppercase",
|
||||
},
|
||||
},
|
||||
fullWidth: {
|
||||
true: {
|
||||
width: "100%",
|
||||
},
|
||||
},
|
||||
ghost: {
|
||||
true: {
|
||||
boxShadow: "none",
|
||||
background: "transparent",
|
||||
color: "$slate12",
|
||||
color: "$mauve12",
|
||||
"@hover": {
|
||||
"&:hover": {
|
||||
backgroundColor: "$slate6",
|
||||
backgroundColor: "$mauve6",
|
||||
boxShadow: "none",
|
||||
},
|
||||
},
|
||||
"&:active": {
|
||||
backgroundColor: "$slate8",
|
||||
backgroundColor: "$mauve8",
|
||||
boxShadow: "none",
|
||||
},
|
||||
"&:focus": {
|
||||
@@ -133,19 +148,26 @@ const Button = styled("button", {
|
||||
},
|
||||
},
|
||||
},
|
||||
isLoading: {
|
||||
true: {
|
||||
"& .button-content": {
|
||||
visibility: "hidden",
|
||||
},
|
||||
pointerEvents: "none",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
compoundVariants: [
|
||||
{
|
||||
outline: true,
|
||||
variant: "default",
|
||||
css: {
|
||||
background: "transparent",
|
||||
color: "$slate12",
|
||||
boxShadow: "inset 0 0 0 1px $colors$slate10",
|
||||
color: "$mauve12",
|
||||
boxShadow: "inset 0 0 0 1px $colors$mauve10",
|
||||
"&:hover": {
|
||||
color: "$slate12",
|
||||
background: "$slate5",
|
||||
color: "$mauve12",
|
||||
background: "$mauve5",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -154,10 +176,10 @@ const Button = styled("button", {
|
||||
variant: "primary",
|
||||
css: {
|
||||
background: "transparent",
|
||||
color: "$slate12",
|
||||
color: "$mauve12",
|
||||
"&:hover": {
|
||||
color: "$slate12",
|
||||
background: "$slate5",
|
||||
color: "$mauve12",
|
||||
background: "$mauve5",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -168,4 +190,22 @@ const Button = styled("button", {
|
||||
},
|
||||
});
|
||||
|
||||
export default Button;
|
||||
const CustomButton: React.FC<
|
||||
React.ComponentProps<typeof StyledButton> & { as?: string }
|
||||
> = React.forwardRef(({ children, as = "button", ...rest }, ref) => (
|
||||
// @ts-expect-error
|
||||
<StyledButton {...rest} ref={ref} as={as}>
|
||||
<Flex
|
||||
as="span"
|
||||
css={{ gap: "$2", alignItems: "center" }}
|
||||
className="button-content"
|
||||
>
|
||||
{children}
|
||||
</Flex>
|
||||
{rest.isLoading && <Spinner css={{ position: "absolute" }} />}
|
||||
</StyledButton>
|
||||
));
|
||||
|
||||
CustomButton.displayName = "CustomButton";
|
||||
|
||||
export default CustomButton;
|
||||
|
||||
29
components/ButtonGroup.tsx
Normal file
29
components/ButtonGroup.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
import { styled } from "../stitches.config";
|
||||
import { StyledButton } from "./Button";
|
||||
|
||||
const ButtonGroup = styled("div", {
|
||||
display: "flex",
|
||||
marginLeft: "1px",
|
||||
[`& ${StyledButton}`]: {
|
||||
marginLeft: "-1px",
|
||||
px: "$4",
|
||||
zIndex: 2,
|
||||
position: "relative",
|
||||
"&:hover, &:focus": {
|
||||
zIndex: 200,
|
||||
},
|
||||
},
|
||||
[`& ${StyledButton}:not(:only-of-type):not(:first-child):not(:last-child)`]: {
|
||||
borderRadius: 0,
|
||||
},
|
||||
[`& ${StyledButton}:first-child:not(:only-of-type)`]: {
|
||||
borderBottomRightRadius: 0,
|
||||
borderTopRightRadius: 0,
|
||||
},
|
||||
[`& ${StyledButton}:last-child:not(:only-of-type)`]: {
|
||||
borderBottomLeftRadius: 0,
|
||||
borderTopLeftRadius: 0,
|
||||
},
|
||||
});
|
||||
|
||||
export default ButtonGroup;
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from "react";
|
||||
import * as Stiches from "@stitches/react";
|
||||
import { keyframes } from "@stitches/react";
|
||||
import { violet, blackA, mauve, whiteA } from "@radix-ui/colors";
|
||||
import { blackA } from "@radix-ui/colors";
|
||||
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
||||
import { styled } from "../stitches.config";
|
||||
|
||||
@@ -23,14 +23,14 @@ const StyledOverlay = styled(DialogPrimitive.Overlay, {
|
||||
animation: `${overlayShow} 150ms cubic-bezier(0.16, 1, 0.3, 1)`,
|
||||
},
|
||||
".dark &": {
|
||||
backgroundColor: blackA.blackA9,
|
||||
backgroundColor: blackA.blackA11,
|
||||
},
|
||||
});
|
||||
|
||||
const StyledContent = styled(DialogPrimitive.Content, {
|
||||
zIndex: 1000,
|
||||
backgroundColor: "$slate2",
|
||||
color: "$slate12",
|
||||
backgroundColor: "$mauve2",
|
||||
color: "$mauve12",
|
||||
borderRadius: "$md",
|
||||
boxShadow:
|
||||
"0px 10px 38px -5px rgba(22, 23, 24, 0.25), 0px 10px 20px -5px rgba(22, 23, 24, 0.2)",
|
||||
@@ -47,9 +47,9 @@ const StyledContent = styled(DialogPrimitive.Content, {
|
||||
},
|
||||
"&:focus": { outline: "none" },
|
||||
".dark &": {
|
||||
backgroundColor: "$slate5",
|
||||
backgroundColor: "$mauve5",
|
||||
boxShadow:
|
||||
"0px 10px 38px 0px rgba(22, 23, 24, 0.85), 0px 10px 20px 0px rgba(22, 23, 24, 0.6)",
|
||||
"0px 10px 38px 0px rgba(0, 0, 0, 0.85), 0px 10px 20px 0px rgba(0, 0, 0, 0.6)",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -65,39 +65,21 @@ const Content: React.FC<{ css?: Stiches.CSS }> = ({ css, children }) => {
|
||||
const StyledTitle = styled(DialogPrimitive.Title, {
|
||||
margin: 0,
|
||||
fontWeight: 500,
|
||||
color: "$slate12",
|
||||
color: "$mauve12",
|
||||
fontSize: 17,
|
||||
});
|
||||
|
||||
const StyledDescription = styled(DialogPrimitive.Description, {
|
||||
margin: "10px 0 20px",
|
||||
color: "$slate11",
|
||||
color: "$mauve11",
|
||||
fontSize: 15,
|
||||
lineHeight: 1.5,
|
||||
});
|
||||
|
||||
// Exports
|
||||
export const Dialog = DialogPrimitive.Root;
|
||||
export const Dialog = styled(DialogPrimitive.Root);
|
||||
export const DialogTrigger = DialogPrimitive.Trigger;
|
||||
export const DialogContent = Content;
|
||||
export const DialogTitle = StyledTitle;
|
||||
export const DialogDescription = StyledDescription;
|
||||
export const DialogClose = DialogPrimitive.Close;
|
||||
|
||||
const Input = styled("input", {
|
||||
all: "unset",
|
||||
width: "100%",
|
||||
flex: "1",
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
borderRadius: 4,
|
||||
padding: "0 10px",
|
||||
fontSize: 15,
|
||||
lineHeight: 1,
|
||||
color: violet.violet11,
|
||||
boxShadow: `0 0 0 1px ${violet.violet7}`,
|
||||
height: 35,
|
||||
|
||||
"&:focus": { boxShadow: `0 0 0 2px ${violet.violet8}` },
|
||||
});
|
||||
|
||||
@@ -2,7 +2,6 @@ import { keyframes } from "@stitches/react";
|
||||
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
||||
|
||||
import { styled } from "../stitches.config";
|
||||
import { blackA, slateDark } from "@radix-ui/colors";
|
||||
|
||||
const slideUpAndFade = keyframes({
|
||||
"0%": { opacity: 0, transform: "translateY(2px)" },
|
||||
@@ -26,7 +25,7 @@ const slideLeftAndFade = keyframes({
|
||||
|
||||
const StyledContent = styled(DropdownMenuPrimitive.Content, {
|
||||
minWidth: 220,
|
||||
backgroundColor: "$slate2",
|
||||
backgroundColor: "$mauve2",
|
||||
borderRadius: 6,
|
||||
padding: 5,
|
||||
boxShadow:
|
||||
@@ -43,7 +42,7 @@ const StyledContent = styled(DropdownMenuPrimitive.Content, {
|
||||
},
|
||||
},
|
||||
".dark &": {
|
||||
backgroundColor: "$slate5",
|
||||
backgroundColor: "$mauve5",
|
||||
boxShadow:
|
||||
"0px 10px 38px -10px rgba(22, 23, 24, 0.85), 0px 10px 20px -15px rgba(22, 23, 24, 0.6)",
|
||||
},
|
||||
@@ -53,7 +52,7 @@ const itemStyles = {
|
||||
all: "unset",
|
||||
fontSize: 13,
|
||||
lineHeight: 1,
|
||||
color: "$slate12",
|
||||
color: "$mauve12",
|
||||
borderRadius: 3,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
@@ -62,10 +61,12 @@ const itemStyles = {
|
||||
position: "relative",
|
||||
paddingLeft: "5px",
|
||||
userSelect: "none",
|
||||
py: "$0.5",
|
||||
pr: "$2",
|
||||
gap: "$2",
|
||||
|
||||
"&[data-disabled]": {
|
||||
color: "$slate9",
|
||||
color: "$mauve9",
|
||||
pointerEvents: "none",
|
||||
},
|
||||
|
||||
@@ -94,12 +95,12 @@ const StyledLabel = styled(DropdownMenuPrimitive.Label, {
|
||||
paddingLeft: 25,
|
||||
fontSize: 12,
|
||||
lineHeight: "25px",
|
||||
color: "$slate11",
|
||||
color: "$mauve11",
|
||||
});
|
||||
|
||||
const StyledSeparator = styled(DropdownMenuPrimitive.Separator, {
|
||||
height: 1,
|
||||
backgroundColor: "$slate7",
|
||||
backgroundColor: "$mauve7",
|
||||
margin: 5,
|
||||
});
|
||||
|
||||
@@ -113,7 +114,10 @@ const StyledItemIndicator = styled(DropdownMenuPrimitive.ItemIndicator, {
|
||||
});
|
||||
|
||||
const StyledArrow = styled(DropdownMenuPrimitive.Arrow, {
|
||||
fill: "$slate2",
|
||||
fill: "$mauve2",
|
||||
".dark &": {
|
||||
fill: "$mauve5",
|
||||
},
|
||||
});
|
||||
|
||||
// Exports
|
||||
|
||||
@@ -1,8 +1,37 @@
|
||||
import React, { useRef, useState } from "react";
|
||||
import { Plus, Share, DownloadSimple, Gear, X } from "phosphor-react";
|
||||
import { useTheme } from "next-themes";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import {
|
||||
Plus,
|
||||
Share,
|
||||
DownloadSimple,
|
||||
Gear,
|
||||
X,
|
||||
GithubLogo,
|
||||
SignOut,
|
||||
ArrowSquareOut,
|
||||
CloudArrowUp,
|
||||
CaretDown,
|
||||
User,
|
||||
FilePlus,
|
||||
} from "phosphor-react";
|
||||
import Image from "next/image";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuArrow,
|
||||
DropdownMenuSeparator,
|
||||
} from "./DropdownMenu";
|
||||
import NewWindow from "react-new-window";
|
||||
import { signOut, useSession } from "next-auth/react";
|
||||
import { useSnapshot } from "valtio";
|
||||
|
||||
import { createNewFile, state, updateEditorSettings } from "../state";
|
||||
import {
|
||||
createNewFile,
|
||||
state,
|
||||
syncToGist,
|
||||
updateEditorSettings,
|
||||
} from "../state";
|
||||
import Box from "./Box";
|
||||
import Button from "./Button";
|
||||
import Container from "./Container";
|
||||
@@ -16,23 +45,52 @@ import {
|
||||
} from "./Dialog";
|
||||
import Flex from "./Flex";
|
||||
import Stack from "./Stack";
|
||||
import { useSnapshot } from "valtio";
|
||||
import { useSession } from "next-auth/react";
|
||||
import { useRouter } from "next/router";
|
||||
import Input from "./Input";
|
||||
import toast from "react-hot-toast";
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogContent,
|
||||
AlertDialogTitle,
|
||||
AlertDialogDescription,
|
||||
AlertDialogCancel,
|
||||
AlertDialogAction,
|
||||
} from "./AlertDialog";
|
||||
|
||||
const EditorNavigation = () => {
|
||||
const snap = useSnapshot(state);
|
||||
const [createNewAlertOpen, setCreateNewAlertOpen] = useState(false);
|
||||
const [editorSettingsOpen, setEditorSettingsOpen] = useState(false);
|
||||
const [filename, setFilename] = useState("");
|
||||
const { theme } = useTheme();
|
||||
const { data: session, status } = useSession();
|
||||
const router = useRouter();
|
||||
const [popup, setPopUp] = useState(false);
|
||||
const [editorSettings, setEditorSettings] = useState(snap.editorSettings);
|
||||
useEffect(() => {
|
||||
if (session && session.user && popup) {
|
||||
setPopUp(false);
|
||||
}
|
||||
}, [session, popup]);
|
||||
return (
|
||||
<Flex css={{ flexShrink: 0, gap: "$0" }}>
|
||||
<Flex css={{ overflowX: "scroll", py: "$3", flex: 1 }}>
|
||||
<Flex
|
||||
css={{
|
||||
overflowX: "scroll",
|
||||
py: "$3",
|
||||
flex: 1,
|
||||
"&::-webkit-scrollbar": {
|
||||
height: 0,
|
||||
background: "transparent",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Container css={{ flex: 1 }}>
|
||||
<Stack css={{ gap: "$3", flex: 1, flexWrap: "nowrap" }}>
|
||||
{state.loading && "loading"}
|
||||
<Stack
|
||||
css={{
|
||||
gap: "$3",
|
||||
flex: 1,
|
||||
flexWrap: "nowrap",
|
||||
marginBottom: "-1px",
|
||||
}}
|
||||
>
|
||||
{snap.files &&
|
||||
snap.files.length > 0 &&
|
||||
snap.files?.map((file, index) => (
|
||||
@@ -40,7 +98,7 @@ const EditorNavigation = () => {
|
||||
size="sm"
|
||||
outline={snap.active !== index}
|
||||
onClick={() => (state.active = index)}
|
||||
key={file.name}
|
||||
key={file.name + index}
|
||||
css={{
|
||||
"&:hover": {
|
||||
span: {
|
||||
@@ -54,13 +112,28 @@ const EditorNavigation = () => {
|
||||
as="span"
|
||||
css={{
|
||||
display: "flex",
|
||||
p: "1px",
|
||||
p: "2px",
|
||||
borderRadius: "$full",
|
||||
mr: "-4px",
|
||||
"&:hover": {
|
||||
// boxSizing: "0px 0px 1px",
|
||||
backgroundColor: "$mauve2",
|
||||
color: "$mauve12",
|
||||
},
|
||||
}}
|
||||
onClick={(ev: React.MouseEvent<HTMLElement>) => {
|
||||
ev.stopPropagation();
|
||||
// Remove file from state
|
||||
state.files.splice(index, 1);
|
||||
// Change active file state
|
||||
// If deleted file is behind active tab
|
||||
// we keep the current state otherwise
|
||||
// select previous file on the list
|
||||
state.active =
|
||||
index > snap.active ? snap.active : snap.active - 1;
|
||||
}}
|
||||
onClick={() => state.files.splice(index, 1)}
|
||||
>
|
||||
<X size="13px" />
|
||||
<X size="9px" weight="bold" />
|
||||
</Box>
|
||||
</Button>
|
||||
))}
|
||||
@@ -79,10 +152,8 @@ const EditorNavigation = () => {
|
||||
<DialogContent>
|
||||
<DialogTitle>Create new file</DialogTitle>
|
||||
<DialogDescription>
|
||||
<span>
|
||||
Create empty C file or select one of the existing ones
|
||||
</span>
|
||||
<input
|
||||
<label>Filename</label>
|
||||
<Input
|
||||
value={filename}
|
||||
onChange={(e) => setFilename(e.target.value)}
|
||||
/>
|
||||
@@ -120,113 +191,276 @@ const EditorNavigation = () => {
|
||||
<Flex
|
||||
css={{
|
||||
py: "$3",
|
||||
backgroundColor: "$slate3",
|
||||
backgroundColor: "$mauve3",
|
||||
zIndex: 1,
|
||||
}}
|
||||
>
|
||||
<Container css={{ width: "unset" }}>
|
||||
<Container
|
||||
css={{ width: "unset", display: "flex", alignItems: "center" }}
|
||||
>
|
||||
{status === "authenticated" ? (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Box
|
||||
css={{
|
||||
display: "flex",
|
||||
borderRadius: "$full",
|
||||
overflow: "hidden",
|
||||
width: "$6",
|
||||
height: "$6",
|
||||
boxShadow: "0px 0px 0px 1px $colors$mauve11",
|
||||
position: "relative",
|
||||
mr: "$3",
|
||||
"@hover": {
|
||||
"&:hover": {
|
||||
cursor: "pointer",
|
||||
boxShadow: "0px 0px 0px 1px $colors$mauve12",
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
src={session?.user?.image || ""}
|
||||
width="30px"
|
||||
height="30px"
|
||||
objectFit="cover"
|
||||
alt="User avatar"
|
||||
/>
|
||||
</Box>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem disabled onClick={() => signOut()}>
|
||||
<User size="16px" /> {session?.user?.username} (
|
||||
{session?.user.name})
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
onClick={() =>
|
||||
window.open(
|
||||
`http://gist.github.com/${session?.user.username}`
|
||||
)
|
||||
}
|
||||
>
|
||||
<ArrowSquareOut size="16px" />
|
||||
Go to your Gist
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem onClick={() => signOut({ callbackUrl: "/" })}>
|
||||
<SignOut size="16px" /> Log out
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuArrow offset={10} />
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
) : (
|
||||
<Button
|
||||
outline
|
||||
size="sm"
|
||||
css={{ mr: "$3" }}
|
||||
onClick={() => setPopUp(true)}
|
||||
>
|
||||
<GithubLogo size="16px" /> Login
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<Stack
|
||||
css={{
|
||||
display: "inline-flex",
|
||||
marginLeft: "auto",
|
||||
flexShrink: 0,
|
||||
gap: "$0",
|
||||
border: "1px solid $slate10",
|
||||
borderRadius: "$sm",
|
||||
boxShadow: "inset 0px 0px 0px 1px $colors$mauve10",
|
||||
zIndex: 9,
|
||||
position: "relative",
|
||||
overflow: "hidden",
|
||||
button: {
|
||||
borderRadius: "$0",
|
||||
borderRadius: 0,
|
||||
px: "$2",
|
||||
alignSelf: "flex-start",
|
||||
boxShadow: "none",
|
||||
},
|
||||
"button:not(:first-child):not(:last-child)": {
|
||||
borderRight: 0,
|
||||
borderLeft: 0,
|
||||
},
|
||||
"button:first-child": {
|
||||
borderTopLeftRadius: "$sm",
|
||||
borderBottomLeftRadius: "$sm",
|
||||
},
|
||||
"button:last-child": {
|
||||
borderTopRightRadius: "$sm",
|
||||
borderBottomRightRadius: "$sm",
|
||||
boxShadow: "inset 0px 0px 0px 1px $colors$mauve10",
|
||||
"&:hover": {
|
||||
boxShadow: "inset 0px 0px 0px 1px $colors$mauve12",
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Button ghost size="sm" css={{ alignItems: "center" }}>
|
||||
<Button outline size="sm" css={{ alignItems: "center" }}>
|
||||
<DownloadSimple size="16px" />
|
||||
</Button>
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button ghost size="sm" css={{ alignItems: "center" }}>
|
||||
<Button
|
||||
outline
|
||||
size="sm"
|
||||
css={{ alignItems: "center" }}
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(
|
||||
`${window.location.origin}/develop/${snap.gistId}`
|
||||
);
|
||||
toast.success("Copied share link to clipboard!");
|
||||
}}
|
||||
>
|
||||
<Share size="16px" />
|
||||
</Button>
|
||||
<Button
|
||||
outline
|
||||
size="sm"
|
||||
disabled={!session || !session.user}
|
||||
isLoading={snap.gistLoading}
|
||||
css={{ alignItems: "center" }}
|
||||
onClick={() => {
|
||||
if (snap.gistOwner === session?.user.username) {
|
||||
syncToGist(session);
|
||||
} else {
|
||||
setCreateNewAlertOpen(true);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<CloudArrowUp size="16px" />
|
||||
</Button>
|
||||
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button outline size="sm">
|
||||
<CaretDown size="16px" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem>
|
||||
<DownloadSimple size="16px" /> Download as ZIP
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(
|
||||
`${window.location.origin}/develop/${snap.gistId}`
|
||||
);
|
||||
toast.success("Copied share link to clipboard!");
|
||||
}}
|
||||
>
|
||||
<Share size="16px" />
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogTitle>Share hook</DialogTitle>
|
||||
<DialogDescription>
|
||||
<span>
|
||||
We will store your hook code in public GitHub Gist and
|
||||
generate link to that
|
||||
</span>
|
||||
</DialogDescription>
|
||||
|
||||
<Flex
|
||||
css={{ marginTop: 25, justifyContent: "flex-end", gap: "$3" }}
|
||||
Copy share link to clipboard
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
disabled={
|
||||
session?.user.username !== snap.gistOwner || !snap.gistId
|
||||
}
|
||||
onClick={() => {
|
||||
syncToGist(session);
|
||||
}}
|
||||
>
|
||||
<DialogClose asChild>
|
||||
<Button outline>Cancel</Button>
|
||||
</DialogClose>
|
||||
</Flex>
|
||||
<DialogClose asChild>
|
||||
<Box css={{ position: "absolute", top: "$3", right: "$3" }}>
|
||||
<X size="20px" />
|
||||
</Box>
|
||||
</DialogClose>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button ghost size="sm" css={{ alignItems: "center" }}>
|
||||
<Gear size="16px" />
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogTitle>Editor settings</DialogTitle>
|
||||
<DialogDescription>
|
||||
<span>You can edit your editor settings here</span>
|
||||
<input
|
||||
value={editorSettings.tabSize}
|
||||
onChange={(e) =>
|
||||
setEditorSettings((curr) => ({
|
||||
...curr,
|
||||
tabSize: Number(e.target.value),
|
||||
}))
|
||||
}
|
||||
/>
|
||||
</DialogDescription>
|
||||
|
||||
<Flex
|
||||
css={{ marginTop: 25, justifyContent: "flex-end", gap: "$3" }}
|
||||
<CloudArrowUp size="16px" /> Push to Gist
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem
|
||||
disabled={status !== "authenticated"}
|
||||
onClick={() => {
|
||||
setCreateNewAlertOpen(true);
|
||||
}}
|
||||
>
|
||||
<DialogClose asChild>
|
||||
<Button
|
||||
outline
|
||||
onClick={() => updateEditorSettings(editorSettings)}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<DialogClose asChild>
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={() => updateEditorSettings(editorSettings)}
|
||||
>
|
||||
Save changes
|
||||
</Button>
|
||||
</DialogClose>
|
||||
</Flex>
|
||||
<DialogClose asChild>
|
||||
<Box css={{ position: "absolute", top: "$3", right: "$3" }}>
|
||||
<X size="20px" />
|
||||
</Box>
|
||||
</DialogClose>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
<FilePlus size="16px" /> Create as a new Gist
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuItem onClick={() => setEditorSettingsOpen(true)}>
|
||||
<Gear size="16px" /> Editor Settings
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuArrow offset={10} />
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</Stack>
|
||||
|
||||
{popup && !session ? (
|
||||
<NewWindow center="parent" url="/sign-in" />
|
||||
) : null}
|
||||
</Container>
|
||||
</Flex>
|
||||
<AlertDialog
|
||||
open={createNewAlertOpen}
|
||||
onOpenChange={(value) => setCreateNewAlertOpen(value)}
|
||||
>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogTitle>Are you sure?</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
This action will create new <strong>public</strong> Github Gist from
|
||||
your current saved files. You can delete gist anytime from your
|
||||
GitHub Gists page.
|
||||
</AlertDialogDescription>
|
||||
<Flex css={{ justifyContent: "flex-end", gap: "$3" }}>
|
||||
<AlertDialogCancel asChild>
|
||||
<Button outline>Cancel</Button>
|
||||
</AlertDialogCancel>
|
||||
<AlertDialogAction asChild>
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={() => {
|
||||
syncToGist(session, true);
|
||||
}}
|
||||
>
|
||||
<FilePlus size="15px" /> Create new Gist
|
||||
</Button>
|
||||
</AlertDialogAction>
|
||||
</Flex>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
|
||||
<Dialog open={editorSettingsOpen} onOpenChange={setEditorSettingsOpen}>
|
||||
<DialogTrigger asChild>
|
||||
{/* <Button outline size="sm" css={{ alignItems: "center" }}>
|
||||
<Gear size="16px" />
|
||||
</Button> */}
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogTitle>Editor settings</DialogTitle>
|
||||
<DialogDescription>
|
||||
<label>Tab size</label>
|
||||
<Input
|
||||
type="number"
|
||||
min="1"
|
||||
value={editorSettings.tabSize}
|
||||
onChange={(e) =>
|
||||
setEditorSettings((curr) => ({
|
||||
...curr,
|
||||
tabSize: Number(e.target.value),
|
||||
}))
|
||||
}
|
||||
/>
|
||||
</DialogDescription>
|
||||
|
||||
<Flex css={{ marginTop: 25, justifyContent: "flex-end", gap: "$3" }}>
|
||||
<DialogClose asChild>
|
||||
<Button
|
||||
outline
|
||||
onClick={() => updateEditorSettings(editorSettings)}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<DialogClose asChild>
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={() => updateEditorSettings(editorSettings)}
|
||||
>
|
||||
Save changes
|
||||
</Button>
|
||||
</DialogClose>
|
||||
</Flex>
|
||||
<DialogClose asChild>
|
||||
<Box css={{ position: "absolute", top: "$3", right: "$3" }}>
|
||||
<X size="20px" />
|
||||
</Box>
|
||||
</DialogClose>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
import React from "react";
|
||||
import { useSnapshot } from "valtio";
|
||||
import Container from "./Container";
|
||||
import Box from "./Box";
|
||||
|
||||
import LogText from "./LogText";
|
||||
import { state } from "../state";
|
||||
import { compileCode, state } from "../state";
|
||||
import { Play, Prohibit } from "phosphor-react";
|
||||
import Button from "./Button";
|
||||
import Heading from "./Heading";
|
||||
|
||||
const Footer = () => {
|
||||
const snap = useSnapshot(state);
|
||||
@@ -12,11 +16,33 @@ const Footer = () => {
|
||||
as="footer"
|
||||
css={{
|
||||
display: "flex",
|
||||
borderTop: "1px solid $slate6",
|
||||
background: "$slate1",
|
||||
borderTop: "1px solid $mauve6",
|
||||
background: "$mauve1",
|
||||
position: "relative",
|
||||
}}
|
||||
>
|
||||
<Container css={{ py: "$4", flexShrink: 1 }}>
|
||||
<Container css={{ py: "$3", flexShrink: 1 }}>
|
||||
<Heading
|
||||
as="h3"
|
||||
css={{ fontWeight: 300, m: 0, fontSize: "11px", color: "$mauve9" }}
|
||||
>
|
||||
DEVELOPMENT LOG
|
||||
</Heading>
|
||||
<Button
|
||||
ghost
|
||||
size="xs"
|
||||
css={{
|
||||
position: "absolute",
|
||||
right: "$3",
|
||||
top: "$2",
|
||||
color: "$mauve10",
|
||||
}}
|
||||
onClick={() => {
|
||||
state.logs = [];
|
||||
}}
|
||||
>
|
||||
<Prohibit size="14px" />
|
||||
</Button>
|
||||
<Box
|
||||
as="pre"
|
||||
css={{
|
||||
@@ -27,15 +53,13 @@ const Footer = () => {
|
||||
fontSize: "13px",
|
||||
fontWeight: "$body",
|
||||
fontFamily: "$monospace",
|
||||
overflowY: "scroll",
|
||||
overflowY: "auto",
|
||||
wordWrap: "break-word",
|
||||
py: 3,
|
||||
px: 3,
|
||||
m: 3,
|
||||
}}
|
||||
>
|
||||
{snap.logs.map((log, index) => (
|
||||
<Box key={log.type + index}>
|
||||
{snap.logs?.map((log, index) => (
|
||||
<Box as="span" key={log.type + index}>
|
||||
<LogText capitalize variant={log.type}>
|
||||
{log.type}:{" "}
|
||||
</LogText>
|
||||
@@ -43,6 +67,24 @@ const Footer = () => {
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
<Button
|
||||
variant="primary"
|
||||
uppercase
|
||||
disabled={!snap.files.length}
|
||||
isLoading={snap.compiling}
|
||||
onClick={() => compileCode(snap.active)}
|
||||
css={{
|
||||
position: "absolute",
|
||||
bottom: "$4",
|
||||
left: "$4",
|
||||
alignItems: "center",
|
||||
display: "flex",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
>
|
||||
<Play weight="bold" size="16px" />
|
||||
Compile to Wasm
|
||||
</Button>
|
||||
</Container>
|
||||
</Box>
|
||||
);
|
||||
|
||||
@@ -4,7 +4,13 @@ const Heading = styled("span", {
|
||||
fontFamily: "$heading",
|
||||
lineHeight: "$heading",
|
||||
fontWeight: "$heading",
|
||||
textTransform: "uppercase",
|
||||
variants: {
|
||||
uppercase: {
|
||||
true: {
|
||||
textTransform: "uppercase",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default Heading;
|
||||
|
||||
@@ -1,33 +1,25 @@
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import React, { useRef } from "react";
|
||||
import { useSnapshot, ref } from "valtio";
|
||||
import Editor from "@monaco-editor/react";
|
||||
import type monaco from "monaco-editor";
|
||||
import { Play } from "phosphor-react";
|
||||
import { ArrowBendLeftUp } from "phosphor-react";
|
||||
import { useTheme } from "next-themes";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
import Box from "./Box";
|
||||
import Button from "./Button";
|
||||
import Container from "./Container";
|
||||
import dark from "../theme/editor/amy.json";
|
||||
import light from "../theme/editor/xcode_default.json";
|
||||
import { compileCode, saveFile, state } from "../state";
|
||||
import { saveFile, state } from "../state";
|
||||
|
||||
import EditorNavigation from "./EditorNavigation";
|
||||
import Spinner from "./Spinner";
|
||||
import Text from "./Text";
|
||||
|
||||
const HooksEditor = () => {
|
||||
const editorRef = useRef<monaco.editor.IStandaloneCodeEditor>();
|
||||
const snap = useSnapshot(state);
|
||||
const router = useRouter();
|
||||
const { theme } = useTheme();
|
||||
// useEffect(() => {
|
||||
// if (snap.editorCtx) {
|
||||
// snap.editorCtx.getModels().forEach((model) => {
|
||||
// // console.log(model.id,);
|
||||
// snap.editorCtx?.createModel(model.getValue(), "c", model.uri);
|
||||
// });
|
||||
// }
|
||||
// // eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
// }, []);
|
||||
console.log("reinit");
|
||||
return (
|
||||
<Box
|
||||
css={{
|
||||
@@ -36,61 +28,76 @@ const HooksEditor = () => {
|
||||
display: "flex",
|
||||
position: "relative",
|
||||
flexDirection: "column",
|
||||
backgroundColor: "$slate3",
|
||||
backgroundColor: "$mauve3",
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
<EditorNavigation />
|
||||
<Editor
|
||||
keepCurrentModel
|
||||
// defaultLanguage={snap.files?.[snap.active]?.language}
|
||||
path={snap.files?.[snap.active]?.name}
|
||||
// defaultValue={snap.files?.[snap.active]?.content}
|
||||
beforeMount={(monaco) => {
|
||||
if (!state.editorCtx) {
|
||||
state.editorCtx = ref(monaco.editor);
|
||||
// @ts-expect-error
|
||||
monaco.editor.defineTheme("dark", dark);
|
||||
// @ts-expect-error
|
||||
monaco.editor.defineTheme("light", light);
|
||||
}
|
||||
}}
|
||||
onMount={(editor, monaco) => {
|
||||
editorRef.current = editor;
|
||||
// hook editor to global state
|
||||
editor.updateOptions({
|
||||
minimap: {
|
||||
enabled: false,
|
||||
},
|
||||
...snap.editorSettings,
|
||||
});
|
||||
editor.addCommand(
|
||||
monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_S,
|
||||
() => {
|
||||
saveFile(editor.getValue());
|
||||
{snap.files.length > 0 && router.isReady ? (
|
||||
<Editor
|
||||
keepCurrentModel
|
||||
defaultLanguage={snap.files?.[snap.active]?.language}
|
||||
language={snap.files?.[snap.active]?.language}
|
||||
path={snap.files?.[snap.active]?.name}
|
||||
defaultValue={snap.files?.[snap.active]?.content}
|
||||
beforeMount={(monaco) => {
|
||||
if (!state.editorCtx) {
|
||||
state.editorCtx = ref(monaco.editor);
|
||||
// @ts-expect-error
|
||||
monaco.editor.defineTheme("dark", dark);
|
||||
// @ts-expect-error
|
||||
monaco.editor.defineTheme("light", light);
|
||||
}
|
||||
);
|
||||
}}
|
||||
theme={theme === "dark" ? "dark" : "light"}
|
||||
/>
|
||||
<Button
|
||||
variant="primary"
|
||||
uppercase
|
||||
onClick={() => compileCode(snap.active)}
|
||||
disabled={snap.compiling}
|
||||
css={{
|
||||
position: "absolute",
|
||||
bottom: "$4",
|
||||
left: "$4",
|
||||
alignItems: "center",
|
||||
display: "flex",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
>
|
||||
<Play weight="bold" size="16px" />
|
||||
Compile to Wasm
|
||||
{snap.compiling && <Spinner />}
|
||||
</Button>
|
||||
}}
|
||||
onMount={(editor, monaco) => {
|
||||
editorRef.current = editor;
|
||||
// hook editor to global state
|
||||
editor.updateOptions({
|
||||
minimap: {
|
||||
enabled: false,
|
||||
},
|
||||
...snap.editorSettings,
|
||||
});
|
||||
editor.addCommand(
|
||||
monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_S,
|
||||
() => {
|
||||
saveFile(editor.getValue());
|
||||
}
|
||||
);
|
||||
}}
|
||||
theme={theme === "dark" ? "dark" : "light"}
|
||||
/>
|
||||
) : (
|
||||
<Container>
|
||||
{!snap.loading && router.isReady && (
|
||||
<Box
|
||||
css={{
|
||||
flexDirection: "row",
|
||||
width: "$spaces$wide",
|
||||
gap: "$3",
|
||||
display: "inline-flex",
|
||||
}}
|
||||
>
|
||||
<Box css={{ display: "inline-flex", pl: "35px" }}>
|
||||
<ArrowBendLeftUp size={30} />
|
||||
</Box>
|
||||
<Box
|
||||
css={{ pl: "0px", pt: "15px", flex: 1, display: "inline-flex" }}
|
||||
>
|
||||
<Text
|
||||
css={{
|
||||
fontSize: "14px",
|
||||
maxWidth: "220px",
|
||||
fontFamily: "$monospace",
|
||||
}}
|
||||
>
|
||||
Click the link above to create a your file
|
||||
</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
</Container>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
147
components/Input.tsx
Normal file
147
components/Input.tsx
Normal file
@@ -0,0 +1,147 @@
|
||||
import { styled } from "../stitches.config";
|
||||
|
||||
export const Input = styled("input", {
|
||||
// Reset
|
||||
appearance: "none",
|
||||
borderWidth: "0",
|
||||
boxSizing: "border-box",
|
||||
fontFamily: "inherit",
|
||||
outline: "none",
|
||||
width: "100%",
|
||||
flex: "1",
|
||||
backgroundColor: "$mauve4",
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
borderRadius: "$sm",
|
||||
px: "$2",
|
||||
fontSize: "$md",
|
||||
lineHeight: 1,
|
||||
color: "$mauve12",
|
||||
boxShadow: `0 0 0 1px $colors$mauve8`,
|
||||
height: 35,
|
||||
WebkitTapHighlightColor: "rgba(0,0,0,0)",
|
||||
"&::before": {
|
||||
boxSizing: "border-box",
|
||||
},
|
||||
"&::after": {
|
||||
boxSizing: "border-box",
|
||||
},
|
||||
fontVariantNumeric: "tabular-nums",
|
||||
|
||||
"&:-webkit-autofill": {
|
||||
boxShadow: "inset 0 0 0 1px $colors$blue6, inset 0 0 0 100px $colors$blue3",
|
||||
},
|
||||
|
||||
"&:-webkit-autofill::first-line": {
|
||||
fontFamily: "$untitled",
|
||||
color: "$mauve12",
|
||||
},
|
||||
|
||||
"&:focus": {
|
||||
boxShadow: `0 0 0 1px $colors$mauve10`,
|
||||
"&:-webkit-autofill": {
|
||||
boxShadow: `0 0 0 1px $colors$mauve10`,
|
||||
},
|
||||
},
|
||||
"&::placeholder": {
|
||||
color: "$mauve9",
|
||||
},
|
||||
"&:disabled": {
|
||||
pointerEvents: "none",
|
||||
backgroundColor: "$mauve2",
|
||||
color: "$mauve8",
|
||||
cursor: "not-allowed",
|
||||
"&::placeholder": {
|
||||
color: "$mauve7",
|
||||
},
|
||||
},
|
||||
"&:read-only": {
|
||||
backgroundColor: "$mauve2",
|
||||
"&:focus": {
|
||||
boxShadow: "inset 0px 0px 0px 1px $colors$mauve7",
|
||||
},
|
||||
},
|
||||
|
||||
variants: {
|
||||
size: {
|
||||
sm: {
|
||||
height: "$5",
|
||||
fontSize: "$1",
|
||||
lineHeight: "$sizes$4",
|
||||
"&:-webkit-autofill::first-line": {
|
||||
fontSize: "$1",
|
||||
},
|
||||
},
|
||||
md: {
|
||||
height: "$8",
|
||||
fontSize: "$1",
|
||||
lineHeight: "$sizes$5",
|
||||
"&:-webkit-autofill::first-line": {
|
||||
fontSize: "$1",
|
||||
},
|
||||
},
|
||||
lg: {
|
||||
height: "$12",
|
||||
fontSize: "$2",
|
||||
lineHeight: "$sizes$6",
|
||||
"&:-webkit-autofill::first-line": {
|
||||
fontSize: "$3",
|
||||
},
|
||||
},
|
||||
},
|
||||
variant: {
|
||||
ghost: {
|
||||
boxShadow: "none",
|
||||
backgroundColor: "transparent",
|
||||
"@hover": {
|
||||
"&:hover": {
|
||||
boxShadow: "inset 0 0 0 1px $colors$mauve7",
|
||||
},
|
||||
},
|
||||
"&:focus": {
|
||||
backgroundColor: "$loContrast",
|
||||
boxShadow: `0 0 0 1px $colors$mauve10`,
|
||||
},
|
||||
"&:disabled": {
|
||||
backgroundColor: "transparent",
|
||||
},
|
||||
"&:read-only": {
|
||||
backgroundColor: "transparent",
|
||||
},
|
||||
},
|
||||
},
|
||||
state: {
|
||||
invalid: {
|
||||
boxShadow: "inset 0 0 0 1px $colors$red7",
|
||||
"&:focus": {
|
||||
boxShadow:
|
||||
"inset 0px 0px 0px 1px $colors$red8, 0px 0px 0px 1px $colors$red8",
|
||||
},
|
||||
},
|
||||
valid: {
|
||||
boxShadow: "inset 0 0 0 1px $colors$green7",
|
||||
"&:focus": {
|
||||
boxShadow:
|
||||
"inset 0px 0px 0px 1px $colors$green8, 0px 0px 0px 1px $colors$green8",
|
||||
},
|
||||
},
|
||||
},
|
||||
cursor: {
|
||||
default: {
|
||||
cursor: "default",
|
||||
"&:focus": {
|
||||
cursor: "text",
|
||||
},
|
||||
},
|
||||
text: {
|
||||
cursor: "text",
|
||||
},
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
size: "md",
|
||||
},
|
||||
});
|
||||
|
||||
export default Input;
|
||||
@@ -1,5 +1,3 @@
|
||||
import { useTheme } from "next-themes";
|
||||
|
||||
import { styled } from "../stitches.config";
|
||||
|
||||
const SVG = styled("svg", {
|
||||
|
||||
@@ -1,43 +1,45 @@
|
||||
import React from "react";
|
||||
import Link from "next/link";
|
||||
import {
|
||||
Gear,
|
||||
GithubLogo,
|
||||
SignOut,
|
||||
User,
|
||||
ArrowSquareOut,
|
||||
} from "phosphor-react";
|
||||
|
||||
import { useSnapshot } from "valtio";
|
||||
import Image from "next/image";
|
||||
import { useSession, signIn, signOut } from "next-auth/react";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuArrow,
|
||||
DropdownMenuSeparator,
|
||||
} from "./DropdownMenu";
|
||||
import { useRouter } from "next/router";
|
||||
import { FolderOpen, X, ArrowUpRight, BookOpen } from "phosphor-react";
|
||||
|
||||
import Stack from "./Stack";
|
||||
import Logo from "./Logo";
|
||||
import Button from "./Button";
|
||||
import Flex from "./Flex";
|
||||
import Container from "./Container";
|
||||
import Box from "./Box";
|
||||
import Flex from "./Flex";
|
||||
import ThemeChanger from "./ThemeChanger";
|
||||
import { useRouter } from "next/router";
|
||||
import { state } from "../state";
|
||||
import Heading from "./Heading";
|
||||
import Text from "./Text";
|
||||
import Spinner from "./Spinner";
|
||||
import truncate from "../utils/truncate";
|
||||
import ButtonGroup from "./ButtonGroup";
|
||||
import {
|
||||
Dialog,
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "./Dialog";
|
||||
import PanelBox from "./PanelBox";
|
||||
|
||||
const Navigation = () => {
|
||||
const { data: session, status } = useSession();
|
||||
const router = useRouter();
|
||||
const snap = useSnapshot(state);
|
||||
const slug = router.query?.slug;
|
||||
const gistId = Array.isArray(slug) ? slug[0] : null;
|
||||
|
||||
return (
|
||||
<Box
|
||||
as="nav"
|
||||
css={{
|
||||
display: "flex",
|
||||
height: "60px",
|
||||
borderBottom: "1px solid $slate6",
|
||||
borderBottom: "1px solid $mauve6",
|
||||
position: "relative",
|
||||
zIndex: 2003,
|
||||
}}
|
||||
@@ -46,112 +48,333 @@ const Navigation = () => {
|
||||
css={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
py: "$2",
|
||||
}}
|
||||
>
|
||||
<Link href="/" passHref>
|
||||
<Box
|
||||
as="a"
|
||||
css={{ display: "flex", alignItems: "center", color: "$textColor" }}
|
||||
>
|
||||
<Logo width="30px" height="30px" />
|
||||
</Box>
|
||||
</Link>
|
||||
<Stack css={{ ml: "$4", gap: "$3" }}>
|
||||
<Link href="/develop" passHref shallow>
|
||||
<Button
|
||||
<Flex
|
||||
css={{
|
||||
flex: 1,
|
||||
alignItems: "center",
|
||||
borderRight: "1px solid $colors$mauve6",
|
||||
py: "$3",
|
||||
pr: "$4",
|
||||
}}
|
||||
>
|
||||
<Link href="/" passHref>
|
||||
<Box
|
||||
as="a"
|
||||
outline={!router.pathname.includes("/develop")}
|
||||
uppercase
|
||||
>
|
||||
Develop
|
||||
</Button>
|
||||
</Link>
|
||||
<Link href="/deploy" passHref shallow>
|
||||
<Button
|
||||
as="a"
|
||||
outline={!router.pathname.includes("/deploy")}
|
||||
uppercase
|
||||
>
|
||||
Deploy
|
||||
</Button>
|
||||
</Link>
|
||||
<Link href="/test" passHref shallow>
|
||||
<Button
|
||||
as="a"
|
||||
outline={!router.pathname.includes("/test")}
|
||||
uppercase
|
||||
>
|
||||
Test
|
||||
</Button>
|
||||
</Link>
|
||||
</Stack>
|
||||
<Stack css={{ color: "text", ml: "auto" }}>
|
||||
<ThemeChanger />
|
||||
{status === "authenticated" && (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Box
|
||||
css={{
|
||||
borderRadius: "$full",
|
||||
overflow: "hidden",
|
||||
width: "30px",
|
||||
height: "30px",
|
||||
position: "relative",
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
src={session?.user?.image || ""}
|
||||
width="30px"
|
||||
height="30px"
|
||||
objectFit="cover"
|
||||
alt="User avatar"
|
||||
/>
|
||||
</Box>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem disabled onClick={() => signOut()}>
|
||||
<User size="16px" /> {session?.user?.username} (
|
||||
{session?.user.name})
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
onClick={() =>
|
||||
window.open(
|
||||
`http://gist.github.com/${session?.user.username}`
|
||||
)
|
||||
}
|
||||
>
|
||||
<ArrowSquareOut size="16px" />
|
||||
Go to your Gist
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>
|
||||
<Gear size="16px" /> Settings
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => signOut()}>
|
||||
<SignOut size="16px" /> Log out
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuArrow offset={10} />
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
)}
|
||||
{status === "unauthenticated" && (
|
||||
<Button outline onClick={() => signIn("github")}>
|
||||
<GithubLogo size="16px" /> Github Login
|
||||
</Button>
|
||||
)}
|
||||
{status === "loading" && "loading"}
|
||||
{/* <Box
|
||||
css={{
|
||||
border: "1px solid",
|
||||
borderRadius: "3px",
|
||||
borderColor: "text",
|
||||
p: 1,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
color: "$textColor",
|
||||
}}
|
||||
>
|
||||
<BookOpen size="20px" />
|
||||
</Box> */}
|
||||
</Stack>
|
||||
<Logo width="30px" height="30px" />
|
||||
</Box>
|
||||
</Link>
|
||||
<Flex
|
||||
css={{
|
||||
ml: "$5",
|
||||
flexDirection: "column",
|
||||
gap: "1px",
|
||||
}}
|
||||
>
|
||||
{snap.loading ? (
|
||||
<Spinner />
|
||||
) : (
|
||||
<>
|
||||
<Heading css={{ lineHeight: 1 }}>
|
||||
{snap.files?.[0]?.name || "XRPL Hooks"}
|
||||
</Heading>
|
||||
<Text
|
||||
css={{ fontSize: "$xs", color: "$mauve10", lineHeight: 1 }}
|
||||
>
|
||||
{snap.files.length > 0 ? "Gist: " : "Playground"}
|
||||
<Text css={{ color: "$mauve12" }}>
|
||||
{snap.files.length > 0 &&
|
||||
`${snap.gistOwner || "-"}/${truncate(snap.gistId || "")}`}
|
||||
</Text>
|
||||
</Text>
|
||||
</>
|
||||
)}
|
||||
</Flex>
|
||||
<ButtonGroup css={{ marginLeft: "auto" }}>
|
||||
<Dialog
|
||||
open={snap.mainModalOpen}
|
||||
onOpenChange={(open) => (state.mainModalOpen = open)}
|
||||
>
|
||||
<DialogTrigger asChild>
|
||||
<Button outline>
|
||||
<FolderOpen size="15px" />
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent
|
||||
css={{
|
||||
maxWidth: "100%",
|
||||
width: "80vw",
|
||||
height: "80%",
|
||||
backgroundColor: "$mauve1 !important",
|
||||
overflowY: "auto",
|
||||
p: 0,
|
||||
}}
|
||||
>
|
||||
<Flex
|
||||
css={{
|
||||
flexDirection: "column",
|
||||
flex: 1,
|
||||
height: "auto",
|
||||
"@md": {
|
||||
flexDirection: "row",
|
||||
height: "100%",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Flex
|
||||
css={{
|
||||
borderBottom: "1px solid $colors$mauve5",
|
||||
width: "100%",
|
||||
flexDirection: "column",
|
||||
p: "$7",
|
||||
height: "100%",
|
||||
"@md": {
|
||||
width: "30%",
|
||||
borderBottom: "0px",
|
||||
borderRight: "1px solid $colors$mauve5",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<DialogTitle
|
||||
css={{
|
||||
textTransform: "uppercase",
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
gap: "$3",
|
||||
fontSize: "$xl",
|
||||
}}
|
||||
>
|
||||
<Logo width="30px" height="30px" /> XRPL Hooks Editor
|
||||
</DialogTitle>
|
||||
<DialogDescription as="div">
|
||||
<Text
|
||||
css={{
|
||||
display: "inline-flex",
|
||||
color: "inherit",
|
||||
my: "$5",
|
||||
mb: "$7",
|
||||
}}
|
||||
>
|
||||
Hooks add smart contract functionality to the XRP
|
||||
Ledger.
|
||||
</Text>
|
||||
<Flex
|
||||
css={{ flexDirection: "column", gap: "$2", mt: "$2" }}
|
||||
>
|
||||
<Text
|
||||
css={{
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
gap: "$3",
|
||||
color: "$green9",
|
||||
"&:hover": {
|
||||
color: "$green11 !important",
|
||||
},
|
||||
"&:focus": {
|
||||
outline: 0,
|
||||
},
|
||||
}}
|
||||
as="a"
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
href="https://github.com/XRPL-Labs/xrpld-hooks"
|
||||
>
|
||||
<ArrowUpRight size="15px" /> Developing Hooks
|
||||
</Text>
|
||||
|
||||
<Text
|
||||
css={{
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
gap: "$3",
|
||||
color: "$green9",
|
||||
"&:hover": {
|
||||
color: "$green11 !important",
|
||||
},
|
||||
"&:focus": {
|
||||
outline: 0,
|
||||
},
|
||||
}}
|
||||
as="a"
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
href="https://xrpl-hooks.readme.io/docs"
|
||||
>
|
||||
<ArrowUpRight size="15px" /> Hooks documentation
|
||||
</Text>
|
||||
<Text
|
||||
css={{
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
gap: "$3",
|
||||
color: "$green9",
|
||||
"&:hover": {
|
||||
color: "$green11 !important",
|
||||
},
|
||||
"&:focus": {
|
||||
outline: 0,
|
||||
},
|
||||
}}
|
||||
as="a"
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
href="https://xrpl.org/docs.html"
|
||||
>
|
||||
<ArrowUpRight size="15px" /> XRPL documentation
|
||||
</Text>
|
||||
</Flex>
|
||||
</DialogDescription>
|
||||
</Flex>
|
||||
|
||||
<Flex
|
||||
css={{
|
||||
display: "grid",
|
||||
gridTemplateColumns: "1fr",
|
||||
gridTemplateRows: "max-content",
|
||||
flex: 1,
|
||||
p: "$7",
|
||||
gap: "$3",
|
||||
alignItems: "flex-start",
|
||||
flexWrap: "wrap",
|
||||
backgroundImage: `url('/pattern.svg'), url('/pattern-2.svg')`,
|
||||
backgroundRepeat: "no-repeat",
|
||||
backgroundPosition: "bottom left, top right",
|
||||
"@md": {
|
||||
gridTemplateColumns: "1fr 1fr 1fr",
|
||||
gridTemplateRows: "max-content",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<PanelBox
|
||||
as="a"
|
||||
href="/develop/be088224fb37c0075e84491da0e602c1"
|
||||
>
|
||||
<Heading>Starter</Heading>
|
||||
<Text>Just an empty starter with essential imports</Text>
|
||||
</PanelBox>
|
||||
<PanelBox
|
||||
as="a"
|
||||
href="/develop/be088224fb37c0075e84491da0e602c1"
|
||||
>
|
||||
<Heading>Firewall</Heading>
|
||||
<Text>
|
||||
This Hook essentially checks a blacklist of accounts
|
||||
</Text>
|
||||
</PanelBox>
|
||||
<PanelBox
|
||||
as="a"
|
||||
href="/develop/be088224fb37c0075e84491da0e602c1"
|
||||
>
|
||||
<Heading>Accept</Heading>
|
||||
<Text>
|
||||
This hook just accepts any transaction coming through it
|
||||
</Text>
|
||||
</PanelBox>
|
||||
<PanelBox
|
||||
as="a"
|
||||
href="/develop/be088224fb37c0075e84491da0e602c1"
|
||||
>
|
||||
<Heading>Accept</Heading>
|
||||
<Text>
|
||||
This hook just accepts any transaction coming through it
|
||||
</Text>
|
||||
</PanelBox>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<DialogClose asChild>
|
||||
<Box
|
||||
css={{
|
||||
position: "absolute",
|
||||
top: "$1",
|
||||
right: "$1",
|
||||
cursor: "pointer",
|
||||
background: "$mauve1",
|
||||
display: "flex",
|
||||
borderRadius: "$full",
|
||||
p: "$1",
|
||||
}}
|
||||
>
|
||||
<X size="20px" />
|
||||
</Box>
|
||||
</DialogClose>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
<ThemeChanger />
|
||||
</ButtonGroup>
|
||||
</Flex>
|
||||
<Flex
|
||||
css={{
|
||||
flexWrap: "nowrap",
|
||||
marginLeft: "$4",
|
||||
overflowX: "scroll",
|
||||
"&::-webkit-scrollbar": {
|
||||
height: 0,
|
||||
background: "transparent",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Stack
|
||||
css={{
|
||||
ml: "$4",
|
||||
gap: "$3",
|
||||
flexWrap: "nowrap",
|
||||
alignItems: "center",
|
||||
marginLeft: "auto",
|
||||
}}
|
||||
>
|
||||
<ButtonGroup>
|
||||
<Link
|
||||
href={gistId ? `/develop/${gistId}` : "/develop"}
|
||||
passHref
|
||||
shallow
|
||||
>
|
||||
<Button
|
||||
as="a"
|
||||
outline={!router.pathname.includes("/develop")}
|
||||
uppercase
|
||||
>
|
||||
Develop
|
||||
</Button>
|
||||
</Link>
|
||||
<Link
|
||||
href={gistId ? `/deploy/${gistId}` : "/deploy"}
|
||||
passHref
|
||||
shallow
|
||||
>
|
||||
<Button
|
||||
as="a"
|
||||
outline={!router.pathname.includes("/deploy")}
|
||||
uppercase
|
||||
>
|
||||
Deploy
|
||||
</Button>
|
||||
</Link>
|
||||
<Link
|
||||
href={gistId ? `/test/${gistId}` : "/test"}
|
||||
passHref
|
||||
shallow
|
||||
>
|
||||
<Button
|
||||
as="a"
|
||||
outline={!router.pathname.includes("/test")}
|
||||
uppercase
|
||||
>
|
||||
Test
|
||||
</Button>
|
||||
</Link>
|
||||
</ButtonGroup>
|
||||
<Button outline disabled>
|
||||
<BookOpen size="15px" />
|
||||
</Button>
|
||||
</Stack>
|
||||
</Flex>
|
||||
</Container>
|
||||
</Box>
|
||||
);
|
||||
|
||||
30
components/PanelBox.tsx
Normal file
30
components/PanelBox.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
import { styled } from "../stitches.config";
|
||||
import Heading from "./Heading";
|
||||
import Text from "./Text";
|
||||
|
||||
const PanelBox = styled("div", {
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
border: "1px solid $colors$mauve5",
|
||||
backgroundColor: "$mauve1",
|
||||
padding: "$3",
|
||||
borderRadius: "$sm",
|
||||
fontWeight: "lighter",
|
||||
height: "auto",
|
||||
cursor: "pointer",
|
||||
flex: "1 1 0px",
|
||||
"&:hover": {
|
||||
border: "1px solid $colors$mauve9",
|
||||
},
|
||||
[`& ${Heading}`]: {
|
||||
fontWeight: "lighter",
|
||||
mb: "$2",
|
||||
},
|
||||
[`& ${Text}`]: {
|
||||
fontWeight: "lighter",
|
||||
color: "$mauve10",
|
||||
fontSize: "$sm",
|
||||
},
|
||||
});
|
||||
|
||||
export default PanelBox;
|
||||
@@ -3,11 +3,12 @@ import { styled, keyframes } from "../stitches.config";
|
||||
|
||||
const rotate = keyframes({
|
||||
"0%": { transform: "rotate(0deg)" },
|
||||
"100%": { transform: "rotate(360deg)" },
|
||||
"100%": { transform: "rotate(-360deg)" },
|
||||
});
|
||||
|
||||
const Spinner = styled(SpinnerIcon, {
|
||||
animation: `${rotate} 150ms cubic-bezier(0.16, 1, 0.3, 1) infinite`,
|
||||
animation: `${rotate} 150ms linear infinite`,
|
||||
fontSize: "16px",
|
||||
});
|
||||
|
||||
export default Spinner;
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import { Children } from "react";
|
||||
|
||||
import Box from "./Box";
|
||||
import { styled } from "../stitches.config";
|
||||
import type * as Stitches from "@stitches/react";
|
||||
|
||||
const StackComponent = styled(Box, {
|
||||
display: "flex",
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useState, useEffect } from "react";
|
||||
import { useTheme } from "next-themes";
|
||||
import { Sun, Moon } from "phosphor-react";
|
||||
|
||||
import Box from "./Box";
|
||||
import Button from "./Button";
|
||||
|
||||
const ThemeChanger = () => {
|
||||
const { theme, setTheme } = useTheme();
|
||||
@@ -12,7 +12,8 @@ const ThemeChanger = () => {
|
||||
if (!mounted) return null;
|
||||
|
||||
return (
|
||||
<Box
|
||||
<Button
|
||||
outline
|
||||
onClick={() => {
|
||||
setTheme(theme && theme === "light" ? "dark" : "light");
|
||||
}}
|
||||
@@ -25,12 +26,8 @@ const ThemeChanger = () => {
|
||||
color: "$muted",
|
||||
}}
|
||||
>
|
||||
{theme === "dark" ? (
|
||||
<Sun weight="bold" size="16px" />
|
||||
) : (
|
||||
<Moon weight="bold" size="16px" />
|
||||
)}
|
||||
</Box>
|
||||
{theme === "dark" ? <Sun size="15px" /> : <Moon size="15px" />}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -9,24 +9,25 @@
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@mattjennings/react-modal": "^1.0.3",
|
||||
"@monaco-editor/react": "^4.3.1",
|
||||
"@octokit/core": "^3.5.1",
|
||||
"@radix-ui/colors": "^0.1.7",
|
||||
"@radix-ui/react-alert-dialog": "^0.1.1",
|
||||
"@radix-ui/react-dialog": "^0.1.1",
|
||||
"@radix-ui/react-dropdown-menu": "^0.1.1",
|
||||
"@stitches/react": "^1.2.5",
|
||||
"@theme-ui/color": "^0.11.3",
|
||||
"@theme-ui/match-media": "^0.11.3",
|
||||
"@radix-ui/react-id": "^0.1.1",
|
||||
"@stitches/react": "^1.2.6-0",
|
||||
"monaco-editor": "^0.29.1",
|
||||
"next": "^12.0.4",
|
||||
"next-auth": "^4.0.0-beta.5",
|
||||
"next-themes": "^0.0.15",
|
||||
"octokit": "^1.7.0",
|
||||
"phosphor-react": "^1.3.1",
|
||||
"re-resizable": "^6.9.1",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"react-hot-toast": "^2.1.1",
|
||||
"react-new-window": "^0.2.1",
|
||||
"valtio": "^1.2.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,30 +1,67 @@
|
||||
import { useEffect } from "react";
|
||||
import "../styles/globals.css";
|
||||
import type { AppProps } from "next/app";
|
||||
import Head from "next/head";
|
||||
import { SessionProvider } from "next-auth/react";
|
||||
import { ThemeProvider } from "next-themes";
|
||||
import { Toaster } from "react-hot-toast";
|
||||
import { useRouter } from "next/router";
|
||||
import { IdProvider } from "@radix-ui/react-id";
|
||||
|
||||
import { darkTheme } from "../stitches.config";
|
||||
import { darkTheme, css } from "../stitches.config";
|
||||
import Navigation from "../components/Navigation";
|
||||
import { fetchFiles, state } from "../state";
|
||||
|
||||
function MyApp({ Component, pageProps: { session, ...pageProps } }: AppProps) {
|
||||
const router = useRouter();
|
||||
const slug = router.query?.slug;
|
||||
const gistId = (Array.isArray(slug) && slug[0]) ?? null;
|
||||
useEffect(() => {
|
||||
if (router.pathname.includes("/develop")) {
|
||||
if (gistId && router.isReady) {
|
||||
fetchFiles(gistId);
|
||||
} else {
|
||||
if (!gistId && router.isReady) {
|
||||
state.mainModalOpen = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [gistId, router.isReady, router.pathname]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SessionProvider session={session}>
|
||||
<ThemeProvider
|
||||
attribute="class"
|
||||
defaultTheme="dark"
|
||||
enableSystem={false}
|
||||
value={{
|
||||
light: "light",
|
||||
dark: darkTheme.className,
|
||||
}}
|
||||
>
|
||||
<Navigation />
|
||||
<Component {...pageProps} />
|
||||
<Toaster />
|
||||
</ThemeProvider>
|
||||
</SessionProvider>
|
||||
<Head>
|
||||
<title>XRPL Hooks Playground</title>
|
||||
</Head>
|
||||
<IdProvider>
|
||||
<SessionProvider session={session}>
|
||||
<ThemeProvider
|
||||
attribute="class"
|
||||
defaultTheme="dark"
|
||||
enableSystem={false}
|
||||
value={{
|
||||
light: "light",
|
||||
dark: darkTheme.className,
|
||||
}}
|
||||
>
|
||||
<Navigation />
|
||||
<Component {...pageProps} />
|
||||
<Toaster
|
||||
toastOptions={{
|
||||
className: css({
|
||||
backgroundColor: "$mauve1",
|
||||
color: "$mauve10",
|
||||
fontSize: "$sm",
|
||||
".dark &": {
|
||||
backgroundColor: "$mauve4",
|
||||
color: "$mauve12",
|
||||
},
|
||||
})(),
|
||||
}}
|
||||
/>
|
||||
</ThemeProvider>
|
||||
</SessionProvider>
|
||||
</IdProvider>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import type { NextRequest, NextFetchEvent } from 'next/server';
|
||||
import { NextResponse as Response } from 'next/server';
|
||||
import { getToken } from "next-auth/jwt"
|
||||
|
||||
export default function middleware(req: NextRequest, ev: NextFetchEvent) {
|
||||
|
||||
if (req.nextUrl.pathname === "/") {
|
||||
console.log('kissa', ev);
|
||||
return Response.redirect("/develop");
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import NextAuth from "next-auth"
|
||||
import GithubProvider from "next-auth/providers/github"
|
||||
|
||||
export default NextAuth({
|
||||
// Configure one or more authentication providers
|
||||
@@ -42,7 +41,6 @@ export default NextAuth({
|
||||
},
|
||||
async session({ session, token }) {
|
||||
session.accessToken = token.accessToken as string;
|
||||
const user = { ...session.user, username: token.username };
|
||||
session['user']['username'] = token.username as string;
|
||||
return session
|
||||
}
|
||||
|
||||
9
pages/deploy/[[...slug]].tsx
Normal file
9
pages/deploy/[[...slug]].tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import Container from "../../components/Container";
|
||||
|
||||
const Deploy = () => {
|
||||
return (
|
||||
<Container css={{ py: "$10" }}>This will be the deploy page</Container>
|
||||
);
|
||||
};
|
||||
|
||||
export default Deploy;
|
||||
@@ -1,12 +0,0 @@
|
||||
import { useSnapshot } from "valtio";
|
||||
import Container from "../../components/Container";
|
||||
import { state } from "../../state";
|
||||
|
||||
const Deploy = () => {
|
||||
const snap = useSnapshot(state);
|
||||
return (
|
||||
<Container>This will be the deploy page {JSON.stringify(snap)}</Container>
|
||||
);
|
||||
};
|
||||
|
||||
export default Deploy;
|
||||
24
pages/develop/[[...slug]].tsx
Normal file
24
pages/develop/[[...slug]].tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import dynamic from "next/dynamic";
|
||||
|
||||
import type { NextPage } from "next";
|
||||
|
||||
const HooksEditor = dynamic(() => import("../../components/HooksEditor"), {
|
||||
ssr: false,
|
||||
});
|
||||
|
||||
const Footer = dynamic(() => import("../../components/Footer"), {
|
||||
ssr: false,
|
||||
});
|
||||
|
||||
const Home: NextPage = () => {
|
||||
return (
|
||||
<>
|
||||
<main style={{ display: "flex", flex: 1 }}>
|
||||
<HooksEditor />
|
||||
</main>
|
||||
<Footer />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Home;
|
||||
@@ -1,39 +0,0 @@
|
||||
import type { NextPage } from "next";
|
||||
import Head from "next/head";
|
||||
import dynamic from "next/dynamic";
|
||||
|
||||
import Footer from "../../components/Footer";
|
||||
|
||||
const HooksEditor = dynamic(() => import("../../components/HooksEditor"), {
|
||||
ssr: false,
|
||||
});
|
||||
|
||||
const Home: NextPage = () => {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>XRPL Hooks Playground</title>
|
||||
</Head>
|
||||
<main style={{ display: "flex", flex: 1 }}>
|
||||
<HooksEditor />
|
||||
</main>
|
||||
|
||||
<Footer />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Home;
|
||||
|
||||
// export const getStaticPaths: GetStaticPaths = async () => {
|
||||
// // ...
|
||||
// return { paths: [], fallback: "blocking" };
|
||||
// };
|
||||
|
||||
// export const getStaticProps: GetStaticProps = async (context) => {
|
||||
// // ...
|
||||
// return {
|
||||
// props: {},
|
||||
// revalidate: 60,
|
||||
// };
|
||||
// };
|
||||
5
pages/index.tsx
Normal file
5
pages/index.tsx
Normal file
@@ -0,0 +1,5 @@
|
||||
const Home = () => {
|
||||
return <p>homepage</p>;
|
||||
};
|
||||
|
||||
export default Home;
|
||||
38
pages/sign-in.tsx
Normal file
38
pages/sign-in.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
import { useEffect } from "react";
|
||||
import { signIn, useSession } from "next-auth/react";
|
||||
|
||||
import Box from "../components/Box";
|
||||
import Spinner from "../components/Spinner";
|
||||
|
||||
const SignInPage = () => {
|
||||
const { data: session, status } = useSession();
|
||||
|
||||
useEffect(() => {
|
||||
if (status !== "loading" && !session)
|
||||
void signIn("github", { redirect: false });
|
||||
if (status !== "loading" && session) window.close();
|
||||
}, [session, status]);
|
||||
|
||||
return (
|
||||
<Box
|
||||
css={{
|
||||
display: "flex",
|
||||
backgroundColor: "$mauve1",
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
zIndex: 9999,
|
||||
textAlign: "center",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
gap: "$2",
|
||||
}}
|
||||
>
|
||||
Logging in <Spinner />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default SignInPage;
|
||||
@@ -1,7 +1,7 @@
|
||||
import Container from "../../components/Container";
|
||||
|
||||
const Test = () => {
|
||||
return <Container>This will be the test page</Container>;
|
||||
return <Container css={{ py: "$10" }}>This will be the test page</Container>;
|
||||
};
|
||||
|
||||
export default Test;
|
||||
9
public/pattern-2.svg
Normal file
9
public/pattern-2.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 138 KiB |
9
public/pattern.svg
Normal file
9
public/pattern.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 134 KiB |
166
state.ts
166
state.ts
@@ -1,21 +1,27 @@
|
||||
import { proxy, subscribe } from 'valtio';
|
||||
import { proxy } from 'valtio';
|
||||
import { devtools } from 'valtio/utils';
|
||||
import { Octokit } from '@octokit/core';
|
||||
import type monaco from 'monaco-editor';
|
||||
import toast from 'react-hot-toast';
|
||||
import Router from 'next/router';
|
||||
import type { Session } from 'next-auth';
|
||||
|
||||
const octokit = new Octokit();
|
||||
|
||||
interface File {
|
||||
name: string,
|
||||
language: string,
|
||||
content: string
|
||||
name: string;
|
||||
language: string;
|
||||
content: string;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
files: File[],
|
||||
gistId?: string | null,
|
||||
gistOwner?: string | null,
|
||||
gistName?: string | null,
|
||||
active: number;
|
||||
loading: boolean;
|
||||
gistLoading: boolean;
|
||||
compiling: boolean;
|
||||
logs: {
|
||||
type: 'error' | 'warning' | 'log',
|
||||
@@ -24,10 +30,11 @@ interface IState {
|
||||
editorCtx?: typeof monaco.editor;
|
||||
editorSettings: {
|
||||
tabSize: number;
|
||||
}
|
||||
},
|
||||
mainModalOpen: boolean;
|
||||
}
|
||||
|
||||
let localStorageState: null | string = null;
|
||||
// let localStorageState: null | string = null;
|
||||
let initialState = {
|
||||
files: [],
|
||||
active: 0,
|
||||
@@ -35,30 +42,38 @@ let initialState = {
|
||||
compiling: false,
|
||||
logs: [],
|
||||
editorCtx: undefined,
|
||||
gistId: undefined,
|
||||
gistOwner: undefined,
|
||||
gistName: undefined,
|
||||
gistLoading: false,
|
||||
editorSettings: {
|
||||
tabSize: 2
|
||||
}
|
||||
},
|
||||
mainModalOpen: false
|
||||
}
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
try {
|
||||
localStorageState = localStorage.getItem('hooksIdeState');
|
||||
} catch (err) {
|
||||
console.log(`localStorage state broken`);
|
||||
localStorage.removeItem('hooksIdeState');
|
||||
}
|
||||
}
|
||||
if (localStorageState) {
|
||||
initialState = JSON.parse(localStorageState);
|
||||
}
|
||||
// Check if there's a persited state in localStorage
|
||||
// if (typeof window !== 'undefined') {
|
||||
// try {
|
||||
// localStorageState = localStorage.getItem('hooksIdeState');
|
||||
// } catch (err) {
|
||||
// console.log(`localStorage state broken`);
|
||||
// localStorage.removeItem('hooksIdeState');
|
||||
// }
|
||||
// }
|
||||
// if (localStorageState) {
|
||||
// initialState = JSON.parse(localStorageState);
|
||||
// }
|
||||
|
||||
// Initialize state
|
||||
export const state = proxy<IState>(initialState);
|
||||
export const state = proxy<IState>({ ...initialState, logs: [] });
|
||||
|
||||
// Fetch content from Githug Gists
|
||||
export const fetchFiles = (gistId: string) => {
|
||||
state.loading = true;
|
||||
if (gistId) {
|
||||
state.logs.push({ type: 'log', message: `Fetching Gist with id: ${gistId}` });
|
||||
|
||||
octokit.request("GET /gists/{gist_id}", { gist_id: gistId }).then(res => {
|
||||
if (res.data.files && Object.keys(res.data.files).length > 0) {
|
||||
const files = Object.keys(res.data.files).map(filename => ({
|
||||
@@ -70,11 +85,17 @@ export const fetchFiles = (gistId: string) => {
|
||||
if (files.length > 0) {
|
||||
state.logs.push({ type: 'log', message: 'Fetched successfully ✅' })
|
||||
state.files = files;
|
||||
state.gistId = gistId;
|
||||
state.gistName = Object.keys(res.data.files)?.[0] || 'untitled';
|
||||
state.gistOwner = res.data.owner?.login;
|
||||
return
|
||||
} else {
|
||||
// Open main modal if now files
|
||||
state.mainModalOpen = true;
|
||||
}
|
||||
return
|
||||
return Router.push({ pathname: '/develop' })
|
||||
}
|
||||
|
||||
state.loading = false;
|
||||
}).catch(err => {
|
||||
state.loading = false;
|
||||
state.logs.push({ type: 'error', message: `Couldn't find Gist with id: ${gistId}` })
|
||||
@@ -86,9 +107,72 @@ export const fetchFiles = (gistId: string) => {
|
||||
// return state.files = initFiles
|
||||
}
|
||||
|
||||
export const syncToGist = async (session?: Session | null, createNewGist?: boolean) => {
|
||||
let files: Record<string, { filename: string, content: string }> = {};
|
||||
state.gistLoading = true;
|
||||
|
||||
if (!session || !session.user) {
|
||||
state.gistLoading = false;
|
||||
return toast.error('You need to be logged in!')
|
||||
}
|
||||
const toastId = toast.loading('Pushing to Gist');
|
||||
if (!state.files || !state.files.length) {
|
||||
state.gistLoading = false;
|
||||
return toast.error(`You need to create some files we can push to gist`, { id: toastId })
|
||||
}
|
||||
if (state.gistId && session?.user.username === state.gistOwner && !createNewGist) {
|
||||
const currentFilesRes = await octokit.request("GET /gists/{gist_id}", { gist_id: state.gistId });
|
||||
if (currentFilesRes.data.files) {
|
||||
Object.keys(currentFilesRes?.data?.files).forEach(filename => {
|
||||
files[`${filename}`] = { filename, content: "" }
|
||||
})
|
||||
}
|
||||
state.files.forEach(file => {
|
||||
files[`${file.name}`] = { filename: file.name, content: file.content }
|
||||
})
|
||||
// Update existing Gist
|
||||
octokit.request("PATCH /gists/{gist_id}", {
|
||||
gist_id: state.gistId, files, headers: {
|
||||
authorization: `token ${session?.accessToken || ''}`
|
||||
}
|
||||
}).then(res => {
|
||||
state.gistLoading = false;
|
||||
return toast.success('Updated to gist successfully!', { id: toastId })
|
||||
}).catch(err => {
|
||||
console.log(err);
|
||||
state.gistLoading = false;
|
||||
return toast.error(`Could not update Gist, try again later!`, { id: toastId })
|
||||
})
|
||||
} else {
|
||||
// Not Gist of the current user or it isn't Gist yet
|
||||
state.files.forEach(file => {
|
||||
files[`${file.name}`] = { filename: file.name, content: file.content }
|
||||
})
|
||||
octokit.request("POST /gists", {
|
||||
files,
|
||||
public: true,
|
||||
headers: {
|
||||
authorization: `token ${session?.accessToken || ''}`
|
||||
}
|
||||
}).then(res => {
|
||||
state.gistLoading = false;
|
||||
state.gistOwner = res.data.owner?.login;
|
||||
state.gistId = res.data.id;
|
||||
state.gistName = Array.isArray(res.data.files) ? Object.keys(res.data?.files)?.[0] : 'Untitled';
|
||||
Router.push({ pathname: `/develop/${res.data.id}` })
|
||||
return toast.success('Created new gist successfully!', { id: toastId })
|
||||
}).catch(err => {
|
||||
console.log(err);
|
||||
state.gistLoading = false;
|
||||
return toast.error(`Could not create Gist, try again later!`, { id: toastId })
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const updateEditorSettings = (editorSettings: IState['editorSettings']) => {
|
||||
state.editorCtx?.getModels().forEach(model => {
|
||||
console.log(model.uri)
|
||||
model.updateOptions({
|
||||
...editorSettings
|
||||
})
|
||||
@@ -97,11 +181,17 @@ export const updateEditorSettings = (editorSettings: IState['editorSettings']) =
|
||||
}
|
||||
|
||||
export const saveFile = (value: string) => {
|
||||
const editorModels = state.editorCtx?.getModels();
|
||||
const currentModel = editorModels?.find(editorModel => editorModel.uri.path === `/${state.files[state.active].name}`);
|
||||
if (state.files.length > 0) {
|
||||
state.files[state.active].content = currentModel?.getValue() || '';
|
||||
}
|
||||
toast.success('Saved successfully', { position: 'bottom-center' })
|
||||
}
|
||||
|
||||
export const createNewFile = (name: string) => {
|
||||
state.files.push({ name, language: 'c', content: "" })
|
||||
const emptyFile: File = { name, language: 'c', content: "" };
|
||||
state.files.push(emptyFile)
|
||||
state.active = state.files.length - 1;
|
||||
}
|
||||
|
||||
@@ -134,17 +224,31 @@ export const compileCode = async (activeId: number) => {
|
||||
});
|
||||
const json = await res.json();
|
||||
state.compiling = false;
|
||||
toast.success('Compiled successfully!');
|
||||
console.log(json)
|
||||
} catch {
|
||||
if (!json.success) {
|
||||
state.logs.push({ type: 'error', message: json.message })
|
||||
if (json.tasks && json.tasks.length > 0) {
|
||||
json.tasks.forEach((task: any) => {
|
||||
if (!task.success) {
|
||||
state.logs.push({ type: 'error', message: task?.console })
|
||||
}
|
||||
})
|
||||
}
|
||||
return toast.error(`Couldn't compile!`, { position: 'bottom-center' });
|
||||
}
|
||||
state.logs.push({ type: 'log', message: 'Compiled successfully ✅' })
|
||||
toast.success('Compiled successfully!', { position: 'bottom-center' });
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
state.logs.push({ type: 'error', message: 'Error occured while compiling!' })
|
||||
state.compiling = false;
|
||||
}
|
||||
}
|
||||
|
||||
const unsub = devtools(state, 'Files State');
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
devtools(state, 'Files State');
|
||||
}
|
||||
|
||||
subscribe(state, () => {
|
||||
const { editorCtx, ...storedState } = state;
|
||||
localStorage.setItem('hooksIdeState', JSON.stringify(storedState))
|
||||
});
|
||||
// subscribe(state, () => {
|
||||
// const { editorCtx, ...storedState } = state;
|
||||
// localStorage.setItem('hooksIdeState', JSON.stringify(storedState))
|
||||
// });
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
green,
|
||||
plum,
|
||||
slate,
|
||||
mauve,
|
||||
pink,
|
||||
yellow,
|
||||
grayDark,
|
||||
@@ -16,8 +17,9 @@ import {
|
||||
greenDark,
|
||||
plumDark,
|
||||
slateDark,
|
||||
mauveDark,
|
||||
pinkDark,
|
||||
yellowDark
|
||||
yellowDark,
|
||||
} from '@radix-ui/colors';
|
||||
|
||||
export const {
|
||||
@@ -38,6 +40,7 @@ export const {
|
||||
...green,
|
||||
...plum,
|
||||
...slate,
|
||||
...mauve,
|
||||
...pink,
|
||||
...yellow,
|
||||
background: "$gray1",
|
||||
@@ -188,7 +191,7 @@ export const {
|
||||
},
|
||||
fontWeights: {
|
||||
body: 400,
|
||||
heading: 400,
|
||||
heading: 700,
|
||||
bold: 700,
|
||||
},
|
||||
lineHeights: {
|
||||
@@ -293,6 +296,7 @@ export const darkTheme = createTheme('dark', {
|
||||
...greenDark,
|
||||
...plumDark,
|
||||
...slateDark,
|
||||
...mauveDark,
|
||||
...pinkDark,
|
||||
...yellowDark
|
||||
},
|
||||
@@ -300,5 +304,12 @@ export const darkTheme = createTheme('dark', {
|
||||
|
||||
export const globalStyles = globalCss({
|
||||
// body: { backgroundColor: '$background', color: '$text', fontFamily: 'Helvetica' },
|
||||
'html, body': { backgroundColor: '$gray1', color: '$gray12', fontFamily: '$body', fontSize: '$md' },
|
||||
'html, body': {
|
||||
backgroundColor: '$gray1',
|
||||
color: '$gray12',
|
||||
fontFamily: '$body',
|
||||
fontSize: '$md',
|
||||
'-webkit-font-smoothing': 'antialiased',
|
||||
'-moz-osx-font-smoothing': 'grayscale'
|
||||
},
|
||||
});
|
||||
|
||||
@@ -182,7 +182,7 @@
|
||||
],
|
||||
"colors": {
|
||||
"editor.foreground": "#D0D0FF",
|
||||
"editor.background": "#202425",
|
||||
"editor.background": "#232326",
|
||||
"editor.selectionBackground": "#ffffff30",
|
||||
"editor.lineHighlightBackground": "#ffffff20",
|
||||
"editorCursor.foreground": "#7070FF",
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
],
|
||||
"colors": {
|
||||
"editor.foreground": "#000000",
|
||||
"editor.background": "#f1f3f5",
|
||||
"editor.background": "#f4f2f4",
|
||||
"editor.selectionBackground": "#B5D5FF",
|
||||
"editor.lineHighlightBackground": "#00000012",
|
||||
"editorCursor.foreground": "#000000",
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true
|
||||
"incremental": true,
|
||||
"noUnusedLocals": true
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
|
||||
8
utils/truncate.ts
Normal file
8
utils/truncate.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
const truncate = (str: string, max: number = 8) => {
|
||||
const array = str.trim().split('');
|
||||
const ellipsis = array.length > max ? '...' : '';
|
||||
|
||||
return array.slice(0, max).join('') + ellipsis;
|
||||
};
|
||||
|
||||
export default truncate
|
||||
179
yarn.lock
179
yarn.lock
@@ -43,7 +43,7 @@
|
||||
core-js-pure "^3.16.0"
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/runtime@7.15.4", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.13.10", "@babel/runtime@^7.14.0", "@babel/runtime@^7.15.4":
|
||||
"@babel/runtime@7.15.4", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.13.10", "@babel/runtime@^7.15.4":
|
||||
version "7.15.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.4.tgz#fd17d16bfdf878e6dd02d19753a39fa8a8d9c84a"
|
||||
integrity sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw==
|
||||
@@ -58,71 +58,6 @@
|
||||
"@babel/helper-validator-identifier" "^7.14.9"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@emotion/cache@^11.5.0":
|
||||
version "11.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.5.0.tgz#a5eb78cbef8163939ee345e3ddf0af217b845e62"
|
||||
integrity sha512-mAZ5QRpLriBtaj/k2qyrXwck6yeoz1V5lMt/jfj6igWU35yYlNKs2LziXVgvH81gnJZ+9QQNGelSsnuoAy6uIw==
|
||||
dependencies:
|
||||
"@emotion/memoize" "^0.7.4"
|
||||
"@emotion/sheet" "^1.0.3"
|
||||
"@emotion/utils" "^1.0.0"
|
||||
"@emotion/weak-memoize" "^0.2.5"
|
||||
stylis "^4.0.10"
|
||||
|
||||
"@emotion/hash@^0.8.0":
|
||||
version "0.8.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413"
|
||||
integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==
|
||||
|
||||
"@emotion/memoize@^0.7.4":
|
||||
version "0.7.5"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.5.tgz#2c40f81449a4e554e9fc6396910ed4843ec2be50"
|
||||
integrity sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==
|
||||
|
||||
"@emotion/react@^11.1.1":
|
||||
version "11.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.5.0.tgz#19b5771bbfbda5e8517e948a2d9064810f0022bd"
|
||||
integrity sha512-MYq/bzp3rYbee4EMBORCn4duPQfgpiEB5XzrZEBnUZAL80Qdfr7CEv/T80jwaTl/dnZmt9SnTa8NkTrwFNpLlw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@emotion/cache" "^11.5.0"
|
||||
"@emotion/serialize" "^1.0.2"
|
||||
"@emotion/sheet" "^1.0.3"
|
||||
"@emotion/utils" "^1.0.0"
|
||||
"@emotion/weak-memoize" "^0.2.5"
|
||||
hoist-non-react-statics "^3.3.1"
|
||||
|
||||
"@emotion/serialize@^1.0.2":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.0.2.tgz#77cb21a0571c9f68eb66087754a65fa97bfcd965"
|
||||
integrity sha512-95MgNJ9+/ajxU7QIAruiOAdYNjxZX7G2mhgrtDWswA21VviYIRP1R5QilZ/bDY42xiKsaktP4egJb3QdYQZi1A==
|
||||
dependencies:
|
||||
"@emotion/hash" "^0.8.0"
|
||||
"@emotion/memoize" "^0.7.4"
|
||||
"@emotion/unitless" "^0.7.5"
|
||||
"@emotion/utils" "^1.0.0"
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@emotion/sheet@^1.0.3":
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.0.3.tgz#00c326cd7985c5ccb8fe2c1b592886579dcfab8f"
|
||||
integrity sha512-YoX5GyQ4db7LpbmXHMuc8kebtBGP6nZfRC5Z13OKJMixBEwdZrJ914D6yJv/P+ZH/YY3F5s89NYX2hlZAf3SRQ==
|
||||
|
||||
"@emotion/unitless@^0.7.5":
|
||||
version "0.7.5"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed"
|
||||
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
|
||||
|
||||
"@emotion/utils@^1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.0.0.tgz#abe06a83160b10570816c913990245813a2fd6af"
|
||||
integrity sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA==
|
||||
|
||||
"@emotion/weak-memoize@^0.2.5":
|
||||
version "0.2.5"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46"
|
||||
integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==
|
||||
|
||||
"@eslint/eslintrc@^0.4.3":
|
||||
version "0.4.3"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c"
|
||||
@@ -172,14 +107,6 @@
|
||||
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz#87de7af9c231826fdd68ac7258f77c429e0e5fcf"
|
||||
integrity sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==
|
||||
|
||||
"@mattjennings/react-modal@^1.0.3":
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@mattjennings/react-modal/-/react-modal-1.0.3.tgz#f796c5238c6d799290edee2884f377aa2bc2902e"
|
||||
integrity sha512-k3Kyhrt35fshWXa7jqAWCivf/aM5T5oM1kxc9zCsb3W87arRtt0s1pY43hQeV149OV3Wh9Tn+2xlgAq+Tsj0HQ==
|
||||
dependencies:
|
||||
"@theme-ui/match-media" "^0.3.1"
|
||||
react-scrolllock "^5.0.1"
|
||||
|
||||
"@monaco-editor/loader@^1.2.0":
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@monaco-editor/loader/-/loader-1.2.0.tgz#373fad69973384624e3d9b60eefd786461a76acd"
|
||||
@@ -560,6 +487,18 @@
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
|
||||
"@radix-ui/react-alert-dialog@^0.1.1":
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-alert-dialog/-/react-alert-dialog-0.1.1.tgz#979dc343bc2766b0049e4940a49867a3c4b002f8"
|
||||
integrity sha512-2oiBy38KK/hZZFpAsjUibxjbKv+HXwsGQUcKKXZH5/D+9BPScKcF192r7aAbQer3NNMHuPEOGuGeYKWegUEzTA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/primitive" "0.1.0"
|
||||
"@radix-ui/react-compose-refs" "0.1.0"
|
||||
"@radix-ui/react-context" "0.1.1"
|
||||
"@radix-ui/react-dialog" "0.1.1"
|
||||
"@radix-ui/react-slot" "0.1.1"
|
||||
|
||||
"@radix-ui/react-arrow@0.1.1":
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-0.1.1.tgz#e8e05444b37b9f71bf712a8cd4dd07dbd419e749"
|
||||
@@ -593,7 +532,7 @@
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
|
||||
"@radix-ui/react-dialog@^0.1.1":
|
||||
"@radix-ui/react-dialog@0.1.1", "@radix-ui/react-dialog@^0.1.1":
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-0.1.1.tgz#515bcda3ab6a3a9b1cc20237eedc38b6c5921a7d"
|
||||
integrity sha512-+M/tY9n2/5yhpZrWankiVPJPFHkmgn4q+lXOeVRkMOFsyXQKhwhmPihYFUBk3BszsdKeV5BrZvdDpbWve3ZKKA==
|
||||
@@ -657,7 +596,7 @@
|
||||
"@radix-ui/react-primitive" "0.1.1"
|
||||
"@radix-ui/react-use-callback-ref" "0.1.0"
|
||||
|
||||
"@radix-ui/react-id@0.1.1":
|
||||
"@radix-ui/react-id@0.1.1", "@radix-ui/react-id@^0.1.1":
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-0.1.1.tgz#42c8f3967875e6824b2ac9d49c66317047c8d6ff"
|
||||
integrity sha512-Vlg5me65+NUgxPBuA0Lk6FerNe+Mq4EuJ8xzpskGxS2t8p1puI3IkyLZ2wWtDSb1KXazoaHn8adBypagt+1P0g==
|
||||
@@ -825,36 +764,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.0.8.tgz#be3e914e84eacf16dbebd311c0d0b44aa1174c64"
|
||||
integrity sha512-ZK5v4bJwgXldAUA8r3q9YKfCwOqoHTK/ZqRjSeRXQrBXWouoPnS4MQtgC4AXGiiBuUu5wxrRgTlv0ktmM4P1Aw==
|
||||
|
||||
"@stitches/react@^1.2.5":
|
||||
version "1.2.5"
|
||||
resolved "https://registry.yarnpkg.com/@stitches/react/-/react-1.2.5.tgz#2353343c220f0c59ba388a26fdd9ff7962cb6031"
|
||||
integrity sha512-95Wwjp5cvoYQjg616OBiHZM1PnIF51pnFQIgSPxPzS/xXBrer9sNO1tfpVfLYfOifvuotse2IFNbypJ92BXzvg==
|
||||
|
||||
"@theme-ui/color@^0.11.3":
|
||||
version "0.11.3"
|
||||
resolved "https://registry.yarnpkg.com/@theme-ui/color/-/color-0.11.3.tgz#5f85aae99178e51e4d63b1d3cb3e31cd209e7c49"
|
||||
integrity sha512-Z8c0RXVsphzhGWZDgPowwFTOLwpOhHQ4Oz+EbZFphRmXe+t6LXBhJ8vzRFEC4H5i+tV3xmunVVX7hwKlfdjO7Q==
|
||||
dependencies:
|
||||
"@theme-ui/css" "0.11.3"
|
||||
polished "^4.0.5"
|
||||
|
||||
"@theme-ui/css@0.11.3":
|
||||
version "0.11.3"
|
||||
resolved "https://registry.yarnpkg.com/@theme-ui/css/-/css-0.11.3.tgz#9962db78b9d60a96b2f6497f858e6baa7aa0f5c5"
|
||||
integrity sha512-b2vRZEc6ZBMYCVFqvSSrWdVbKgSJHOOTMow1czApJjrmZBygkG9DN0/1hgO9spDkmfp/tmRmBzrTlgFlE6pybA==
|
||||
dependencies:
|
||||
"@emotion/react" "^11.1.1"
|
||||
csstype "^3.0.5"
|
||||
|
||||
"@theme-ui/match-media@^0.11.3":
|
||||
version "0.11.3"
|
||||
resolved "https://registry.yarnpkg.com/@theme-ui/match-media/-/match-media-0.11.3.tgz#86fa82b47eae00e0f9dd5ae995e1fe5c28b4e48f"
|
||||
integrity sha512-UZXJ5DI/Q+3h9JtK0FFxEesfLUEP6JNXukng3SqprYcKcDBQRqVa1+Qc/pPkIklEK9li3/c0MBGGNHqKFMRnig==
|
||||
|
||||
"@theme-ui/match-media@^0.3.1":
|
||||
version "0.3.5"
|
||||
resolved "https://registry.yarnpkg.com/@theme-ui/match-media/-/match-media-0.3.5.tgz#e676b9f74e1f58608cfdb48ae8be69c4b7517109"
|
||||
integrity sha512-twhqy3H++jP7TqCZSRvSSc1/hxqjVokX+G/gf5S6lYQj4+zaksTO/AyzBzb/6iJLLkN2WeL9P2yjCeSTMxdJGw==
|
||||
"@stitches/react@^1.2.6-0":
|
||||
version "1.2.6-0"
|
||||
resolved "https://registry.yarnpkg.com/@stitches/react/-/react-1.2.6-0.tgz#ea7a1d35940f96337d18f5afd41aee60cbdcede7"
|
||||
integrity sha512-hws7FTFTatR5RhLkg6lFWzvGXpZYNA9OqAA8HC/jCJDDvfEpN/8+9DjTX7k7/4oEWyaZBOfALAyHj/YrgScjxQ==
|
||||
|
||||
"@types/aws-lambda@^8.10.83":
|
||||
version "8.10.84"
|
||||
@@ -1505,7 +1418,7 @@ cssnano-simple@3.0.0:
|
||||
dependencies:
|
||||
cssnano-preset-simple "^3.0.0"
|
||||
|
||||
csstype@^3.0.2, csstype@^3.0.4, csstype@^3.0.5:
|
||||
csstype@^3.0.2, csstype@^3.0.4:
|
||||
version "3.0.9"
|
||||
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.9.tgz#6410af31b26bd0520933d02cbc64fce9ce3fbf0b"
|
||||
integrity sha512-rpw6JPxK6Rfg1zLOYCSwle2GFOOsnjmDYDaBwEcwoOg4qlsIVCN789VkBZDJAGi4T07gI4YSutR43t9Zz4Lzuw==
|
||||
@@ -1956,11 +1869,6 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3:
|
||||
md5.js "^1.3.4"
|
||||
safe-buffer "^5.1.1"
|
||||
|
||||
exenv@^1.2.2:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d"
|
||||
integrity sha1-KueOhdmJQVhnCwPUe+wfA72Ru50=
|
||||
|
||||
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
|
||||
@@ -1987,6 +1895,11 @@ fast-levenshtein@^2.0.6:
|
||||
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
|
||||
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
|
||||
|
||||
fast-memoize@^2.5.1:
|
||||
version "2.5.2"
|
||||
resolved "https://registry.yarnpkg.com/fast-memoize/-/fast-memoize-2.5.2.tgz#79e3bb6a4ec867ea40ba0e7146816f6cdce9b57e"
|
||||
integrity sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw==
|
||||
|
||||
fastq@^1.6.0:
|
||||
version "1.13.0"
|
||||
resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c"
|
||||
@@ -2239,13 +2152,6 @@ hmac-drbg@^1.0.1:
|
||||
minimalistic-assert "^1.0.0"
|
||||
minimalistic-crypto-utils "^1.0.1"
|
||||
|
||||
hoist-non-react-statics@^3.3.1:
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
|
||||
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
|
||||
dependencies:
|
||||
react-is "^16.7.0"
|
||||
|
||||
http-errors@1.7.3:
|
||||
version "1.7.3"
|
||||
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06"
|
||||
@@ -3184,13 +3090,6 @@ platform@1.3.6:
|
||||
resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.6.tgz#48b4ce983164b209c2d45a107adb31f473a6e7a7"
|
||||
integrity sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==
|
||||
|
||||
polished@^4.0.5:
|
||||
version "4.1.3"
|
||||
resolved "https://registry.yarnpkg.com/polished/-/polished-4.1.3.tgz#7a3abf2972364e7d97770b827eec9a9e64002cfc"
|
||||
integrity sha512-ocPAcVBUOryJEKe0z2KLd1l9EBa1r5mSwlKpExmrLzsnIzJo4axsoU9O2BjOTkDGDT4mZ0WFE5XKTlR3nLnZOA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.14.0"
|
||||
|
||||
postcss@8.2.15:
|
||||
version "8.2.15"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.15.tgz#9e66ccf07292817d226fc315cbbf9bc148fbca65"
|
||||
@@ -3305,6 +3204,13 @@ raw-body@2.4.1:
|
||||
iconv-lite "0.4.24"
|
||||
unpipe "1.0.0"
|
||||
|
||||
re-resizable@^6.9.1:
|
||||
version "6.9.1"
|
||||
resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.9.1.tgz#6be082b55d02364ca4bfee139e04feebdf52441c"
|
||||
integrity sha512-KRYAgr9/j1PJ3K+t+MBhlQ+qkkoLDJ1rs0z1heIWvYbCW/9Vq4djDU+QumJ3hQbwwtzXF6OInla6rOx6hhgRhQ==
|
||||
dependencies:
|
||||
fast-memoize "^2.5.1"
|
||||
|
||||
react-dom@17.0.2:
|
||||
version "17.0.2"
|
||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23"
|
||||
@@ -3326,11 +3232,18 @@ react-is@17.0.2:
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
|
||||
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
|
||||
|
||||
react-is@^16.7.0, react-is@^16.8.1:
|
||||
react-is@^16.8.1:
|
||||
version "16.13.1"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
||||
|
||||
react-new-window@^0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/react-new-window/-/react-new-window-0.2.1.tgz#510aa91ba0334f0d42ba499c617a37f46c4d84ba"
|
||||
integrity sha512-3s6W8eipRbjoLGvWpFRPSt2/z5h9FTS01C+ZjaEZX7/cF6ejGc6JVuL4oEo0s73IluaqoLIDB49AK4fSMW8pJw==
|
||||
dependencies:
|
||||
prop-types "^15.7.2"
|
||||
|
||||
react-refresh@0.8.3:
|
||||
version "0.8.3"
|
||||
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f"
|
||||
@@ -3355,13 +3268,6 @@ react-remove-scroll@^2.4.0:
|
||||
use-callback-ref "^1.2.3"
|
||||
use-sidecar "^1.0.1"
|
||||
|
||||
react-scrolllock@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/react-scrolllock/-/react-scrolllock-5.0.1.tgz#da1cfb7b6d55c86ae41dbad5274b778c307752b7"
|
||||
integrity sha512-poeEsjnZAlpA6fJlaNo4rZtcip2j6l5mUGU/SJe1FFlicEudS943++u7ZSdA7lk10hoyYK3grOD02/qqt5Lxhw==
|
||||
dependencies:
|
||||
exenv "^1.2.2"
|
||||
|
||||
react-style-singleton@^2.1.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.1.1.tgz#ce7f90b67618be2b6b94902a30aaea152ce52e66"
|
||||
@@ -3725,11 +3631,6 @@ stylis@3.5.4:
|
||||
resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.5.4.tgz#f665f25f5e299cf3d64654ab949a57c768b73fbe"
|
||||
integrity sha512-8/3pSmthWM7lsPBKv7NXkzn2Uc9W7NotcwGNpJaa3k7WMM1XDCA4MgT5k/8BIexd5ydZdboXtU90XH9Ec4Bv/Q==
|
||||
|
||||
stylis@^4.0.10:
|
||||
version "4.0.10"
|
||||
resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.0.10.tgz#446512d1097197ab3f02fb3c258358c3f7a14240"
|
||||
integrity sha512-m3k+dk7QeJw660eIKRRn3xPF6uuvHs/FFzjX3HQ5ove0qYsiygoAhwn5a3IYKaZPo5LrYD0rfVmtv1gNY1uYwg==
|
||||
|
||||
supports-color@^5.3.0:
|
||||
version "5.5.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
|
||||
|
||||
Reference in New Issue
Block a user