front init

This commit is contained in:
Daniil
2026-01-12 23:06:40 +03:00
parent b1d3e89988
commit 749fda017c
27 changed files with 2322 additions and 148 deletions
+98
View File
@@ -0,0 +1,98 @@
import { mkdir, rename, rm } from "node:fs/promises"
const segments = "ui,model,api"
const args = Bun.argv.slice(2)
function printUsageAndExit(): never {
console.error(
"Ошибка: Необходимо указать <название слоя> и <название компонента>",
)
console.log("Пример: bun gc features MyButton")
process.exit(1)
}
function runShell(command: string): void {
console.log(`Выполняется: ${command}`)
const result = Bun.spawnSync({
cmd: ["sh", "-lc", command],
stdin: "inherit",
stdout: "inherit",
stderr: "inherit",
})
if (result.exitCode !== 0) {
const suffix = result.signalCode ? ` (signal ${result.signalCode})` : ""
throw new Error(`Команда завершилась с кодом ${result.exitCode}${suffix}`)
}
}
if (args.length < 2) {
printUsageAndExit()
}
const layer = args[0]
const component = args[1]
const otherArgs = args.slice(2).join(" ")
let componentPath = "./src/"
if (layer === "shared" || layer === "app") {
componentPath += `${layer}/${component}`
} else if (layer === "entity" || layer === "entities") {
componentPath += `entities/${component}`
} else {
componentPath += `${layer}s/${component}`
}
const fsdCommand = `fsd ${layer} ${component} ${otherArgs} --segments ${segments} -r src`
try {
runShell(fsdCommand)
} catch (error) {
console.error(`Ошибка выполнения команды: ${(error as Error).message}`)
process.exit(1)
}
console.log(`Удаление индекс файла: ${componentPath}/index.ts`)
try {
await rm(`${componentPath}/index.ts`)
} catch (error) {
console.error(`Ошибка выполнения команды: ${(error as Error).message}`)
process.exit(1)
}
const createTsx = `bunx generate-react-cli component ${component} --flat --path ${componentPath}`
try {
runShell(createTsx)
} catch (error) {
console.error(`Ошибка выполнения команды: ${(error as Error).message}`)
process.exit(1)
}
console.log("Перемещение файлов...")
const oldPath = `${componentPath}/${component}`
const newPath = `${componentPath}`
try {
await mkdir(`${newPath}/ui`, { recursive: true })
await mkdir(`${newPath}/model`, { recursive: true })
await rename(`${oldPath}.tsx`, `${newPath}/ui/${component}.tsx`)
console.log("TSX файл перемещен")
await rename(
`${oldPath}.module.scss`,
`${newPath}/ui/${component}.module.scss`,
)
console.log("SCSS файл перемещен")
await rename(`${oldPath}.d.ts`, `${newPath}/model/${component}.d.ts`)
console.log("D.TS файл перемещен")
} catch (error) {
console.error(`Ошибка выполнения команды: ${(error as Error).message}`)
process.exit(1)
}
+3
View File
@@ -0,0 +1,3 @@
export interface ITemplateNameProps {
message?: string
}
@@ -0,0 +1,2 @@
.root {
}
+16
View File
@@ -0,0 +1,16 @@
import type { JSX } from "react"
import { FunctionComponent } from "react"
import { ITemplateNameProps } from "../model/TemplateName.d"
import styles from "./TemplateName.module.scss"
export const TemplateName: FunctionComponent<
ITemplateNameProps
> = (): JSX.Element => {
return (
<div className={styles.root} data-testid="TemplateName">
TemplateName Component
</div>
)
}
+1
View File
@@ -0,0 +1 @@
export * from "./ui/TemplateName"
+217
View File
@@ -0,0 +1,217 @@
# AGENTS.md — Coffee Project Frontend
## Project Overview
Next.js 16 application using **Feature-Sliced Design (FSD)** architecture, powered by **Bun** runtime and package manager.
---
## Tech Stack
| Category | Technology |
| ------------- | ------------------------------------------ |
| Runtime | Bun 1.3.5 |
| Framework | Next.js 16.1.1 (App Router) |
| Language | TypeScript 5.9 |
| UI Library | React 19 |
| Styling | SCSS Modules, normalize.css |
| State/Fetch | TanStack React Query 5, Axios, Xior |
| Animation | Framer Motion |
| Utilities | Lodash, Moment.js, classnames, usehooks-ts |
| Icons | Lucide React, SVGR (custom icons) |
| Notifications | React Toastify |
| File Upload | React Dropzone |
| Linting | ESLint 9, Prettier, Stylelint |
| Testing | Jest, Testing Library |
---
## Commands
```bash
bun dev # Start dev server
bun run build # Production build
bun run start # Start production server
bun run lint # Run ESLint + Prettier
bun run gc <layer> <ComponentName> # Generate FSD component
bun run gicons # Convert SVGs to React components
```
---
## Project Structure (FSD)
```
app/ # Next.js App Router entry
pages/ # Keep empty (Next.js requires it)
public/ # Static assets
src/
├── app/ # App layer: global styles, providers
├── pages/ # Page compositions
├── widgets/ # Large UI blocks (header, sidebar)
├── features/ # User interactions (auth, search)
├── entities/ # Business entities (user, product)
└── shared/ # Reusable: UI kit, utils, API, assets
├── ui/ # Button, Input, Icons...
├── api/ # API clients
├── lib/ # Utilities
└── assets/ # Images, raw-icons
```
### Path Aliases
```ts
@app/* ./src/app/*
@pages/* ./src/pages/*
@widgets/* ./src/widgets/*
@features/* ./src/features/*
@entities/* ./src/entities/*
@shared/* ./src/shared/*
@/* ./src/*
```
---
## Component Structure
Each component follows FSD slice structure:
```
ComponentName/
├── index.ts # Public API (re-export)
├── ui/
│ ├── ComponentName.tsx
│ └── ComponentName.module.scss
├── model/
│ └── ComponentName.d.ts # Props interface
└── api/ # Optional: component-specific API
```
### Component Template
```tsx
import type { JSX } from "react"
import { FunctionComponent } from "react"
import { IComponentNameProps } from "../model/ComponentName.d"
import styles from "./ComponentName.module.scss"
export const ComponentName: FunctionComponent<
IComponentNameProps
> = (): JSX.Element => {
return (
<div className={styles.root} data-testid="ComponentName">
ComponentName
</div>
)
}
```
### Generate Component
```bash
bun run gc <layer> <ComponentName>
# Examples:
bun run gc shared Button
bun run gc features AuthForm
bun run gc entities UserCard
```
---
## Best Practices
### Code Style
1. **Small Functions** — max 20-30 lines; extract helpers
2. **Single Responsibility** — one function = one purpose
3. **Descriptive Names**`getUserById` not `getData`
4. **Early Returns** — reduce nesting with guard clauses
5. **No Magic Values** — use constants: `const MAX_ITEMS = 10`
### TypeScript
```ts
// ✅ Use interfaces for props
interface IButtonProps {
variant: "primary" | "secondary"
disabled?: boolean
onClick: () => void
}
// ✅ Prefer explicit types over `any`
// ✅ Use `type` for unions/intersections, `interface` for objects
```
### React Patterns
```tsx
// ✅ Functional components with explicit return type
export const Button: FC<IButtonProps> = ({ variant, onClick }): JSX.Element => { ... }
// ✅ Destructure props
// ✅ Use data-testid for testing
// ✅ Colocate styles with components (CSS Modules)
```
### FSD Rules
1. **Import Direction** — only downward: `features → entities → shared`
2. **Public API** — export only through `index.ts`
3. **No Cross-Slice Imports** — features cannot import from other features
4. **Shared is Agnostic** — no business logic in shared layer
### File Naming
| Type | Convention | Example |
| --------- | ----------------- | ---------------------- |
| Component | PascalCase | `UserCard.tsx` |
| Module | PascalCase.module | `UserCard.module.scss` |
| Types | PascalCase.d | `UserCard.d.ts` |
| Hook | camelCase (use-) | `useAuth.ts` |
| Utility | camelCase | `formatDate.ts` |
| Constant | UPPER_SNAKE_CASE | `API_ENDPOINTS.ts` |
### Performance
1. Use `React.memo` for expensive renders
2. Use `useMemo` / `useCallback` for derived data and callbacks
3. Lazy load pages/heavy components with `next/dynamic`
4. Prefer server components where possible (Next.js App Router)
### Testing
- Place tests next to components: `ComponentName.test.tsx`
- Use `data-testid` attributes for queries
- Test behavior, not implementation
---
## Icons Workflow
1. Place raw SVG in `src/shared/assets/raw-icons/`
2. Run `bun run gicons`
3. Import from `@shared/ui/Icons/IconName`
---
## Notes
- **Keep `pages/` folder** in root — removing causes Next.js build errors
- **Bun only** — use `bun` commands, not npm/yarn
- **SCSS Modules** — all styles are scoped via `.module.scss`
- **Strict TypeScript** — `strict: true` in tsconfig
---
## Quick Reference
| Task | Command / Location |
| ------------------ | ------------------------------- |
| Add dependency | `bun add <package>` |
| Add dev dependency | `bun add -d <package>` |
| Create component | `bun run gc <layer> <Name>` |
| Global styles | `src/app/styles/global.scss` |
| API client | Use Axios/Xior with React Query |
| State management | TanStack Query (server state) |
+8 -41
View File
@@ -1,23 +1,13 @@
# Next.js + Feature-Sliced Design | Pure Template # Coffee Project Frontend
## IMPORTANT Next.js application structured with Feature-Sliced Design and configured to run with Bun.
Do not delete the pages\* folder even if you are using App Router, deleting the pages folder ## Notes
will result in a [build error](https://t.me/feature_sliced/1/107414).
In WebStorm you can mark a directory as [excluded](https://www.jetbrains.com/help/webstorm/configuring-project-structure.html#content-root). After that, you wont see it in shared files (like, for example, node_modules or .next) - Keep the `pages` folder in the project root; removing it can cause a build error with Next.js.
- Bun is the package manager: `bun install`, `bun dev`, `bun run build`, `bun run lint`.
## ADDITIONAL SOLUTION TO THE PROBLEM (NOT RECOMMENDED) ## Folders
If you don't like the empty "pages" folder in the project root, you can rename the pages layer (./src/pages)
for example to "pagesLayer" and then delete the pages folder from the project root
(you will also have to change path aliases in tsconfig and similar).
**Use what you like best <3**
---
## Folders description
| Folder | Description | | Folder | Description |
| ------------ | --------------------------------------------------------------------------------------------------------------- | | ------------ | --------------------------------------------------------------------------------------------------------------- |
@@ -31,31 +21,8 @@ for example to "pagesLayer" and then delete the pages folder from the project ro
| src/entities | Entities FSD Layer | | src/entities | Entities FSD Layer |
| src/shared | Shared FSD Layer | | src/shared | Shared FSD Layer |
## Remove junk _.gitkeep_ files ## Tooling
### UNIX - ESLint
```bash
rm -rf .src/app/.gitkeep .src/entities/.gitkeep .src/features/.gitkeep .src/shared/.gitkeep .src/widgets/.gitkeep ./public/.gitkeep
```
### WINDOWS
```bash
del .\src\app\.gitkeep
del .\src\entities\.gitkeep
del .\src\features\.gitkeep
del .\src\shared\.gitkeep
del .\src\widgets\.gitkeep
del .\public\.gitkeep
```
This template uses such development assistants
- Eslint
- Prettier - Prettier
- Stylelint - Stylelint
- Jest
If you don't need it, you can disable it at any time by removing the
dependency from your _package.json_ and _.\*rc_ file.
+4 -3
View File
@@ -1,11 +1,12 @@
import type { Metadata } from "next" import type { Metadata } from "next"
import type { ReactNode } from "react" import type { ReactNode } from "react"
import "@app/styles/global.scss" import "@shared/styles/global.scss"
import "bootstrap/dist/css/bootstrap.min.css"
export const metadata: Metadata = { export const metadata: Metadata = {
title: "Let's Develop!", title: "Coffee Project",
description: "FSD Template with Next.js by yunglocokid", description: "Standalone Next.js app using FSD structure",
} }
export default function RootLayout({ export default function RootLayout({
+1601
View File
File diff suppressed because it is too large Load Diff
+24
View File
@@ -0,0 +1,24 @@
{
"usesTypeScript": true,
"usesStyledComponents": false,
"usesCssModule": true,
"cssPreprocessor": "scss",
"testLibrary": "Testing Library",
"component": {
"default": {
"path": "src/shared",
"withStyle": true,
"withTest": false,
"withStory": false,
"withLazy": false,
"withIndex": true,
"withTypeDeclare": true,
"customTemplates": {
"index": ".templates/component/index.ts",
"component": ".templates/component/TemplateName.tsx",
"typeDeclare": ".templates/component/TemplateName.d.ts",
"style": ".templates/component/TemplateName.module.scss"
}
}
}
}
+16 -1
View File
@@ -1,4 +1,19 @@
/** @type {import('next').NextConfig} */ /** @type {import('next').NextConfig} */
const nextConfig = {} import path from "path"
import { fileURLToPath } from "url"
const dirname = path.dirname(fileURLToPath(import.meta.url))
const stylesPath = path.join(dirname, "src/shared/styles")
console.log("dirname", dirname)
const nextConfig = {
sassOptions: {
includePaths: [stylesPath],
additionalData: `@use "${path.join(stylesPath, "_variables.scss")}";
@use "${path.join(stylesPath, "_breakpoints.scss")}";
@use "${path.join(stylesPath, "_typography.scss")}";
@use "${path.join(stylesPath, "_mixins.scss")}";`,
},
}
export default nextConfig export default nextConfig
+49 -41
View File
@@ -1,54 +1,62 @@
{ {
"name": "fsd-nest-template", "name": "fsd-nest-template",
"description": "Pure Next.js FSD template with jest, react testing lib, stylelint, prettier and eslint",
"author": {
"name": "@yunglocokid (Dmitriy Bratchikov)",
"url": "https://github.com/yunglocokid"
},
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"packageManager": "bun@1.3.5",
"scripts": { "scripts": {
"dev": "next dev", "dev": "bun --bun next dev",
"build": "next build", "build": "bun --bun next build",
"start": "next start", "start": "bun --bun next start",
"lint": "concurrently \"yarn lint:es\" \"yarn lint:prettier\"", "lint": "concurrently \"bun run lint:es\" \"bun run lint:prettier\"",
"lint:es": "next lint", "create-component": "npx generate-react-cli component",
"lint:prettier": "prettier . --write", "gc": "bun run .scripts/create-fsd-component.ts",
"test": "jest", "gicons": "npx @svgr/cli --ext tsx --typescript --no-prettier --icon --ref --no-svgo ./src/shared/assets/raw-icons/ --out-dir ./src/shared/ui/Icons/"
"test:watch": "jest --watch"
}, },
"dependencies": { "dependencies": {
"next": "14.2.3", "@tanstack/react-query": "^5.90.14",
"@tanstack/react-query-devtools": "^5.91.2",
"axios": "^1.13.2",
"bootstrap": "^5.3.8",
"classnames": "^2.5.1",
"framer-motion": "^12.23.26",
"lodash": "^4.17.21",
"lucide-react": "^0.562.0",
"moment": "^2.30.1",
"next": "16.1.1",
"normalize.css": "^8.0.1", "normalize.css": "^8.0.1",
"react": "^18", "openapi-react-query": "^0.5.1",
"react-dom": "^18" "react": "^19.2.3",
"react-aria-components": "^1.14.0",
"react-bootstrap": "^2.10.10",
"react-dom": "^19.2.3",
"react-dropzone": "^14.3.8",
"react-toastify": "^11.0.5",
"usehooks-ts": "^3.1.1",
"xior": "^0.8.2"
}, },
"devDependencies": { "devDependencies": {
"@ianvs/prettier-plugin-sort-imports": "^4.2.1", "@ianvs/prettier-plugin-sort-imports": "^4.7.0",
"@testing-library/jest-dom": "^6.4.5", "@svgr/cli": "^8.1.0",
"@testing-library/react": "^15.0.7", "@types/bun": "^1.3.5",
"@types/jest": "^29.5.12", "@types/node": "^25.0.3",
"@types/node": "^20", "@types/react": "^19.2.7",
"@types/react": "^18", "@types/react-dom": "^19.2.3",
"@types/react-dom": "^18", "concurrently": "^9.2.1",
"concurrently": "^8.2.2", "eslint": "^9.39.2",
"eslint": "^8", "eslint-config-next": "16.1.1",
"eslint-config-next": "14.2.3", "eslint-import-resolver-typescript": "^4.4.4",
"eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-boundaries": "^5.3.1",
"eslint-plugin-boundaries": "^4.2.1", "eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react-hooks": "^4.6.2", "eslint-plugin-react-refresh": "^0.4.26",
"eslint-plugin-react-refresh": "^0.4.7", "prettier": "^3.7.4",
"jest": "^29.7.0", "sass": "^1.97.1",
"jest-environment-jsdom": "^29.7.0", "stylelint": "^16.26.1",
"prettier": "^3.2.5", "stylelint-config-standard": "^39.0.1",
"sass": "^1.77.1", "stylelint-config-standard-scss": "^16.0.0",
"stylelint": "^16.5.0", "stylelint-order": "^7.0.0",
"stylelint-config-standard": "^36.0.0",
"stylelint-config-standard-scss": "^13.1.0",
"stylelint-order": "^6.0.4",
"stylelint-order-config-standard": "^0.1.3", "stylelint-order-config-standard": "^0.1.3",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"typescript": "^5", "typescript": "^5.9.3",
"typescript-eslint": "^7.10.0" "typescript-eslint": "^8.50.1"
} }
} }
-9
View File
@@ -1,9 +0,0 @@
@import "normalize.css";
* {
box-sizing: border-box;
margin: 0;
padding: 0;
border: 0;
}
+3 -32
View File
@@ -13,15 +13,15 @@
font-family: Roboto, sans-serif; font-family: Roboto, sans-serif;
font-size: 2vw; font-size: 2vw;
font-weight: bold;
} }
.path { .path {
font-style: italic; font-style: italic;
} }
.font { .title {
font-size: 5vw; font-size: 4vw;
font-weight: 700;
} }
.hint { .hint {
@@ -34,32 +34,3 @@
font-size: 1vw; font-size: 1vw;
} }
.testHint {
margin: 0 30px;
}
.link {
transition: 0.3s;
animation: shine 4s linear infinite;
color: #000;
background: linear-gradient(
to right,
#020024 10%,
#5b0979 40%,
#5b0979 60%,
#020024 80%
);
background-clip: text;
background-size: 200% auto;
font-size: 5vw;
-webkit-text-fill-color: transparent;
@keyframes shine {
to {
background-position: 200% center;
}
}
}
+6 -17
View File
@@ -1,27 +1,16 @@
import Link from "next/link" import { Button } from "@shared/ui"
import cls from "./HomePage.module.scss" import cls from "./HomePage.module.scss"
const HomePage = () => { const HomePage = () => {
return ( return (
<div className={cls.homepage}> <div className={cls.homepage}>
<p className={cls.font}> <p className={cls.title}>Coffee Project Starter</p>
Hello from{" "} <pre className={cls.hint}>
<Link Edit <span className={cls.path}>src/pages/HomePage</span> to begin
href="https://github.com/yunglocokid" building your features.
target="_blank"
className={cls.link}
>
yunglocokid
</Link>
</p>
<pre className={cls.hint} data-testid="hint-code">
You can edit <span className={cls.path}>src/pages/HomePage</span> to
start {"<3"}!<br />
<small className={cls.testHint}>
You can also test your application using Jest :D. Try it!
</small>
</pre> </pre>
<Button variant="primary">Get Started</Button>
</div> </div>
) )
} }
+45
View File
@@ -0,0 +1,45 @@
@use "sass:map";
@use "sass:meta";
$mobile: 767;
$tablet: 1439;
$desktopSecond: 1919;
$mobileMin: "mobileMin";
$mobileMax: "mobileMax";
$tabletMin: "tabletMin";
$tabletMax: "tabletMax";
$desktopSecondMin: "desktopSecondMin";
$desktopSecondMax: "desktopSecondMax";
$breakpoints: (
"mobileMin": (
min-width: $mobile + 1 + px
),
"mobileMax": (
max-width: $mobile + px
),
"tabletMin": (
min-width: $tablet + 1 + px
),
"tabletMax": (
max-width: $tablet + px
),
"desktopSecondMin": (
min-width: $desktopSecond + 1 + px
),
"desktopSecondMax": (
max-width: $desktopSecond + px
)
) !default;
@mixin respond-to($breakpoint) {
@if map.has-key($breakpoints, $breakpoint) {
@media #{meta.inspect(map.get($breakpoints, $breakpoint))} {
@content;
}
} @else {
@warn "Unfortunately, no value could be retrieved from `#{$breakpoint}`. "
+ "Available breakpoints are: #{map.keys($breakpoints)}.";
}
}
+51
View File
@@ -0,0 +1,51 @@
// Common mixins for the project
// Flexbox center
@mixin flex-center {
display: flex;
align-items: center;
justify-content: center;
}
// Flexbox column
@mixin flex-column {
display: flex;
flex-direction: column;
}
// Truncate text with ellipsis
@mixin text-ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
// Visually hidden (accessible)
@mixin visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
// Reset button styles
@mixin reset-button {
padding: 0;
border: none;
background: none;
cursor: pointer;
font: inherit;
color: inherit;
}
// Reset list styles
@mixin reset-list {
margin: 0;
padding: 0;
list-style: none;
}
+49
View File
@@ -0,0 +1,49 @@
@mixin font-header-l {
font-variant-numeric: lining-nums proportional-nums;
font-weight: 500;
font-size: 20px;
line-height: 26px;
letter-spacing: -0.41px;
}
@mixin font-subheader-l {
font-weight: 500;
font-size: 16px;
line-height: 22px;
letter-spacing: 0px;
}
@mixin font-body-m {
font-weight: 500;
font-size: 16px;
line-height: 22px;
letter-spacing: 0px;
}
@mixin font-body-mm {
font-weight: 500;
font-size: 16px;
line-height: 22px;
letter-spacing: 0px;
}
@mixin font-body-mr {
font-weight: 400;
font-size: 16px;
line-height: 22px;
letter-spacing: 0px;
}
@mixin font-body-s {
font-weight: 400;
font-size: 14px;
line-height: 20px;
letter-spacing: 0px;
}
@mixin font-caption-m {
font-weight: 400;
font-size: 12px;
line-height: 18px;
letter-spacing: 0px;
}
+33
View File
@@ -0,0 +1,33 @@
$purple-50: var(--purple-50);
$purple-100: var(--purple-100);
$purple-200: var(--purple-200);
$purple-300: var(--purple-300);
$purple-400: var(--purple-400);
$purple-500: var(--purple-500);
$purple-600: var(--purple-600);
$purple-700: var(--purple-700);
$purple-800: var(--purple-800);
$purple-900: var(--purple-900);
$green-50: var(--green-50);
$green-100: var(--green-100);
$green-200: var(--green-200);
$green-300: var(--green-300);
$green-400: var(--green-400);
$green-500: var(--green-500);
$green-600: var(--green-600);
$green-700: var(--green-700);
$green-800: var(--green-800);
$green-900: var(--green-900);
$color-success: var(--color-success);
$color-danger: var(--color-danger);
$color-warning: var(--color-warning);
$color-primary: var(--color-primary);
$color-secondary: var(--color-secondary);
$color-white: var(--color-white);
$color-black: var(--color-black);
$header-height: var(--header-height);
+59
View File
@@ -0,0 +1,59 @@
@import "normalize.css";
* {
box-sizing: border-box;
margin: 0;
padding: 0;
border: 0;
font-family: var(--font-roboto);
font-variant-numeric: lining-nums proportional-nums;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
font-variation-settings: "opsz" 10;
}
body {
background-color: #f8f8f8;
}
:root {
/* Dark Fuchsia Palette (HSL) */
--purple-50: hsl(300, 52%, 93%);
--purple-100: hsl(298, 46%, 82%);
--purple-200: hsl(298, 51%, 69%);
--purple-300: hsl(297, 53%, 56%);
--purple-400: hsl(297, 70%, 44%); /* Primary */
--purple-500: hsl(296, 100%, 35%);
--purple-600: hsl(293, 100%, 34%);
--purple-700: hsl(288, 100%, 33%);
--purple-800: hsl(283, 100%, 32%);
--purple-900: hsl(272, 100%, 30%);
/* Deep Lime Green Palette (HSL) */
--green-50: hsl(84, 50%, 94%);
--green-100: hsl(85, 48%, 83%);
--green-200: hsl(86, 47%, 73%);
--green-300: hsl(85, 47%, 61%);
--green-400: hsl(85, 51%, 53%);
--green-500: hsl(84, 67%, 43%);
--green-600: hsl(87, 71%, 39%);
--green-700: hsl(88, 79%, 33%);
--green-800: hsl(90, 93%, 26%); /* Secondary */
--green-900: hsl(104, 100%, 19%);
--color-success: #22c55e;
--color-danger: #ef4444;
--color-warning: #facc15;
--color-primary: var(--purple-400);
--color-secondary: var(--green-800);
--color-white: #ffffff;
--color-black: #000000;
--header-height: 56px;
}
+15
View File
@@ -0,0 +1,15 @@
.app {
width: 100%;
// max-width: 1192px;
margin: 0 auto;
padding: 16px;
padding-top: 24px;
box-sizing: border-box;
height: calc(100vh - var(--header-height) - 16px);
margin-top: var(--header-height);
@include breakpoints.respond-to(breakpoints.$mobileMax) {
padding-top: 12px;
height: calc(100svh - var(--header-height));
}
}
+3
View File
@@ -0,0 +1,3 @@
export interface IButtonProps {
message?: string
}
+7
View File
@@ -0,0 +1,7 @@
import BootstrapButton, { ButtonProps } from "react-bootstrap/Button"
export const Button = (props: ButtonProps) => (
<BootstrapButton variant="primary" {...props}>
{props.children}
</BootstrapButton>
)
+1
View File
@@ -0,0 +1 @@
export * from "./Button"
+1
View File
@@ -0,0 +1 @@
export * from "./Button"
+10 -4
View File
@@ -10,7 +10,7 @@
"moduleResolution": "bundler", "moduleResolution": "bundler",
"resolveJsonModule": true, "resolveJsonModule": true,
"isolatedModules": true, "isolatedModules": true,
"jsx": "preserve", "jsx": "react-jsx",
"incremental": true, "incremental": true,
"plugins": [ "plugins": [
{ {
@@ -24,10 +24,16 @@
"@pages/*": ["./src/pages/*"], "@pages/*": ["./src/pages/*"],
"@shared/*": ["./src/shared/*"], "@shared/*": ["./src/shared/*"],
"@widgets/*": ["./src/widgets/*"], "@widgets/*": ["./src/widgets/*"],
"@/*": ["./src/*"] "@/*": ["./src/*"]
} },
"target": "ES2017"
}, },
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], "include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
".next/dev/types/**/*.ts"
],
"exclude": ["node_modules"] "exclude": ["node_modules"]
} }