init
@@ -0,0 +1,24 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
.DS_Store
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"arrowParens": "avoid",
|
||||||
|
"semi": true,
|
||||||
|
"singleQuote": true,
|
||||||
|
"tabWidth": 2,
|
||||||
|
"trailingComma": "all"
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
# React + TypeScript + Vite
|
||||||
|
|
||||||
|
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
||||||
|
|
||||||
|
Currently, two official plugins are available:
|
||||||
|
|
||||||
|
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
|
||||||
|
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
||||||
|
|
||||||
|
## Expanding the ESLint configuration
|
||||||
|
|
||||||
|
If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
|
||||||
|
|
||||||
|
- Configure the top-level `parserOptions` property like this:
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default tseslint.config({
|
||||||
|
languageOptions: {
|
||||||
|
// other options...
|
||||||
|
parserOptions: {
|
||||||
|
project: ['./tsconfig.node.json', './tsconfig.app.json'],
|
||||||
|
tsconfigRootDir: import.meta.dirname,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked`
|
||||||
|
- Optionally add `...tseslint.configs.stylisticTypeChecked`
|
||||||
|
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config:
|
||||||
|
|
||||||
|
```js
|
||||||
|
// eslint.config.js
|
||||||
|
import react from 'eslint-plugin-react'
|
||||||
|
|
||||||
|
export default tseslint.config({
|
||||||
|
// Set the react version
|
||||||
|
settings: { react: { version: '18.3' } },
|
||||||
|
plugins: {
|
||||||
|
// Add the react plugin
|
||||||
|
react,
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
// other rules...
|
||||||
|
// Enable its recommended rules
|
||||||
|
...react.configs.recommended.rules,
|
||||||
|
...react.configs['jsx-runtime'].rules,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import js from '@eslint/js'
|
||||||
|
import globals from 'globals'
|
||||||
|
import reactHooks from 'eslint-plugin-react-hooks'
|
||||||
|
import reactRefresh from 'eslint-plugin-react-refresh'
|
||||||
|
import tseslint from 'typescript-eslint'
|
||||||
|
|
||||||
|
export default tseslint.config(
|
||||||
|
{ ignores: ['dist'] },
|
||||||
|
{
|
||||||
|
extends: [js.configs.recommended, ...tseslint.configs.recommended],
|
||||||
|
files: ['**/*.{ts,tsx}'],
|
||||||
|
languageOptions: {
|
||||||
|
ecmaVersion: 2020,
|
||||||
|
globals: globals.browser,
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
'react-hooks': reactHooks,
|
||||||
|
'react-refresh': reactRefresh,
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
...reactHooks.configs.recommended.rules,
|
||||||
|
'react-refresh/only-export-components': [
|
||||||
|
'warn',
|
||||||
|
{ allowConstantExport: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<!-- <link rel="icon" type="image/svg+xml" href="/vite.svg" /> -->
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Vite + React + TS</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
<script type="module" src="/src/main.tsx"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"name": "graff.event",
|
||||||
|
"private": true,
|
||||||
|
"version": "0.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "tsc -b && vite build",
|
||||||
|
"lint": "eslint .",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"framer-motion": "^11.3.31",
|
||||||
|
"react": "^18.3.1",
|
||||||
|
"react-dom": "^18.3.1",
|
||||||
|
"react-router-dom": "^6.26.1",
|
||||||
|
"usehooks-ts": "^3.1.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@eslint/js": "^9.9.0",
|
||||||
|
"@types/react": "^18.3.3",
|
||||||
|
"@types/react-dom": "^18.3.0",
|
||||||
|
"@vitejs/plugin-react": "^4.3.1",
|
||||||
|
"autoprefixer": "^10.4.20",
|
||||||
|
"eslint": "^9.9.0",
|
||||||
|
"eslint-plugin-react-hooks": "^5.1.0-rc.0",
|
||||||
|
"eslint-plugin-react-refresh": "^0.4.9",
|
||||||
|
"globals": "^15.9.0",
|
||||||
|
"postcss": "^8.4.41",
|
||||||
|
"prettier": "^3.3.3",
|
||||||
|
"tailwindcss": "^3.4.10",
|
||||||
|
"typescript": "^5.5.3",
|
||||||
|
"typescript-eslint": "^8.0.1",
|
||||||
|
"vite": "^5.4.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -0,0 +1,250 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="robots" content="noindex, noarchive">
|
||||||
|
<meta name="format-detection" content="telephone=no">
|
||||||
|
<title>Transfonter demo</title>
|
||||||
|
<link href="stylesheet.css" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
/*
|
||||||
|
http://meyerweb.com/eric/tools/css/reset/
|
||||||
|
v2.0 | 20110126
|
||||||
|
License: none (public domain)
|
||||||
|
*/
|
||||||
|
html, body, div, span, applet, object, iframe,
|
||||||
|
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||||
|
a, abbr, acronym, address, big, cite, code,
|
||||||
|
del, dfn, em, img, ins, kbd, q, s, samp,
|
||||||
|
small, strike, strong, sub, sup, tt, var,
|
||||||
|
b, u, i, center,
|
||||||
|
dl, dt, dd, ol, ul, li,
|
||||||
|
fieldset, form, label, legend,
|
||||||
|
table, caption, tbody, tfoot, thead, tr, th, td,
|
||||||
|
article, aside, canvas, details, embed,
|
||||||
|
figure, figcaption, footer, header, hgroup,
|
||||||
|
menu, nav, output, ruby, section, summary,
|
||||||
|
time, mark, audio, video {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
font-size: 100%;
|
||||||
|
font: inherit;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
/* HTML5 display-role reset for older browsers */
|
||||||
|
article, aside, details, figcaption, figure,
|
||||||
|
footer, header, hgroup, menu, nav, section {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
ol, ul {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
blockquote, q {
|
||||||
|
quotes: none;
|
||||||
|
}
|
||||||
|
blockquote:before, blockquote:after,
|
||||||
|
q:before, q:after {
|
||||||
|
content: '';
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
/* demo styles */
|
||||||
|
body {
|
||||||
|
background: #f0f0f0;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
.page {
|
||||||
|
background: #fff;
|
||||||
|
width: 920px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px 20px 0 20px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.font-container {
|
||||||
|
overflow-x: auto;
|
||||||
|
overflow-y: hidden;
|
||||||
|
margin-bottom: 40px;
|
||||||
|
line-height: 1.3;
|
||||||
|
white-space: nowrap;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
position: relative;
|
||||||
|
background: #444;
|
||||||
|
font-size: 32px;
|
||||||
|
color: #fff;
|
||||||
|
padding: 10px 20px;
|
||||||
|
margin: 0 -20px 12px -20px;
|
||||||
|
}
|
||||||
|
.letters {
|
||||||
|
font-size: 25px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.s10:before {
|
||||||
|
content: '10px';
|
||||||
|
}
|
||||||
|
.s11:before {
|
||||||
|
content: '11px';
|
||||||
|
}
|
||||||
|
.s12:before {
|
||||||
|
content: '12px';
|
||||||
|
}
|
||||||
|
.s14:before {
|
||||||
|
content: '14px';
|
||||||
|
}
|
||||||
|
.s18:before {
|
||||||
|
content: '18px';
|
||||||
|
}
|
||||||
|
.s24:before {
|
||||||
|
content: '24px';
|
||||||
|
}
|
||||||
|
.s30:before {
|
||||||
|
content: '30px';
|
||||||
|
}
|
||||||
|
.s36:before {
|
||||||
|
content: '36px';
|
||||||
|
}
|
||||||
|
.s48:before {
|
||||||
|
content: '48px';
|
||||||
|
}
|
||||||
|
.s60:before {
|
||||||
|
content: '60px';
|
||||||
|
}
|
||||||
|
.s72:before {
|
||||||
|
content: '72px';
|
||||||
|
}
|
||||||
|
.s10:before, .s11:before, .s12:before, .s14:before,
|
||||||
|
.s18:before, .s24:before, .s30:before, .s36:before,
|
||||||
|
.s48:before, .s60:before, .s72:before {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
color: #999;
|
||||||
|
padding-right: 6px;
|
||||||
|
}
|
||||||
|
pre {
|
||||||
|
display: block;
|
||||||
|
padding: 9px;
|
||||||
|
margin: 0 0 12px;
|
||||||
|
font-family: Monaco, Menlo, Consolas, "Courier New", monospace;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.428571429;
|
||||||
|
color: #333;
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
overflow-x: auto;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
/* responsive */
|
||||||
|
@media (max-width: 959px) {
|
||||||
|
.page {
|
||||||
|
width: auto;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="page">
|
||||||
|
<div class="demo">
|
||||||
|
<h1 style="font-family: 'TTHovesPro-DmBd'; font-weight: 600; font-style: normal;">☝︎TT Hoves Pro DemiBold</h1>
|
||||||
|
<pre title="Usage">.your-style {
|
||||||
|
font-family: 'TTHovesPro-DmBd';
|
||||||
|
font-weight: 600;
|
||||||
|
font-style: normal;
|
||||||
|
}</pre>
|
||||||
|
<pre title="Preload (optional)">
|
||||||
|
<link rel="preload" href="TTHovesPro-DmBd.woff2" as="font" type="font/woff2" crossorigin></pre>
|
||||||
|
<div class="font-container" style="font-family: 'TTHovesPro-DmBd'; font-weight: 600; font-style: normal;">
|
||||||
|
<p class="letters">
|
||||||
|
abcdefghijklmnopqrstuvwxyz<br>
|
||||||
|
ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>
|
||||||
|
0123456789.:,;()*!?'@#<>$%&^+-=~
|
||||||
|
</p>
|
||||||
|
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="demo">
|
||||||
|
<h1 style="font-family: 'TTHovesPro-Md'; font-weight: 500; font-style: normal;">☝︎TT Hoves Pro Medium</h1>
|
||||||
|
<pre title="Usage">.your-style {
|
||||||
|
font-family: 'TTHovesPro-Md';
|
||||||
|
font-weight: 500;
|
||||||
|
font-style: normal;
|
||||||
|
}</pre>
|
||||||
|
<pre title="Preload (optional)">
|
||||||
|
<link rel="preload" href="TTHovesPro-Md.woff2" as="font" type="font/woff2" crossorigin></pre>
|
||||||
|
<div class="font-container" style="font-family: 'TTHovesPro-Md'; font-weight: 500; font-style: normal;">
|
||||||
|
<p class="letters">
|
||||||
|
abcdefghijklmnopqrstuvwxyz<br>
|
||||||
|
ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>
|
||||||
|
0123456789.:,;()*!?'@#<>$%&^+-=~
|
||||||
|
</p>
|
||||||
|
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="demo">
|
||||||
|
<h1 style="font-family: 'TTHovesPro-Rg'; font-weight: normal; font-style: normal;">☝︎TT Hoves Pro Regular</h1>
|
||||||
|
<pre title="Usage">.your-style {
|
||||||
|
font-family: 'TTHovesPro-Rg';
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}</pre>
|
||||||
|
<pre title="Preload (optional)">
|
||||||
|
<link rel="preload" href="TTHovesPro-Rg.woff2" as="font" type="font/woff2" crossorigin></pre>
|
||||||
|
<div class="font-container" style="font-family: 'TTHovesPro-Rg'; font-weight: normal; font-style: normal;">
|
||||||
|
<p class="letters">
|
||||||
|
abcdefghijklmnopqrstuvwxyz<br>
|
||||||
|
ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>
|
||||||
|
0123456789.:,;()*!?'@#<>$%&^+-=~
|
||||||
|
</p>
|
||||||
|
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: 'TTHovesPro';
|
||||||
|
src: url('TTHovesPro-DmBd.eot');
|
||||||
|
src:
|
||||||
|
url('TTHovesPro-DmBd.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('TTHovesPro-DmBd.woff2') format('woff2'),
|
||||||
|
url('TTHovesPro-DmBd.woff') format('woff'),
|
||||||
|
url('TTHovesPro-DmBd.ttf') format('truetype');
|
||||||
|
font-weight: 600;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'TTHovesPro';
|
||||||
|
src: url('TTHovesPro-Md.eot');
|
||||||
|
src:
|
||||||
|
url('TTHovesPro-Md.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('TTHovesPro-Md.woff2') format('woff2'),
|
||||||
|
url('TTHovesPro-Md.woff') format('woff'),
|
||||||
|
url('TTHovesPro-Md.ttf') format('truetype');
|
||||||
|
font-weight: 500;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'TTHovesPro';
|
||||||
|
src: url('TTHovesPro-Rg.eot');
|
||||||
|
src:
|
||||||
|
url('TTHovesPro-Rg.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('TTHovesPro-Rg.woff2') format('woff2'),
|
||||||
|
url('TTHovesPro-Rg.woff') format('woff'),
|
||||||
|
url('TTHovesPro-Rg.ttf') format('truetype');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export function Footer() {
|
||||||
|
return <footer></footer>;
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { Logo } from '../components/icons/Logo';
|
||||||
|
import { Button } from '../components/ui/Button';
|
||||||
|
import { ClassNameWrapper } from '../hocs/ClassNameWrapper';
|
||||||
|
|
||||||
|
export function Header() {
|
||||||
|
return (
|
||||||
|
<header className="lg:px-6 flex items-center h-16 border-b border-[#3D425C]">
|
||||||
|
<Link to={'/'}>
|
||||||
|
<ClassNameWrapper element={<Logo />} className="h-10" />
|
||||||
|
</Link>
|
||||||
|
<nav className="mx-auto self-stretch flex">
|
||||||
|
{[
|
||||||
|
{ path: '/#products', text: 'Продукты' },
|
||||||
|
{ path: '/#devices', text: 'Оборудование' },
|
||||||
|
{ path: '/#projects', text: 'Проекты' },
|
||||||
|
{ path: '/#contacts', text: 'Контакты' },
|
||||||
|
].map(link => (
|
||||||
|
<HashLink key={link.path} {...link} />
|
||||||
|
))}
|
||||||
|
</nav>
|
||||||
|
<Button className="-mr-6 rounded-none h-full px-10 btn-text">
|
||||||
|
Отправить заявку
|
||||||
|
</Button>
|
||||||
|
</header>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function HashLink({ path, text }: { path: string; text: string }) {
|
||||||
|
return (
|
||||||
|
<Link
|
||||||
|
className="border-l last:border-r border-[#3D425C] px-10 self-stretch text-[#9299BD] btn-text content-center hover:bg-[#3D425C]"
|
||||||
|
to={path}
|
||||||
|
>
|
||||||
|
{text}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { Outlet } from 'react-router-dom';
|
||||||
|
import { Footer } from './Footer';
|
||||||
|
import { Header } from './Header';
|
||||||
|
|
||||||
|
export function Layout() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Header />
|
||||||
|
<main className="lg:px-6">
|
||||||
|
<Outlet />
|
||||||
|
</main>
|
||||||
|
<Footer />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 1.5 MiB |
|
After Width: | Height: | Size: 257 KiB |
|
After Width: | Height: | Size: 218 KiB |
|
After Width: | Height: | Size: 223 KiB |
|
After Width: | Height: | Size: 112 KiB |
|
After Width: | Height: | Size: 240 KiB |
|
After Width: | Height: | Size: 169 KiB |
|
After Width: | Height: | Size: 192 KiB |
|
After Width: | Height: | Size: 223 KiB |
|
After Width: | Height: | Size: 741 KiB |
|
After Width: | Height: | Size: 194 KiB |
|
After Width: | Height: | Size: 158 KiB |
|
After Width: | Height: | Size: 226 KiB |
|
After Width: | Height: | Size: 185 KiB |
|
After Width: | Height: | Size: 273 KiB |
|
After Width: | Height: | Size: 249 KiB |
|
After Width: | Height: | Size: 224 KiB |
|
After Width: | Height: | Size: 198 KiB |
@@ -0,0 +1,28 @@
|
|||||||
|
import { Showreel } from './Showreel';
|
||||||
|
|
||||||
|
export function Motivation() {
|
||||||
|
return (
|
||||||
|
<div className="pt-20">
|
||||||
|
<div className="space-y-12 mb-6">
|
||||||
|
<h1 className="h1 font-medium">
|
||||||
|
Создаем интерактивные
|
||||||
|
<span className="text-gradient"> выставочные решения</span>
|
||||||
|
</h1>
|
||||||
|
<div className="flex gap-x-5">
|
||||||
|
{[
|
||||||
|
{ solution: 'VR и AR', count: 12 },
|
||||||
|
{ solution: 'Интерактивные приложения', count: 21 },
|
||||||
|
{ solution: '3D макеты', count: 14 },
|
||||||
|
].map(({ count, solution }, index) => (
|
||||||
|
<p key={solution} className="h4 font-medium flex gap-x-[7px]">
|
||||||
|
{solution}
|
||||||
|
<sup className="text-xs">{count}</sup>
|
||||||
|
{index !== 2 && <span>/</span>}
|
||||||
|
</p>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Showreel />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
import { motion } from 'framer-motion';
|
||||||
|
import { Title } from './ui/Title';
|
||||||
|
import { promotionFeatures } from '../consts/promotionFeatures';
|
||||||
|
import { useRef } from 'react';
|
||||||
|
import { useHover } from 'usehooks-ts';
|
||||||
|
|
||||||
|
export function Promotion() {
|
||||||
|
return (
|
||||||
|
<div className="pt-[100px] space-y-20">
|
||||||
|
<Title className="max-w-[calc(1310/1600*100vw)]">
|
||||||
|
Повышаем количество посетителей на стенде,
|
||||||
|
<span className="text-gradient">
|
||||||
|
{' '}
|
||||||
|
помогаем продвигать ваш продукт и увеличиваем продажи на выставках
|
||||||
|
</span>
|
||||||
|
</Title>
|
||||||
|
<div>
|
||||||
|
{promotionFeatures.map((feature, index) => (
|
||||||
|
<Feature key={feature.title} number={index + 1} {...feature} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Feature({
|
||||||
|
description,
|
||||||
|
images,
|
||||||
|
number,
|
||||||
|
title,
|
||||||
|
}: {
|
||||||
|
number: number;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
images: string[];
|
||||||
|
}) {
|
||||||
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
const hovered = useHover(ref);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<motion.div
|
||||||
|
ref={ref}
|
||||||
|
className="border-t border-x border-[#3D425C] last:border-b flex justify-between gap-x-16 items-stretch p-7 transition-all overflow-hidden"
|
||||||
|
initial={{ height: 196 }}
|
||||||
|
animate={hovered ? { height: 480 } : { height: 196 }}
|
||||||
|
>
|
||||||
|
<div className="max-w-[calc(540/1600*100vw)]">
|
||||||
|
<div className="flex flex-col justify-between h-full">
|
||||||
|
<p className="l-text text-[#52587A] font-medium">[0{number}]</p>
|
||||||
|
<p className="h3 font-medium">{title}</p>
|
||||||
|
</div>
|
||||||
|
<motion.p
|
||||||
|
className="h4 opacity-60 font-medium mt-6"
|
||||||
|
animate={hovered ? { opacity: 0.6 } : { opacity: 0 }}
|
||||||
|
>
|
||||||
|
{description}
|
||||||
|
</motion.p>
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-x-2 justify-end self-start max-w-[calc(736/1600*100vw)]">
|
||||||
|
{images.map((image, index) => (
|
||||||
|
<motion.img
|
||||||
|
key={image}
|
||||||
|
src={image}
|
||||||
|
alt=""
|
||||||
|
className=""
|
||||||
|
initial={{ maxHeight: (140 / 1600) * window.innerWidth }}
|
||||||
|
animate={
|
||||||
|
index === 0 && hovered
|
||||||
|
? { minHeight: (424 / 1600) * window.innerWidth }
|
||||||
|
: { maxHeight: (140 / 1600) * window.innerWidth }
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { FullScreenIcon } from './icons/FullScreenIcon';
|
||||||
|
|
||||||
|
export function Showreel() {
|
||||||
|
return (
|
||||||
|
<div className="aspect-[1552/616] [background:linear-gradient(rgba(0,0,0,0.2),rgba(0,0,0,0.2)),center_url(src/assets/motivation/Showreel.png)] flex justify-center items-center">
|
||||||
|
<button className="p-[22px] rounded-full border bg-[#14161F33]">
|
||||||
|
<FullScreenIcon />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
export function FullScreenIcon() {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width="28"
|
||||||
|
height="28"
|
||||||
|
viewBox="0 0 28 28"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M6.31723 23.3335L11.3256 18.3251L9.67569 16.6752L4.66732 21.6836V16.6752L2.33398 19.0085V25.6668H8.99228L11.3256 23.3335H6.31723Z"
|
||||||
|
fill="white"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M23.334 6.31675V11.3251L25.6673 8.99179V2.3335L19.009 2.3335L16.6757 4.66683H21.6841L16.6757 9.6752L18.3256 11.3251L23.334 6.31675Z"
|
||||||
|
fill="white"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
|
interface ButtonProps {
|
||||||
|
children: ReactNode;
|
||||||
|
icon?: JSX.Element;
|
||||||
|
color?: 'primary' | 'secondary';
|
||||||
|
width?: 'fit' | 'full';
|
||||||
|
disabled?: boolean;
|
||||||
|
className?: string;
|
||||||
|
onClick?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Button({
|
||||||
|
children,
|
||||||
|
color = 'primary',
|
||||||
|
icon,
|
||||||
|
width = 'fit',
|
||||||
|
disabled = false,
|
||||||
|
className,
|
||||||
|
onClick,
|
||||||
|
}: ButtonProps) {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
disabled={disabled}
|
||||||
|
onClick={onClick}
|
||||||
|
className={`group relative px-6 py-2 rounded-full min-w-fit ${
|
||||||
|
(color === 'primary'
|
||||||
|
? 'bg-gradient-to-r from-[#798FFF] to-[#D375FF]'
|
||||||
|
: '') ||
|
||||||
|
(color === 'secondary' ? 'outline outline-1 outline-[#3D425C]' : '')
|
||||||
|
} ${
|
||||||
|
icon ? 'pr-4' : ''
|
||||||
|
} flex gap-1 items-center overflow-hidden w-${width} ${className} justify-between`}
|
||||||
|
>
|
||||||
|
<span className="group-hover:opacity-10 opacity-0 bg-black transition-opacity absolute top-0 left-0 w-full h-full"></span>
|
||||||
|
<span className={'relative font-medium' + (icon ? '' : ' m-auto')}>
|
||||||
|
{children}
|
||||||
|
</span>
|
||||||
|
<span className="relative">{icon}</span>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { PropsWithChildren } from 'react';
|
||||||
|
|
||||||
|
export function Title({
|
||||||
|
className = '',
|
||||||
|
children,
|
||||||
|
}: PropsWithChildren<{ className?: string }>) {
|
||||||
|
return <h1 className={'font-medium h2 ' + className}>{children}</h1>;
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import { IPromotionFeature } from '../types/IPromotionFeature';
|
||||||
|
|
||||||
|
export const promotionFeatures: IPromotionFeature[] = [
|
||||||
|
{
|
||||||
|
description:
|
||||||
|
'Ключевые преимущества жилого комплекса показаны на интерактивной модели. Для этого создается маршрут, демонстрирующий детали комплекса, важные для покупателя',
|
||||||
|
title: 'Интерактивные презентации',
|
||||||
|
images: [
|
||||||
|
'src/assets/promotion/presentations/1.png',
|
||||||
|
'src/assets/promotion/presentations/2.png',
|
||||||
|
'src/assets/promotion/presentations/3.png',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description:
|
||||||
|
'Ключевые преимущества жилого комплекса показаны на интерактивной модели. Для этого создается маршрут, демонстрирующий детали комплекса, важные для покупателя',
|
||||||
|
title: '3D интерактивные презентации техники и оборудования',
|
||||||
|
images: [
|
||||||
|
'src/assets/promotion/devices/1.png',
|
||||||
|
'src/assets/promotion/devices/2.png',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description:
|
||||||
|
'Ключевые преимущества жилого комплекса показаны на интерактивной модели. Для этого создается маршрут, демонстрирующий детали комплекса, важные для покупателя',
|
||||||
|
title: 'Интерактивный каталог продукции',
|
||||||
|
images: ['src/assets/promotion/catalog/1.png'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description:
|
||||||
|
'Ключевые преимущества жилого комплекса показаны на интерактивной модели. Для этого создается маршрут, демонстрирующий детали комплекса, важные для покупателя',
|
||||||
|
title: '3D интерактивные макеты',
|
||||||
|
images: [
|
||||||
|
'src/assets/promotion/templates/1.png',
|
||||||
|
'src/assets/promotion/templates/2.png',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description:
|
||||||
|
'Ключевые преимущества жилого комплекса показаны на интерактивной модели. Для этого создается маршрут, демонстрирующий детали комплекса, важные для покупателя',
|
||||||
|
title: 'Приложения с виртуальной и дополненной реальностью',
|
||||||
|
images: [
|
||||||
|
'src/assets/promotion/arvr/1.png',
|
||||||
|
'src/assets/promotion/arvr/2.png',
|
||||||
|
'src/assets/promotion/arvr/3.png',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description:
|
||||||
|
'Ключевые преимущества жилого комплекса показаны на интерактивной модели. Для этого создается маршрут, демонстрирующий детали комплекса, важные для покупателя',
|
||||||
|
title: 'Виртуальные выставки и метавселенные',
|
||||||
|
images: ['src/assets/promotion/exhibitions/1.png'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description:
|
||||||
|
'Ключевые преимущества жилого комплекса показаны на интерактивной модели. Для этого создается маршрут, демонстрирующий детали комплекса, важные для покупателя',
|
||||||
|
title: 'Мобильные приложения',
|
||||||
|
images: [
|
||||||
|
'src/assets/promotion/mobiles/1.png',
|
||||||
|
'src/assets/promotion/mobiles/2.png',
|
||||||
|
'src/assets/promotion/mobiles/3.png',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { ReactNode, useEffect, useRef } from 'react';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
element: ReactNode;
|
||||||
|
className: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ClassNameWrapper({ element, className }: Props) {
|
||||||
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!className.split(' ').length) return;
|
||||||
|
|
||||||
|
ref.current?.children
|
||||||
|
.item(0)
|
||||||
|
?.classList.add(...className.split(' ').filter(Boolean));
|
||||||
|
}, [className, element]);
|
||||||
|
|
||||||
|
return <div ref={ref}>{element}</div>;
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { useLayoutEffect, useState } from 'react';
|
||||||
|
|
||||||
|
export function useWindowWidth() {
|
||||||
|
const [width, setWidth] = useState(window.innerWidth);
|
||||||
|
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
const updateWidth = () => setWidth(window.innerWidth);
|
||||||
|
window.addEventListener('resize', updateWidth);
|
||||||
|
updateWidth();
|
||||||
|
return () => window.removeEventListener('resize', updateWidth);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return width;
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
@import url('/fonts/TTHovesProAll/stylesheet.css');
|
||||||
|
|
||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'TTHovesPro';
|
||||||
|
color: #fff;
|
||||||
|
background-color: #14161f;
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer components {
|
||||||
|
.h1 {
|
||||||
|
@apply -tracking-[.02em] text-[clamp(36px,36px+(100vw-360px)/1240*76,112px)] leading-[clamp(36px,36px+(100vw-360px)/1240*50.4,86.4px)];
|
||||||
|
}
|
||||||
|
.h2 {
|
||||||
|
@apply -tracking-[.02em] text-[clamp(24px,24px+(100vw-360px)/1240*48,72px)] leading-none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.h3 {
|
||||||
|
@apply text-[clamp(18px,18px+(100vw-360px)/1240*22,40px)] leading-[clamp(22px,22px+(100vw-360px)/1240*6.8,28.8px)];
|
||||||
|
}
|
||||||
|
|
||||||
|
.h4 {
|
||||||
|
@apply text-[clamp(14px,14px+(100vw-360px)/1240*6,20px)] leading-[clamp(17.6px,17.6px+(100vw-360px)/1240*6.4,24px)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* .accent {
|
||||||
|
@apply -tracking-[.02em] md:text-[clamp(28px,28px+(100vw-768px)/832*4,32px)] text-[clamp(20px,20px+(100vw-360px)/408*8,28px)] md:leading-[clamp(28px,28px+(100vw-768px)/832*7.2,35.2px)] leading-[clamp(20px,20px+(100vw-360px)/408*8,28px)];
|
||||||
|
} */
|
||||||
|
|
||||||
|
.l-text {
|
||||||
|
@apply text-[clamp(14px,14px+(100vw-360px)/1240*6,20px)] leading-[clamp(21.6px,21.6px+(100vw-360px)/1240*5.4,27px)];
|
||||||
|
}
|
||||||
|
|
||||||
|
.m-text {
|
||||||
|
@apply text-[clamp(12px,12px+(100vw-360px)/1240*4,16px)] leading-[clamp(19.6px,19.6px+(100vw-360px)/1240*2.4,22.4px)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* .l-caption {
|
||||||
|
@apply text-[clamp(14px,14px+(100vw-360px)/1240*2,16px)] leading-none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.m-caption {
|
||||||
|
@apply text-[clamp(10px,10px+(100vw-360px)/1240*2,12px)] leading-[clamp(12px,12px+(100vw-360px)/1240*2.4,14.4px)];
|
||||||
|
} */
|
||||||
|
|
||||||
|
.btn-text {
|
||||||
|
@apply -tracking-[.01em] text-[clamp(12px,12px+(100vw-360px)/1240*8,20px)] leading-none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-text {
|
||||||
|
@apply text-[clamp(12px,12px+(100vw-360px)/1240*4,16px)] tracking-[.02em];
|
||||||
|
}
|
||||||
|
|
||||||
|
.descriptor {
|
||||||
|
@apply text-[clamp(14px,14px+(100vw-360px)/1240*2,16px)] leading-[clamp(15.6px,15.6px+(100vw-360px)/1240*2.6,18.2px)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* .feedback-field:focus ~ .feedback-placeholder {
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feedback-field:focus ~ .feedback-placeholder-2 {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feedback-field:valid ~ .feedback-placeholder {
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feedback-field:valid ~ .feedback-placeholder-2 {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feedback-field::placeholder {
|
||||||
|
@apply lg:text-base text-sm font-semibold text-[#77787d];
|
||||||
|
} */
|
||||||
|
|
||||||
|
.text-gradient {
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
@apply bg-gradient-to-r from-[#798FFF] to-[#D375FF] bg-clip-text;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { createRoot } from 'react-dom/client';
|
||||||
|
import './index.css';
|
||||||
|
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
|
||||||
|
import { Layout } from './Layout';
|
||||||
|
import { MainPage } from './pages/MainPage';
|
||||||
|
|
||||||
|
createRoot(document.getElementById('root')!).render(
|
||||||
|
<RouterProvider
|
||||||
|
router={createBrowserRouter([
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
Component: Layout,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
index: true,
|
||||||
|
Component: MainPage,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
])}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { Motivation } from '../components/Motivation';
|
||||||
|
import { Promotion } from '../components/Promotion';
|
||||||
|
|
||||||
|
export function MainPage() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Motivation />
|
||||||
|
<Promotion />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export interface IPromotionFeature {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
images: string[];
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
/// <reference types="vite/client" />
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
export default {
|
||||||
|
content: [
|
||||||
|
"./index.html",
|
||||||
|
"./src/**/*.{js,ts,jsx,tsx}",
|
||||||
|
],
|
||||||
|
theme: {
|
||||||
|
extend: {},
|
||||||
|
},
|
||||||
|
plugins: [],
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2020",
|
||||||
|
"useDefineForClassFields": true,
|
||||||
|
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||||
|
"module": "ESNext",
|
||||||
|
"skipLibCheck": true,
|
||||||
|
|
||||||
|
/* Bundler mode */
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"moduleDetection": "force",
|
||||||
|
"noEmit": true,
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
|
||||||
|
/* Linting */
|
||||||
|
"strict": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"noFallthroughCasesInSwitch": true
|
||||||
|
},
|
||||||
|
"include": ["src"]
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"files": [],
|
||||||
|
"references": [
|
||||||
|
{ "path": "./tsconfig.app.json" },
|
||||||
|
{ "path": "./tsconfig.node.json" }
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2022",
|
||||||
|
"lib": ["ES2023"],
|
||||||
|
"module": "ESNext",
|
||||||
|
"skipLibCheck": true,
|
||||||
|
|
||||||
|
/* Bundler mode */
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"moduleDetection": "force",
|
||||||
|
"noEmit": true,
|
||||||
|
|
||||||
|
/* Linting */
|
||||||
|
"strict": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"noFallthroughCasesInSwitch": true
|
||||||
|
},
|
||||||
|
"include": ["vite.config.ts"]
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import react from '@vitejs/plugin-react'
|
||||||
|
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [react()],
|
||||||
|
})
|
||||||