Add some sidebars and license stuff

This commit is contained in:
2023-07-21 11:55:10 +09:00
parent 3397d7096d
commit fdf8c3b173
21 changed files with 3627 additions and 300 deletions

4
.husky/pre-commit Executable file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
pnpm pre-commit

View File

@ -4,4 +4,6 @@
**/node_modules
/public
/dist
.husky
src/assets/

44
license-emit.js Normal file
View File

@ -0,0 +1,44 @@
import { spawn } from 'child_process';
import { dirname } from 'path';
import { fileURLToPath } from 'url';
import { outputJsonSync } from 'fs-extra/esm';
const __dirname = dirname(fileURLToPath(import.meta.url));
const licenseReportFile = [`${__dirname}/src/assets/licenses.json`];
const licenseReportExec = {
// exec: `${__dirname}/node_modules/.bin/license-report`,
exec: `license-report`,
args: [`--config=${__dirname}/license-report.config.json`],
};
/*
{
name: z.string(),
licenseType: z.string(),
author: z.string(),
link: z.string().url().optional(),
installedFrom: z.string().url().optional(),
}[]
*/
const externalLicenses = [];
const emitReport = (file, toExec, externalLicenses) => {
const exec = spawn(toExec.exec, toExec.args);
let licensesString = '';
exec.stdout.on('data', (data) => {
licensesString += data.toString();
});
exec.on('close', (code) => {
console.log(`child process exited with code ${code}`);
const licenses = JSON.parse(licensesString);
const report = licenses.concat(externalLicenses);
outputJsonSync(file, report, { spaces: 2 });
});
};
for (const file of licenseReportFile) {
emitReport(file, licenseReportExec, externalLicenses);
}

View File

@ -0,0 +1,4 @@
{
"output": "json",
"fields": ["name", "licenseType", "author", "link", "installedFrom"]
}

View File

@ -3,23 +3,40 @@
"private": true,
"version": "0.0.0",
"type": "module",
"lint-staged": {
"*": [
"node license-emit.js"
],
"*.{ts,tsx,js,cjs,json,html,css}": [
"prettier --write"
],
"src/**/*.{ts,tsx}": [
"eslint --fix --report-unused-disable-directives --max-warnings 0"
]
},
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"pre-commit": "lint-staged",
"pre-build:license-report": "node license-emit.js",
"build": "run-s pre-build build:*",
"build:vite": "tsc && vite build",
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"fmt": "prettier --write \"**/*.{ts,tsx,js,cjs,json,html,css}\"",
"preview": "vite preview"
"preview": "vite preview",
"prepare": "husky install"
},
"dependencies": {
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@excalidraw/excalidraw": "^0.15.2",
"@fontsource/roboto": "^5.0.5",
"@mui/icons-material": "^5.14.1",
"@mui/material": "^5.14.1",
"@mui/styled-engine-sc": "^5.12.0",
"jotai": "^2.2.2",
"react": "^18.2.0",
"react-dom": "^18.2.0"
"react-dom": "^18.2.0",
"styled-components": "^6.0.4",
"ts-pattern": "^5.0.4",
"zod": "^3.21.4"
},
"devDependencies": {
"@types/react": "^18.2.14",
@ -30,8 +47,14 @@
"eslint": "^8.44.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.1",
"fs-extra": "^11.1.1",
"husky": "^8.0.0",
"license-report": "^6.4.0",
"lint-staged": "^13.2.3",
"npm-run-all": "^4.1.5",
"prettier": "^3.0.0",
"typescript": "^5.0.2",
"vite": "^4.4.0"
"vite": "^4.4.0",
"vite-tsconfig-paths": "^4.2.0"
}
}

3139
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -1,119 +1,21 @@
import { Excalidraw, Sidebar } from '@excalidraw/excalidraw';
import { Box, Button, Container } from '@mui/material';
import type {
ExcalidrawProps,
ExcalidrawImperativeAPI,
} from '@excalidraw/excalidraw/types/types';
import { FC, useState } from 'react';
import styled from 'styled-components';
import ExcalidrawMain from '@/Components/Excalidraw';
const ExcalidrawContainer: FC<
ExcalidrawProps & { refCallback: (api: ExcalidrawImperativeAPI) => void }
> = (props) => {
return (
<Container>
<Box
sx={{
border: '1.5px solid',
width: '95vw',
height: '95vh',
}}
>
<Excalidraw {...props} ref={props.refCallback} />
</Box>
</Container>
);
};
export const Main = styled.div`
overflow: hidden;
position: absolute;
top: 50%;
left: 50%;
margin-right: -50%;
transform: translate(-50%, -50%);
`;
function App() {
// TODO: jotai premitives
const isCollaborating = false;
const [excalidrawAPI, setExcalidrawAPI] = useState<ExcalidrawImperativeAPI>();
return (
<Container
sx={{
display: 'grid',
height: '100%',
width: '100%',
placeContent: 'center',
overflow: 'hidden',
}}
>
<ExcalidrawContainer
refCallback={(api) => setExcalidrawAPI(api)}
isCollaborating={isCollaborating}
autoFocus={true}
name="Excalidraw with WebRTC"
renderTopRightUI={() => {
return (
<Button
onClick={() => {
excalidrawAPI?.toggleMenu('customSidebar');
}}
>
Button
</Button>
);
}}
renderSidebar={() => {
return (
<Sidebar dockable={true}>
<Sidebar.Header> Header </Sidebar.Header>
<Button>Button</Button>
</Sidebar>
);
}}
/>
</Container>
<Main>
<ExcalidrawMain />
</Main>
);
}
/*
export interface ExcalidrawProps {
// Render UI elements
renderTopRightUI?: (isMobile: boolean, appState: AppState) => JSX.Element | null;
renderSidebar?: () => JSX.Element | null;
onChange?: (elements: readonly ExcalidrawElement[], appState: AppState, files: BinaryFiles) => void;
initialData?: ExcalidrawInitialDataState | null | Promise<ExcalidrawInitialDataState | null>;
excalidrawRef?: ForwardRef<ExcalidrawAPIRefValue>;
isCollaborating?: boolean;
onPointerUpdate?: (payload: {
pointer: {
x: number;
y: number;
};
button: "down" | "up";
pointersMap: Gesture["pointers"];
}) => void;
onPaste?: (data: ClipboardData, event: ClipboardEvent | null) => Promise<boolean> | boolean;
langCode?: Language["code"];
onPointerDown?: (activeTool: AppState["activeTool"], pointerDownState: PointerDownState) => void;
generateIdForFile?: (file: File) => string | Promise<string>;
UIOptions?: Partial<UIOptions>;
renderCustomStats?: (elements: readonly NonDeletedExcalidrawElement[], appState: AppState) => JSX.Element;
viewModeEnabled?: boolean;
zenModeEnabled?: boolean;
gridModeEnabled?: boolean;
libraryReturnUrl?: string;
name?: string;
theme?: Theme;
detectScroll?: boolean;
handleKeyboardGlobally?: boolean;
onLibraryChange?: (libraryItems: LibraryItems) => void | Promise<any>;
autoFocus?: boolean;
onLinkOpen?: (element: NonDeletedExcalidrawElement, event: CustomEvent<{
nativeEvent: MouseEvent | React.PointerEvent<HTMLCanvasElement>;
}>) => void;
onScrollChange?: (scrollX: number, scrollY: number) => void;
children?: React.ReactNode;
}
*/
export default App;

View File

@ -0,0 +1,87 @@
import { ExcalidrawImperativeAPI } from '@excalidraw/excalidraw/types/types';
import ExcalidrawContainer from './Excalidraw/Container';
import { useCallback, useState } from 'react';
import Sidebar, { SidebarVariant } from './Excalidraw/Sidebar';
import RightTopUI from './Excalidraw/RightTopUI';
export const ExcalidrawMain = () => {
const [excalidrawAPI, setExcalidrawAPI] = useState<ExcalidrawImperativeAPI>();
const [sidebarVariant, setSidebarVariant] =
useState<SidebarVariant>('general');
const [toggleState, setToggleState] = useState<boolean>(false);
const onClose = useCallback(
() => setToggleState(!toggleState),
[toggleState]
);
return (
<ExcalidrawContainer
refCallback={(api) => setExcalidrawAPI(api)}
autoFocus={true}
name="Excalidraw with WebRTC"
renderTopRightUI={() => (
<RightTopUI
toggleState={toggleState}
setToggleState={setToggleState}
setSidebarVariant={setSidebarVariant}
excalidrawAPI={excalidrawAPI!}
/>
)}
renderSidebar={() => {
return <Sidebar variant={sidebarVariant} variantProps={{ onClose }} />;
}}
/>
);
};
/*
export interface ExcalidrawProps {
// Render UI elements
renderTopRightUI?: (isMobile: boolean, appState: AppState) => JSX.Element | null;
renderSidebar?: () => JSX.Element | null;
onChange?: (elements: readonly ExcalidrawElement[], appState: AppState, files: BinaryFiles) => void;
initialData?: ExcalidrawInitialDataState | null | Promise<ExcalidrawInitialDataState | null>;
excalidrawRef?: ForwardRef<ExcalidrawAPIRefValue>;
isCollaborating?: boolean;
onPointerUpdate?: (payload: {
pointer: {
x: number;
y: number;
};
button: "down" | "up";
pointersMap: Gesture["pointers"];
}) => void;
onPaste?: (data: ClipboardData, event: ClipboardEvent | null) => Promise<boolean> | boolean;
langCode?: Language["code"];
onPointerDown?: (activeTool: AppState["activeTool"], pointerDownState: PointerDownState) => void;
generateIdForFile?: (file: File) => string | Promise<string>;
UIOptions?: Partial<UIOptions>;
renderCustomStats?: (elements: readonly NonDeletedExcalidrawElement[], appState: AppState) => JSX.Element;
viewModeEnabled?: boolean;
zenModeEnabled?: boolean;
gridModeEnabled?: boolean;
libraryReturnUrl?: string;
name?: string;
theme?: Theme;
detectScroll?: boolean;
handleKeyboardGlobally?: boolean;
onLibraryChange?: (libraryItems: LibraryItems) => void | Promise<any>;
autoFocus?: boolean;
onLinkOpen?: (element: NonDeletedExcalidrawElement, event: CustomEvent<{
nativeEvent: MouseEvent | React.PointerEvent<HTMLCanvasElement>;
}>) => void;
onScrollChange?: (scrollX: number, scrollY: number) => void;
children?: React.ReactNode;
}
*/
export default ExcalidrawMain;

View File

@ -0,0 +1,68 @@
import { Excalidraw } from '@excalidraw/excalidraw';
import type {
ExcalidrawProps,
ExcalidrawImperativeAPI,
} from '@excalidraw/excalidraw/types/types';
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
import styled from 'styled-components';
export type WindowRect = {
width: number;
height: number;
};
export type ExcalidrawBoxProps = {
$windowRect: WindowRect;
$scale?: number;
};
const ExcalidrawBox = styled.div<ExcalidrawBoxProps>`
${(props) => {
const { $windowRect: windowRect, $scale: $scale } = props;
const scale = $scale! ? $scale : 1;
const { width, height } = windowRect;
const scaledWidth = width * scale;
const scaledHeight = height * scale;
return `
width: ${scaledWidth}px;
height: ${scaledHeight}px;
`;
}}
`;
export type ExcalidrawContainerProps = ExcalidrawProps & {
refCallback: (api: ExcalidrawImperativeAPI) => void;
} & Omit<ExcalidrawBoxProps, '$windowRect'>;
export const ExcalidrawContainer: FC<ExcalidrawContainerProps> = (props) => {
const scale = useMemo(
() => (props.$scale ? props.$scale : 1),
[props.$scale]
);
const [windowRect, setWindowRect] = useState<WindowRect>({
width: window.innerWidth,
height: window.innerHeight,
});
const onResize = useCallback(() => {
setWindowRect({
width: window.innerWidth,
height: window.innerHeight,
});
}, []);
useEffect(() => {
window.addEventListener('resize', onResize);
return () => window.removeEventListener('resize', onResize);
}, [onResize]);
return (
<ExcalidrawBox $scale={scale} $windowRect={windowRect}>
<Excalidraw {...props} ref={props.refCallback} />
</ExcalidrawBox>
);
};
export default ExcalidrawContainer;

View File

@ -0,0 +1,43 @@
import { ExcalidrawImperativeAPI } from '@excalidraw/excalidraw/types/types';
import { FC, useCallback } from 'react';
import { ToggleButton, ToggleButtonGroup } from '@/Components/Utilities';
import { SidebarVariant, SidebarVariantSchema } from './Sidebar';
import { z } from 'zod';
export const RightTopUIPropsScheme = z.object({
setSidebarVariant: z.function().args(SidebarVariantSchema).returns(z.void()),
setToggleState: z.function().args(z.boolean()).returns(z.void()),
toggleState: z.boolean(),
});
export type RightTopUIProps = z.infer<typeof RightTopUIPropsScheme> & {
excalidrawAPI: ExcalidrawImperativeAPI;
};
const RightTopUI: FC<RightTopUIProps> = (props) => {
const excalidrawAPI = props.excalidrawAPI;
const sidebarToggle = useCallback(
(variant: SidebarVariant) => {
if (excalidrawAPI && !props.toggleState) {
props.setToggleState(props.toggleState);
props.setSidebarVariant(variant);
excalidrawAPI.toggleMenu('customSidebar');
}
},
[excalidrawAPI, props]
);
return (
<ToggleButtonGroup
exclusive
onChange={(_, value: SidebarVariant) => sidebarToggle(value)}
disabled={props.toggleState}
>
<ToggleButton value="general">General</ToggleButton>
<ToggleButton value="collaboration">Collaboration</ToggleButton>
</ToggleButtonGroup>
);
};
export default RightTopUI;

View File

@ -0,0 +1,40 @@
import { FC } from 'react';
import { match } from 'ts-pattern';
import { z } from 'zod';
import CollaborationSidebar, {
CollaborationSidebarPropsSchema,
} from './Sidebar/Collaboration';
import GeneralSidebar, { GeneralSidebarPropsSchema } from './Sidebar/General';
export const SidebarVariantSchema = z.enum(['collaboration', 'general']);
export type SidebarVariant = z.infer<typeof SidebarVariantSchema>;
export const SidebarVariantPropsSchema = z.union([
CollaborationSidebarPropsSchema,
GeneralSidebarPropsSchema,
]);
export type SidebarVariantProps = z.infer<typeof SidebarVariantPropsSchema>;
export const SidebarProrps = z.object({
variant: SidebarVariantSchema,
variantProps: SidebarVariantPropsSchema,
});
export type SidebarProps = z.infer<typeof SidebarProrps>;
export const Sidebar: FC<SidebarProps> = (props) => {
return match(props.variant)
.with('collaboration', () => {
const _props = CollaborationSidebarPropsSchema.parse(props.variantProps);
return <CollaborationSidebar {..._props} />;
})
.with('general', () => {
const _props = GeneralSidebarPropsSchema.parse(props.variantProps);
return <GeneralSidebar {..._props} />;
})
.exhaustive();
};
export default Sidebar;

View File

@ -0,0 +1,22 @@
import { SidebarProvider } from '@/Components/Utilities';
import { FC } from 'react';
import { z } from 'zod';
import type { ReactNode } from 'react';
export const SidebarBasePropsSchema = z.object({
onClose: z.function().returns(z.void()),
});
export type SidebarBaseProps = z.infer<typeof SidebarBasePropsSchema> & {
children?: ReactNode;
};
const SidebarProviderBase: FC<SidebarBaseProps> = (props) => {
return (
<SidebarProvider dockable={true} onClose={props.onClose}>
{props.children}
</SidebarProvider>
);
};
export default SidebarProviderBase;

View File

@ -0,0 +1,23 @@
import { FC } from 'react';
import { Button, SidebarHeader } from '@/Components/Utilities';
import { z } from 'zod';
import SidebarProviderBase, { SidebarBasePropsSchema } from './Base';
export type CollaborationSidebarProps = z.infer<
typeof CollaborationSidebarPropsSchema
>;
export const CollaborationSidebarPropsSchema = z
.object({})
.merge(SidebarBasePropsSchema);
const CollaborationSidebar: FC<CollaborationSidebarProps> = (props) => {
return (
<SidebarProviderBase onClose={props.onClose}>
<SidebarHeader>Collaboration Settings</SidebarHeader>
<Button>Button</Button>
</SidebarProviderBase>
);
};
export default CollaborationSidebar;

View File

@ -0,0 +1,21 @@
import { FC } from 'react';
import { Button, SidebarHeader } from '@/Components/Utilities';
import { z } from 'zod';
import SidebarProviderBase, { SidebarBasePropsSchema } from './Base';
export type GeneralSidebarProps = z.infer<typeof GeneralSidebarPropsSchema>;
export const GeneralSidebarPropsSchema = z
.object({})
.merge(SidebarBasePropsSchema);
const GeneralSidebar: FC<GeneralSidebarProps> = (props) => {
return (
<SidebarProviderBase onClose={props.onClose}>
<SidebarHeader>General Settings</SidebarHeader>
<Button>Button</Button>
</SidebarProviderBase>
);
};
export default GeneralSidebar;

View File

@ -0,0 +1,16 @@
import styled from 'styled-components';
import {
Button as ButtonBase,
ToggleButtonGroup as ToggleButtonGroupBase,
ToggleButton as ToggleButtonBase,
} from '@mui/material';
import { Sidebar } from '@excalidraw/excalidraw';
export const SidebarProvider = styled(Sidebar)``;
export const SidebarHeader = styled(Sidebar.Header)``;
export const Button = styled(ButtonBase)``;
export const ToggleButtonGroup = styled(ToggleButtonGroupBase)``;
export const ToggleButton = styled(ToggleButtonBase)``;

198
src/assets/licenses.json Normal file
View File

@ -0,0 +1,198 @@
[
{
"name": "@excalidraw/excalidraw",
"licenseType": "MIT",
"author": "n/a",
"link": "https://github.com/excalidraw/excalidraw",
"installedFrom": "https://registry.npmjs.org/@excalidraw/excalidraw/-/excalidraw-0.15.2.tgz"
},
{
"name": "@fontsource/roboto",
"licenseType": "Apache-2.0",
"author": "Google Inc.",
"link": "git+https://github.com/fontsource/font-files.git",
"installedFrom": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-5.0.5.tgz"
},
{
"name": "@mui/icons-material",
"licenseType": "MIT",
"author": "MUI Team",
"link": "git+https://github.com/mui/material-ui.git",
"installedFrom": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.14.1.tgz"
},
{
"name": "@mui/material",
"licenseType": "MIT",
"author": "MUI Team",
"link": "git+https://github.com/mui/material-ui.git",
"installedFrom": "https://registry.npmjs.org/@mui/material/-/material-5.14.1.tgz"
},
{
"name": "@mui/styled-engine-sc",
"licenseType": "MIT",
"author": "MUI Team",
"link": "git+https://github.com/mui/material-ui.git",
"installedFrom": "https://registry.npmjs.org/@mui/styled-engine-sc/-/styled-engine-sc-5.12.0.tgz"
},
{
"name": "jotai",
"licenseType": "MIT",
"author": "Daishi Kato",
"link": "git+https://github.com/pmndrs/jotai.git",
"installedFrom": "https://registry.npmjs.org/jotai/-/jotai-2.2.2.tgz"
},
{
"name": "react",
"licenseType": "MIT",
"author": "n/a",
"link": "git+https://github.com/facebook/react.git",
"installedFrom": "https://registry.npmjs.org/react/-/react-18.2.0.tgz"
},
{
"name": "react-dom",
"licenseType": "MIT",
"author": "n/a",
"link": "git+https://github.com/facebook/react.git",
"installedFrom": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz"
},
{
"name": "styled-components",
"licenseType": "MIT",
"author": "Glen Maddern",
"link": "git+https://github.com/styled-components/styled-components.git",
"installedFrom": "https://registry.npmjs.org/styled-components/-/styled-components-6.0.4.tgz"
},
{
"name": "ts-pattern",
"licenseType": "MIT",
"author": "Gabriel Vergnaud",
"link": "git+ssh://git@github.com/gvergnaud/ts-pattern.git",
"installedFrom": "https://registry.npmjs.org/ts-pattern/-/ts-pattern-5.0.4.tgz"
},
{
"name": "zod",
"licenseType": "MIT",
"author": "Colin McDonnell <colin@colinhacks.com>",
"link": "git+https://github.com/colinhacks/zod.git",
"installedFrom": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz"
},
{
"name": "@types/react",
"licenseType": "MIT",
"author": "n/a",
"link": "https://github.com/DefinitelyTyped/DefinitelyTyped.git",
"installedFrom": "https://registry.npmjs.org/@types/react/-/react-18.2.14.tgz"
},
{
"name": "@types/react-dom",
"licenseType": "MIT",
"author": "n/a",
"link": "https://github.com/DefinitelyTyped/DefinitelyTyped.git",
"installedFrom": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.6.tgz"
},
{
"name": "@typescript-eslint/eslint-plugin",
"licenseType": "MIT",
"author": "n/a",
"link": "git+https://github.com/typescript-eslint/typescript-eslint.git",
"installedFrom": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.61.0.tgz"
},
{
"name": "@typescript-eslint/parser",
"licenseType": "BSD-2-Clause",
"author": "n/a",
"link": "git+https://github.com/typescript-eslint/typescript-eslint.git",
"installedFrom": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.61.0.tgz"
},
{
"name": "@vitejs/plugin-react-swc",
"licenseType": "MIT",
"author": "Arnaud Barré (https://github.com/ArnaudBarre)",
"link": "git+https://github.com/vitejs/vite-plugin-react-swc.git",
"installedFrom": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.3.2.tgz"
},
{
"name": "eslint",
"licenseType": "MIT",
"author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
"link": "git+https://github.com/eslint/eslint.git",
"installedFrom": "https://registry.npmjs.org/eslint/-/eslint-8.44.0.tgz"
},
{
"name": "eslint-plugin-react-hooks",
"licenseType": "MIT",
"author": "n/a",
"link": "git+https://github.com/facebook/react.git",
"installedFrom": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz"
},
{
"name": "eslint-plugin-react-refresh",
"licenseType": "MIT",
"author": "Arnaud Barré (https://github.com/ArnaudBarre)",
"link": "git+https://github.com/ArnaudBarre/eslint-plugin-react-refresh.git",
"installedFrom": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.1.tgz"
},
{
"name": "fs-extra",
"licenseType": "MIT",
"author": "JP Richardson <jprichardson@gmail.com>",
"link": "git+https://github.com/jprichardson/node-fs-extra.git",
"installedFrom": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz"
},
{
"name": "husky",
"licenseType": "MIT",
"author": "Typicode <typicode@gmail.com>",
"link": "git+https://github.com/typicode/husky.git",
"installedFrom": "https://registry.npmjs.org/husky/-/husky-8.0.0.tgz"
},
{
"name": "license-report",
"licenseType": "MIT",
"author": "Yaniv Kessler",
"link": "git+https://github.com/ironSource/license-report.git",
"installedFrom": "https://registry.npmjs.org/license-report/-/license-report-6.4.0.tgz"
},
{
"name": "lint-staged",
"licenseType": "MIT",
"author": "Andrey Okonetchnikov <andrey@okonet.ru>",
"link": "git+https://github.com/okonet/lint-staged.git",
"installedFrom": "https://registry.npmjs.org/lint-staged/-/lint-staged-13.2.3.tgz"
},
{
"name": "npm-run-all",
"licenseType": "MIT",
"author": "Toru Nagashima",
"link": "git+https://github.com/mysticatea/npm-run-all.git",
"installedFrom": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz"
},
{
"name": "prettier",
"licenseType": "MIT",
"author": "James Long",
"link": "git+https://github.com/prettier/prettier.git",
"installedFrom": "https://registry.npmjs.org/prettier/-/prettier-3.0.0.tgz"
},
{
"name": "typescript",
"licenseType": "Apache-2.0",
"author": "Microsoft Corp.",
"link": "git+https://github.com/Microsoft/TypeScript.git",
"installedFrom": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz"
},
{
"name": "vite",
"licenseType": "MIT",
"author": "Evan You",
"link": "git+https://github.com/vitejs/vite.git",
"installedFrom": "https://registry.npmjs.org/vite/-/vite-4.4.0.tgz"
},
{
"name": "vite-tsconfig-paths",
"licenseType": "MIT",
"author": "aleclarson",
"link": "git+https://github.com/aleclarson/vite-tsconfig-paths.git",
"installedFrom": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-4.2.0.tgz"
}
]

5
src/index.css Normal file
View File

@ -0,0 +1,5 @@
body {
margin: 0;
display: flex;
place-items: center;
}

View File

@ -1,11 +1,7 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.tsx';
import '@fontsource/roboto/300.css';
import '@fontsource/roboto/400.css';
import '@fontsource/roboto/500.css';
import '@fontsource/roboto/700.css';
import './index.css';
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>

13
src/types/license.ts Normal file
View File

@ -0,0 +1,13 @@
import { z } from 'zod';
export const License = z.array(
z.object({
name: z.string(),
licenseType: z.string(),
author: z.string(),
link: z.string().url().optional(),
installedFrom: z.string().url().optional(),
})
);
export type License = z.infer<typeof License>;

View File

@ -5,7 +5,6 @@
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
@ -13,13 +12,22 @@
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
"noFallthroughCasesInSwitch": true,
/* Aliases */
"baseUrl": "./",
"paths": {
"@/*": ["src/*"],
"@mui/styled-engine": ["./node_modules/@mui/styled-engine-sc"]
}
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
"references": [
{
"path": "./tsconfig.node.json"
}
]
}

View File

@ -1,7 +1,22 @@
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react-swc';
import tsconfigPaths from 'vite-tsconfig-paths';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@mui/styled-engine': '@mui/styled-engine-sc',
},
},
optimizeDeps: {
include: [
'react',
'react-dom',
'@mui/material',
'@excalidraw/excalidraw',
'styled-components',
],
},
plugins: [react(), tsconfigPaths()],
});