Initial commit

parents
# 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?
# 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,
},
})
```
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 },
],
},
},
)
<!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>
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "firebase",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview"
},
"dependencies": {
"antd": "^5.23.1",
"axios": "^1.7.9",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-router-dom": "^7.1.1",
"sass": "^1.83.4"
},
"devDependencies": {
"@eslint/js": "^9.17.0",
"@types/react": "^18.3.18",
"@types/react-dom": "^18.3.5",
"@vitejs/plugin-react": "^4.3.4",
"eslint": "^9.17.0",
"eslint-plugin-react-hooks": "^5.0.0",
"eslint-plugin-react-refresh": "^0.4.16",
"globals": "^15.14.0",
"typescript": "~5.6.2",
"typescript-eslint": "^8.18.2",
"vite": "^6.0.5"
}
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
\ No newline at end of file
import axios from 'axios'
export const axiosBase = axios.create({
baseURL: 'https://ajs-21-default-rtdb.firebaseio.com/'
})
\ No newline at end of file
import { IEducation, IEducations } from "../Interfaces/education";
export const parserEducations = (data?: IEducation): IEducations[] => {
if(data) {
return Object.keys(data).map((key) => {
return {
id: key,
value: data[key]
}
})
} else {
return []
}
}
\ No newline at end of file
import { axiosBase } from "../Config/axiosBase"
import { notification } from 'antd'
import { IHome } from "../Interfaces/home"
import { IAboutMe } from "../Interfaces/aboutMe"
import { IEducation } from "../Interfaces/education"
class ApiConnector {
public static async getHome() {
try {
const {data} = await axiosBase.get<Promise<IHome>>('home.json')
return data
} catch {
notification.error({
message: 'Ошибка при запросе на HOME'
})
}
}
public static async getAboutMe() {
try {
const {data} = await axiosBase.get<Promise<IAboutMe>>('aboutme.json')
return data
} catch {
notification.error({
message: 'Ошибка при запросе на ABOUT ME'
})
}
}
public static async getEducations() {
try {
const {data} = await axiosBase.get<Promise<IEducation>>('educations.json')
return data
} catch {
notification.error({
message: 'Ошибка при запросе на EDUCATIONS'
})
}
}
public static async getEducation(id?: string) {
try {
const {data} = await axiosBase.get<Promise<string>>(`educations/${id}.json`)
return data
} catch {
notification.error({
message: 'Ошибка при запросе на EDUCATION'
})
}
}
}
export default ApiConnector
\ No newline at end of file
export interface IAboutMe {
info: string
}
\ No newline at end of file
export interface IEducation {
[key: string]: string
}
export interface IEducations {
id: string
value: string
}
\ No newline at end of file
export interface IHome {
promo: {
content: string
title: string
}
}
\ No newline at end of file
import { useEffect, useState } from "react"
import ApiConnector from "../../Integrations/api.connector"
import { IAboutMe } from "../../Interfaces/aboutMe"
import { Row, Typography } from "antd"
const AboutMe = () => {
const [aboutMe, setAboutMe] = useState<IAboutMe | null>(null)
const getData = async () => {
const data = await ApiConnector.getAboutMe()
setAboutMe(data || null)
}
useEffect(() => {
getData()
}, [])
return (
<Row>
<Typography.Title>
{aboutMe?.info}
</Typography.Title>
</Row>
)
}
export default AboutMe
\ No newline at end of file
import {BrowserRouter, Routes, Route} from 'react-router-dom'
import Home from './Home/Home'
import AboutMe from './AboutMe/AboutMe'
import Educations from './Educations/Educations'
import Education from './Education/Education'
import CustomeLayout from './Layout/Layout'
const App = () => (
<BrowserRouter>
<Routes>
<Route path='/' element={<CustomeLayout/>}>
<Route index element={<Home/>}/>
<Route path='/aboutMe' element={<AboutMe/>}/>
<Route path='/education' element={<Educations/>}/>
<Route path='/education/:id' element={<Education/>}/>
</Route>
</Routes>
</BrowserRouter>
)
export default App
\ No newline at end of file
import { useEffect, useState } from "react"
import ApiConnector from "../../Integrations/api.connector"
import { useParams } from "react-router-dom"
import { Row, Typography } from "antd"
const Education = () => {
const {id} = useParams()
const [text, setText] = useState<string | null>(null)
const getData = async () => {
const data = await ApiConnector.getEducation(id)
setText(data || null)
}
useEffect(() => {
getData()
}, [id])
return (
<Row>
<Typography.Title>
{text}
</Typography.Title>
</Row>
)
}
export default Education
\ No newline at end of file
import { useEffect, useState } from "react"
import ApiConnector from "../../Integrations/api.connector"
import { IEducations } from "../../Interfaces/education"
import { parserEducations } from "../../Helpers/parserEducations"
import { Button, Card, Row } from "antd"
import { useNavigate } from "react-router-dom"
const Educations = () => {
const navigate = useNavigate()
const [educations, setEducations] = useState<IEducations[]>([])
const getData = async () => {
const data = await ApiConnector.getEducations()
const parse = parserEducations(data)
setEducations(parse)
}
const onClickReadMore = (id?: string) => {
navigate(`/education/${id}`)
}
useEffect(() => {
getData()
}, [])
return (
<Row>
{
educations?.map((item) => (
<Card
key={item?.id}
title={item?.value}
>
<Button
type={'primary'}
onClick={() => onClickReadMore(item?.id)}
>
Read more
</Button>
</Card>
))
}
</Row>
)
}
export default Educations
\ No newline at end of file
import { useEffect, useState } from "react"
import ApiConnector from "../../Integrations/api.connector"
import { Row, Typography } from "antd"
import { IHome } from "../../Interfaces/home"
const Home = () => {
const [home, setHome] = useState<IHome | null>(null)
const getData = async () => {
const data = await ApiConnector.getHome()
setHome(data || null)
}
useEffect(() => {
getData()
}, [])
return (
<Row>
<Row>
<Typography.Title>
{home?.promo?.title}
</Typography.Title>
</Row>
<Row>
<Typography>
{home?.promo?.content}
</Typography>
</Row>
</Row>
)
}
export default Home
\ No newline at end of file
.headerStyle {
text-align: 'center';
color: '#fff';
height: 64;
padding-inline: 48;
line-height: '64px';
background-color: '#4096ff';
display: flex;
justify-content: space-between;
align-items: center;
}
.contentStyle {
text-align: 'center';
min-height: 120;
line-height: '120px',;
color: '#fff';
background-color: '#0958d9';
}
.layoutStyle {
border-radius: 8;
overflow: 'hidden';
width: 'calc(50% - 8px)';
max-width: 'calc(50% - 8px)';
};
\ No newline at end of file
import { Layout } from 'antd';
import { Outlet, NavLink } from "react-router-dom"
import './Layout.scss'
const { Header, Content } = Layout;
const CustomeLayout = () => {
return (
<Layout className='layoutStyle'>
<Header className='headerStyle'>
<NavLink to='/' end>
Home
</NavLink>
<NavLink to='/aboutMe' end>
About me
</NavLink>
<NavLink to='/education' end>
Educations
</NavLink>
</Header>
<Content className='contentStyle'>
<Outlet/>
</Content>
</Layout>
)
}
export default CustomeLayout
\ No newline at end of file
* {
margin: 0;
}
body {
margin: 0 auto;
}
\ No newline at end of file
import { createRoot } from 'react-dom/client'
import './index.scss'
import App from './Pages/App.tsx'
createRoot(document.getElementById('root')!).render(<App />)
/// <reference types="vite/client" />
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"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,
"noUncheckedSideEffectImports": true
},
"include": ["src"]
}
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
}
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"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,
"noUncheckedSideEffectImports": true
},
"include": ["vite.config.ts"]
}
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
})
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment