Template with a bunch of examples

This commit is contained in:
decamel 2022-07-18 11:38:44 +03:00
commit 7253949f17
236 changed files with 36077 additions and 0 deletions

8
.dockerignore Normal file
View File

@ -0,0 +1,8 @@
.env*
!.env.production
node_modules
build
.vscode
.cache
.nvmrc
README.MD

6
.env.development Normal file
View File

@ -0,0 +1,6 @@
REACT_APP_CMS_BASE_URL=https://cms.techpal.ru/api
REACT_APP_CMS_APP_NAME=techpal
REACT_APP_OPENID_PROVIDER_URL=http://auth.techpal.ru/auth/realms/master/protocol/openid-connect/auth?client_id=techpal&response_type=code
REACT_APP_INTEGRATOR_URL=http://integrator.techpal.ru
REACT_APP_INTEGRATOR_API_VERSION=/api/1
REACT_APP_GRAPHQL_URL=/graphql

6
.env.production Normal file
View File

@ -0,0 +1,6 @@
REACT_APP_CMS_BASE_URL=EXT_CMS_BASE_URL
REACT_APP_CMS_APP_NAME=EXT_CMS_APP_NAME
REACT_APP_OPENID_PROVIDER_URL=EXT_OPENID_PROVIDER_URL
REACT_APP_INTEGRATOR_URL=EXT_INTEGRATOR_URL
REACT_APP_INTEGRATOR_API_VERSION=EXT_INTEGRATOR_API_VERSION
REACT_APP_GRAPHQL_URL=EXT_GRAPHQL_URL

23
.gitignore vendored Normal file
View File

@ -0,0 +1,23 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

1
.nvmrc Normal file
View File

@ -0,0 +1 @@
v16.14.0

14
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,14 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
"version": "0.2.0",
"configurations": [
{
"type": "pwa-chrome",
"request": "launch",
"name": "Launch Chrome against localhost",
"url": "http://localhost:3000",
"webRoot": "${workspaceFolder}"
}
]
}

38
Dockerfile Normal file
View File

@ -0,0 +1,38 @@
# Install dependencies only when needed
FROM node:16-alpine AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
# Rebuild the source code only when needed
FROM node:16-alpine AS builder
ENV NODE_ENV production
WORKDIR /app
# Copy dependencies from deps stage
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
# Bundle static assets with nginx
FROM nginx:1.21.6 as production
# Copy built assets from builder
COPY --from=builder /app/build /usr/share/nginx/html
# Add nginx.config
COPY nginx.conf /etc/nginx/conf.d/default.conf
# Expose ports
EXPOSE 80
COPY entrypoint.sh .
COPY .env.production .
ENV NODE_ENV production
# Execute script
RUN ["chmod", "+x", "./entrypoint.sh"]
ENTRYPOINT ["./entrypoint.sh"]
# Start serving
CMD ["nginx", "-g", "daemon off;"]

24
Makefile Normal file
View File

@ -0,0 +1,24 @@
PROJECT_NAME=freeland-frontend
setup:
npm i
build: setup
npm run build
dev: setup
npm run start
test: setup
npm run test
container: setup
docker build -t ${PROJECT_NAME} .
clean:
rm -rf ./build
build-docker: build container
.PHONY: build dev test container

96
README.md Normal file
View File

@ -0,0 +1,96 @@
# Getting Started with Freeland
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
## Available Scripts
In the project directory, you can run:
### `make dev`
Runs the app in the development mode.\
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
The page will reload if you make edits.\
You will also see any lint errors in the console.
### `make test`
Launches the test runner in the interactive watch mode.\
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
### `make build`
Builds the app for production to the `build` folder.\
It correctly bundles React in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.\
Your app is ready to be deployed!
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
### `make container`
Builds up application container for production and tags it with a `freeland-frontend` tag.\
After process completion port `80` will be exposed inside a container to access files generated by `make build`
### `make build-docker`
Creates docker container ready for deployment
## `make clean`
Drops **build** process artifacts. It will not remove docker containers due to possible other project named\
containers intercections.
## Learn More
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
To learn React, check out the [React documentation](https://reactjs.org/).
## Code sections division
We care about our code appearance in text editor. That's why we are placing some
additional comments to seperate code parts using next style:
/\* -------------------------------------------------------------------------- \*/
/\*                           User service functions                           \*/
/\* -------------------------------------------------------------------------- \*/
Or
/\*-------------------------------- Hello --------------------------------\*/
Or
/\*-----------------------------------------------------------------------\*/
To place such comments for division code sections use [this](https://marketplace.visualstudio.com/items?itemName=stackbreak.comment-divider) extention.
## Domain folder structure
Inside specific domain you can see that we have next folders structure:
- domain folder (e.g.: user)
- controller
- some specific or general domain models (e.g. `userViewModel.ts`)
- data
- Data transfer objects
- Possible actions (e.g. `userActions.ts`) and action types definitions
- Reducer rules for redux (e.g. `userReducer.ts`, rules to change your Redux state on specific action type)
- Service (e.g. `userService.ts`, API interactions)
- Repository/Store implementation (e.g. `userSlice.ts`)
- domain
- Entity definition
- Domain model definition
- Repository/Store interface
- useCases (e.g. `getUserUseCase.ts`, use cases of domain)
- views
- pages
- specific components
## Network layer
We use [Axios](https://github.com/axios/axios) for network interactions
## Css styles and interactive components
As a CSS framework we are using [TailwindCSS](https://tailwindcss.com/)
For UI/UX elements use [HeadlessUI](https://headlessui.com/)

35
entrypoint.sh Executable file
View File

@ -0,0 +1,35 @@
#!/bin/bash
# no verbose
set +x
# config
envFilename='.env.production'
resolvingPath='/usr/share/nginx/html'
function apply_path {
# read all config file
while read line; do
# no comment or not empty
if [ "${line:0:1}" == "#" ] || [ "${line}" == "" ]; then
echo "Skiped line $line"
continue
fi
# split
configName="$(cut -d'=' -f1 <<<"$line")"
configValue="$(cut -d'=' -f2 <<<"$line")"
# get system env
envValue=$(env | grep "^$configName=" | grep -oP '(?!=)(?<==).*$');
if [ -z "$configValue" ]; then
echo "Empty env value met: $configName:$configValue"
fi
# if config found
if [ -n "$configValue" ] && [ -n "$envValue" ]; then
# replace all
echo "Replace: ${configValue} with: ${envValue}"
find $resolvingPath \( -type d -name .git -prune \) -o -type f -print0 | xargs -0 sed -i "s#$configValue#$envValue#g"
fi
done < $envFilename
}
apply_path
echo "Starting React Application"
exec "$@"

21
nginx.conf Normal file
View File

@ -0,0 +1,21 @@
server {
listen *:80;
location / {
root /usr/share/nginx/html/;
include /etc/nginx/mime.types;
try_files $uri $uri/ /index.html;
# Cache static assets
location ~* \.(?:jpg|jpeg|gif|png|ico|svg)$ {
expires 7d;
add_header Cache-Control "public";
}
# Cache css and js bundle
location ~* \.(?:css|js)$ {
add_header Cache-Control "no-cache, public, must-revalidate, proxy-revalidate";
}
}
}

28390
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

73
package.json Normal file
View File

@ -0,0 +1,73 @@
{
"name": "test",
"version": "0.1.0",
"private": true,
"dependencies": {
"@headlessui/react": "^1.5.0",
"@react-keycloak/web": "^3.4.0",
"@reduxjs/toolkit": "^1.8.1",
"axios": "^0.26.1",
"classnames": "^2.3.1",
"cross-env": "^7.0.3",
"formik": "^2.2.9",
"graphql": "^16.4.0",
"graphql-tag": "^2.12.6",
"i18next": "^21.6.16",
"i18next-browser-languagedetector": "^6.1.4",
"i18next-http-backend": "^1.4.0",
"jwt-decode": "^3.1.2",
"keycloak-js": "^18.0.0",
"lodash": "^4.17.21",
"lodash.debounce": "^4.0.8",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"react-hotkeys": "^2.0.0",
"react-i18next": "^11.16.7",
"react-redux": "^7.2.8",
"react-router-dom": "^6.3.0",
"react-scripts": "5.0.0",
"react-scrollbars-custom": "^4.0.27",
"web-vitals": "^2.1.4",
"yup": "^0.32.11"
},
"scripts": {
"dev-tools": "redux-devtools --hostname=localhost --port=8000",
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^12.1.4",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.4.1",
"@types/lodash.debounce": "^4.0.6",
"@types/node": "^16.11.26",
"@types/react": "^17.0.44",
"@types/react-dom": "^17.0.15",
"@types/react-redux": "^7.1.23",
"autoprefixer": "^10.4.4",
"postcss": "^8.4.12",
"tailwindcss": "^3.0.23",
"typescript": "^4.6.3"
}
}

6
postcss.config.js Normal file
View File

@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

5
public/favicon.svg Normal file
View File

@ -0,0 +1,5 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="11" cy="16" r="8" fill="#FF0000" />
<circle cx="25" cy="21" r="3" fill="#0075FF" />
</svg>

After

Width:  |  Height:  |  Size: 205 B

43
public/index.html Normal file
View File

@ -0,0 +1,43 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>Dashboard | Techpal</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

View File

@ -0,0 +1,63 @@
{
"serv": {
"goHome": "Home",
"noSuchPath": "We don't have this page"
},
"sidemenu": {
"dashboard": "Dashboard",
"account": "Account",
"security": "Security",
"services": "Services"
},
"dialogues": {
"confirmAction": {
"title": "Confirm action",
"description": "Enter your techpal account password",
"confirm": "Confirm"
}
},
"hellousr": "Hello, {{username}}",
"edit": "Edit",
"language": "Language",
"selectLanguage": "Select language",
"save": "Save",
"cancel": "Cancel",
"account": {
"info": "Personal information",
"mail": "Mail",
"connect": "Add account",
"connectedAccounts_one": "Connected account",
"connectedAccounts_other": "Connected accounts",
"settings": "Account settings"
},
"security": {
"password": {
"caption": "Password",
"twoFactor": "Two factor authentication (2FA)",
"description": "Keep your account secure by enabling 2FA via SMS or using a temporary one-time passcode (TOTP) from an authenticator app."
},
"activity": {
"caption": "Device activity"
}
},
"search": {
"label": "Search for something.."
},
"subscriptions": {
"subscribed": "Service have been connected"
},
"viewHistory": "View history",
"logOutEverywhere": "log out from all devices",
"back": "Back",
"logOut": "Log out",
"failures": {
"subscriptions": {
"failure": "Failed to connect service",
"exists": "Service have already been connected",
"confirmation": "Invalid confirmation information provided"
},
"services": {
"fork": "Failed to authenticate in service"
}
}
}

View File

@ -0,0 +1,63 @@
{
"serv": {
"goHome": "На главную",
"noSuchPath": "Такой страницы у нас нет"
},
"sidemenu": {
"dashboard": "Панель",
"account": "Аккаунт",
"security": "Безопасность",
"services": "Сервисы"
},
"dialogues": {
"confirmAction": {
"title": "Подтвердите действие",
"description": "Введите ваш пароль от аккаунта techpal",
"confirm": "Подтвердить"
}
},
"hellousr": "Привет, {{username}}",
"edit": "Изменить",
"language": "Язык",
"selectLanguage": "Выберите язык",
"save": "Сохранить",
"cancel": "Отмена",
"account": {
"info": "Личная информация",
"mail": "Почта",
"connect": "Добавить аккаунт",
"connectedAccounts_one": "Связанный аккаунт",
"connectedAccounts_other": "Связанные аккаунты",
"settings": "Настройки аккаунта"
},
"security": {
"password": {
"caption": "Пароль",
"twoFactor": "Двухфакторная аутентификация (2FA)",
"description": "Защитите свою учетную запись, включив 2FA с помощью SMS или используя временный одноразовый пароль (OTP) из приложения для проверки подлинности."
},
"activity": {
"caption": "Активность устройств"
}
},
"search": {
"label": "Найдём что-нибудь.."
},
"subscriptions": {
"subscribed": "Сервис прикреплён к аккаунту"
},
"viewHistory": "просмотреть историю",
"logOutEverywhere": "выйти со всех устройств",
"back": "Назад",
"logOut": "Выйти",
"failures": {
"subscriptions": {
"failure": "Не удалось прикрепить сервис к аккаунту",
"exists": "Сервис уже был прикреплён к вашему аккаунту ранее",
"confirmation": "Неверный пароль"
},
"services": {
"fork": "Не удалось выполнить авторизацию в сервисе"
}
}
}

BIN
public/logo192.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
public/logo512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

25
public/manifest.json Normal file
View File

@ -0,0 +1,25 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

3
public/robots.txt Normal file
View File

@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

38
src/App.css Normal file
View File

@ -0,0 +1,38 @@
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}

9
src/App.test.tsx Normal file
View File

@ -0,0 +1,9 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import App from './App';
test('renders learn react link', () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});

43
src/App.tsx Normal file
View File

@ -0,0 +1,43 @@
/* -------------------------------------------------------------------------- */
/* Libraries */
/* -------------------------------------------------------------------------- */
import React, { useEffect } from "react";
import { BrowserRouter as Router } from "react-router-dom";
import { Provider } from "react-redux";
/* -------------------------------------------------------------------------- */
/* Parts */
/* -------------------------------------------------------------------------- */
import AppHotKeys from "ui/views/HotKeys";
import AppLoader from "components/parts/Loader";
import GlobalSearchbar from "ui/views/GlobalSearch";
/* -------------------------------------------------------------------------- */
/* Misc */
/* -------------------------------------------------------------------------- */
import { store } from "store/store";
import routes from "routes";
import RoutesRenderer from "components/RoutesRenderer";
import NotificationsField from "ui/views/NotificationsField";
/* -------------------------------------------------------------------------- */
/* Application root component */
/* -------------------------------------------------------------------------- */
/**
* Application root component
* @return {JSX.Element}
*/
function App() {
return (
<Provider store={store} >
<AppHotKeys>
<React.Suspense fallback={<AppLoader />}>
<Router>
<RoutesRenderer routes={routes} />
</Router>
<GlobalSearchbar />
<NotificationsField />
</React.Suspense>
</AppHotKeys>
</Provider>
);
}
export default App;

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,4 @@
<svg viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.35355 4.35355C7.54882 4.15829 7.54882 3.84171 7.35355 3.64645L4.17157 0.464466C3.97631 0.269204 3.65973 0.269204 3.46447 0.464466C3.2692 0.659728 3.2692 0.976311 3.46447 1.17157L6.29289 4L3.46447 6.82843C3.2692 7.02369 3.2692 7.34027 3.46447 7.53553C3.65973 7.7308 3.97631 7.7308 4.17157 7.53553L7.35355 4.35355ZM0 4.5H7V3.5H0V4.5Z" fill="white" />
</svg>

After

Width:  |  Height:  |  Size: 443 B

View File

@ -0,0 +1,4 @@
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5 12H19" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
<path d="M12 5L19 12L12 19" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 257 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2">
<path strokeLinecap="round" strokeLinejoin="round" d="M16 12a4 4 0 10-8 0 4 4 0 008 0zm0 0v1.5a2.5 2.5 0 005 0V12a9 9 0 10-9 9m4.5-1.206a8.959 8.959 0 01-4.5 1.207" />
</svg>;

After

Width:  |  Height:  |  Size: 309 B

View File

@ -0,0 +1,7 @@
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.6">
<path d="M19 12H5" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
<path d="M12 19L5 12L12 5" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 297 B

7
src/assets/svg/bell.svg Normal file
View File

@ -0,0 +1,7 @@
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.6">
<path d="M18 8C18 6.4087 17.3679 4.88258 16.2426 3.75736C15.1174 2.63214 13.5913 2 12 2C10.4087 2 8.88258 2.63214 7.75736 3.75736C6.63214 4.88258 6 6.4087 6 8C6 15 3 17 3 17H21C21 17 18 15 18 8Z" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
<path d="M13.73 21C13.5542 21.3031 13.3019 21.5547 12.9982 21.7295C12.6946 21.9044 12.3504 21.9965 12 21.9965C11.6496 21.9965 11.3054 21.9044 11.0018 21.7295C10.6982 21.5547 10.4458 21.3031 10.27 21" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 647 B

5
src/assets/svg/check.svg Normal file
View File

@ -0,0 +1,5 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 405.272 405.272" style="enable-background:new 0 0 405.272 405.272;" xml:space="preserve">
<path d="M393.401,124.425L179.603,338.208c-15.832,15.835-41.514,15.835-57.361,0L11.878,227.836
c-15.838-15.835-15.838-41.52,0-57.358c15.841-15.841,41.521-15.841,57.355-0.006l81.698,81.699L336.037,67.064
c15.841-15.841,41.523-15.829,57.358,0C409.23,82.902,409.23,108.578,393.401,124.425z" />
</svg>

After

Width:  |  Height:  |  Size: 523 B

3
src/assets/svg/chip.svg Normal file
View File

@ -0,0 +1,3 @@
<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.0002 8.19995C11.7272 8.19995 10.5063 8.70566 9.60608 9.60584C8.70591 10.506 8.20019 11.7269 8.20019 13C8.20019 14.273 8.70591 15.4939 9.60608 16.3941C10.5063 17.2942 11.7272 17.7999 13.0002 17.7999C14.2732 17.7999 15.4941 17.2942 16.3943 16.3941C17.2945 15.4939 17.8002 14.273 17.8002 13C17.8002 11.7269 17.2945 10.506 16.3943 9.60584C15.4941 8.70566 14.2732 8.19995 13.0002 8.19995ZM9.80019 13C9.80019 12.1513 10.1373 11.3373 10.7375 10.7372C11.3376 10.1371 12.1515 9.79995 13.0002 9.79995C13.8489 9.79995 14.6628 10.1371 15.2629 10.7372C15.8631 11.3373 16.2002 12.1513 16.2002 13C16.2002 13.8486 15.8631 14.6626 15.2629 15.2627C14.6628 15.8628 13.8489 16.2 13.0002 16.2C12.1515 16.2 11.3376 15.8628 10.7375 15.2627C10.1373 14.6626 9.80019 13.8486 9.80019 13ZM9.00019 0.199951C9.21237 0.199951 9.41585 0.284237 9.56588 0.434266C9.71591 0.584295 9.80019 0.787778 9.80019 0.999951V3.39995H12.2002V0.999951C12.2002 0.787778 12.2845 0.584295 12.4345 0.434266C12.5845 0.284237 12.788 0.199951 13.0002 0.199951C13.2124 0.199951 13.4159 0.284237 13.5659 0.434266C13.7159 0.584295 13.8002 0.787778 13.8002 0.999951V3.39995H16.2002V0.999951C16.2002 0.787778 16.2845 0.584295 16.4345 0.434266C16.5845 0.284237 16.788 0.199951 17.0002 0.199951C17.2124 0.199951 17.4159 0.284237 17.5659 0.434266C17.7159 0.584295 17.8002 0.787778 17.8002 0.999951V3.39995H18.6002C19.6611 3.39995 20.6785 3.82138 21.4286 4.57152C22.1788 5.32167 22.6002 6.33908 22.6002 7.39995V8.19995H25.0002C25.2124 8.19995 25.4159 8.28424 25.5659 8.43427C25.7159 8.58429 25.8002 8.78778 25.8002 8.99995C25.8002 9.21212 25.7159 9.41561 25.5659 9.56564C25.4159 9.71566 25.2124 9.79995 25.0002 9.79995H22.6002V12.2H25.0002C25.2124 12.2 25.4159 12.2842 25.5659 12.4343C25.7159 12.5843 25.8002 12.7878 25.8002 13C25.8002 13.2121 25.7159 13.4156 25.5659 13.5656C25.4159 13.7157 25.2124 13.8 25.0002 13.8H22.6002V16.2H25.0002C25.2124 16.2 25.4159 16.2842 25.5659 16.4343C25.7159 16.5843 25.8002 16.7878 25.8002 17C25.8002 17.2121 25.7159 17.4156 25.5659 17.5656C25.4159 17.7157 25.2124 17.7999 25.0002 17.7999H22.6002V18.6C22.6002 19.6608 22.1788 20.6782 21.4286 21.4284C20.6785 22.1785 19.6611 22.5999 18.6002 22.5999H17.8002V25C17.8002 25.2121 17.7159 25.4156 17.5659 25.5656C17.4159 25.7157 17.2124 25.7999 17.0002 25.7999C16.788 25.7999 16.5845 25.7157 16.4345 25.5656C16.2845 25.4156 16.2002 25.2121 16.2002 25V22.5999H13.8002V25C13.8002 25.2121 13.7159 25.4156 13.5659 25.5656C13.4159 25.7157 13.2124 25.7999 13.0002 25.7999C12.788 25.7999 12.5845 25.7157 12.4345 25.5656C12.2845 25.4156 12.2002 25.2121 12.2002 25V22.5999H9.80019V25C9.80019 25.2121 9.71591 25.4156 9.56588 25.5656C9.41585 25.7157 9.21237 25.7999 9.00019 25.7999C8.78802 25.7999 8.58454 25.7157 8.43451 25.5656C8.28448 25.4156 8.20019 25.2121 8.20019 25V22.5999H7.4002C6.33933 22.5999 5.32191 22.1785 4.57177 21.4284C3.82162 20.6782 3.4002 19.6608 3.4002 18.6V17.7999H1.0002C0.788022 17.7999 0.584539 17.7157 0.43451 17.5656C0.284481 17.4156 0.200195 17.2121 0.200195 17C0.200195 16.7878 0.284481 16.5843 0.43451 16.4343C0.584539 16.2842 0.788022 16.2 1.0002 16.2H3.4002V13.8H1.0002C0.788022 13.8 0.584539 13.7157 0.43451 13.5656C0.284481 13.4156 0.200195 13.2121 0.200195 13C0.200195 12.7878 0.284481 12.5843 0.43451 12.4343C0.584539 12.2842 0.788022 12.2 1.0002 12.2H3.4002V9.79995H1.0002C0.788022 9.79995 0.584539 9.71566 0.43451 9.56564C0.284481 9.41561 0.200195 9.21212 0.200195 8.99995C0.200195 8.78778 0.284481 8.58429 0.43451 8.43427C0.584539 8.28424 0.788022 8.19995 1.0002 8.19995H3.4002V7.39995C3.4002 6.33908 3.82162 5.32167 4.57177 4.57152C5.32191 3.82138 6.33933 3.39995 7.4002 3.39995H8.20019V0.999951C8.20019 0.787778 8.28448 0.584295 8.43451 0.434266C8.58454 0.284237 8.78802 0.199951 9.00019 0.199951ZM21.0002 7.39995C21.0002 6.76343 20.7473 6.15298 20.2973 5.70289C19.8472 5.25281 19.2367 4.99995 18.6002 4.99995H7.4002C6.76368 4.99995 6.15323 5.25281 5.70314 5.70289C5.25305 6.15298 5.0002 6.76343 5.0002 7.39995V18.6C5.0002 19.2365 5.25305 19.8469 5.70314 20.297C6.15323 20.7471 6.76368 21 7.4002 21H18.6002C19.2367 21 19.8472 20.7471 20.2973 20.297C20.7473 19.8469 21.0002 19.2365 21.0002 18.6V7.39995Z" fill="white"/>
</svg>;

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -0,0 +1,17 @@
<svg viewBox="0 0 45 45" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fill-rule="evenodd" transform="translate(1 1)" stroke-width="2">
<circle cx="22" cy="22" r="6" stroke-opacity="0">
<animate attributeName="r" begin="1.5s" dur="3s" values="6;22" calcMode="linear" repeatCount="indefinite" />
<animate attributeName="stroke-opacity" begin="1.5s" dur="3s" values="1;0" calcMode="linear" repeatCount="indefinite" />
<animate attributeName="stroke-width" begin="1.5s" dur="3s" values="2;0" calcMode="linear" repeatCount="indefinite" />
</circle>
<circle cx="22" cy="22" r="6" stroke-opacity="0">
<animate attributeName="r" begin="3s" dur="3s" values="6;22" calcMode="linear" repeatCount="indefinite" />
<animate attributeName="stroke-opacity" begin="3s" dur="3s" values="1;0" calcMode="linear" repeatCount="indefinite" />
<animate attributeName="stroke-width" begin="3s" dur="3s" values="2;0" calcMode="linear" repeatCount="indefinite" />
</circle>
<circle cx="22" cy="22" r="8">
<animate attributeName="r" begin="0s" dur="1.5s" values="6;1;2;3;4;5;6" calcMode="linear" repeatCount="indefinite" />
</circle>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

7
src/assets/svg/cog.svg Normal file
View File

@ -0,0 +1,7 @@
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.6">
<path d="M12 15C13.6569 15 15 13.6569 15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15Z" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
<path d="M19.4 15C19.2669 15.3016 19.2272 15.6362 19.286 15.9606C19.3448 16.285 19.4995 16.5843 19.73 16.82L19.79 16.88C19.976 17.0657 20.1235 17.2863 20.2241 17.5291C20.3248 17.7719 20.3766 18.0322 20.3766 18.295C20.3766 18.5578 20.3248 18.8181 20.2241 19.0609C20.1235 19.3037 19.976 19.5243 19.79 19.71C19.6043 19.896 19.3837 20.0435 19.1409 20.1441C18.8981 20.2448 18.6378 20.2966 18.375 20.2966C18.1122 20.2966 17.8519 20.2448 17.6091 20.1441C17.3663 20.0435 17.1457 19.896 16.96 19.71L16.9 19.65C16.6643 19.4195 16.365 19.2648 16.0406 19.206C15.7162 19.1472 15.3816 19.1869 15.08 19.32C14.7842 19.4468 14.532 19.6572 14.3543 19.9255C14.1766 20.1938 14.0813 20.5082 14.08 20.83V21C14.08 21.5304 13.8693 22.0391 13.4942 22.4142C13.1191 22.7893 12.6104 23 12.08 23C11.5496 23 11.0409 22.7893 10.6658 22.4142C10.2907 22.0391 10.08 21.5304 10.08 21V20.91C10.0723 20.579 9.96512 20.258 9.77251 19.9887C9.5799 19.7194 9.31074 19.5143 9 19.4C8.69838 19.2669 8.36381 19.2272 8.03941 19.286C7.71502 19.3448 7.41568 19.4995 7.18 19.73L7.12 19.79C6.93425 19.976 6.71368 20.1235 6.47088 20.2241C6.22808 20.3248 5.96783 20.3766 5.705 20.3766C5.44217 20.3766 5.18192 20.3248 4.93912 20.2241C4.69632 20.1235 4.47575 19.976 4.29 19.79C4.10405 19.6043 3.95653 19.3837 3.85588 19.1409C3.75523 18.8981 3.70343 18.6378 3.70343 18.375C3.70343 18.1122 3.75523 17.8519 3.85588 17.6091C3.95653 17.3663 4.10405 17.1457 4.29 16.96L4.35 16.9C4.58054 16.6643 4.73519 16.365 4.794 16.0406C4.85282 15.7162 4.81312 15.3816 4.68 15.08C4.55324 14.7842 4.34276 14.532 4.07447 14.3543C3.80618 14.1766 3.49179 14.0813 3.17 14.08H3C2.46957 14.08 1.96086 13.8693 1.58579 13.4942C1.21071 13.1191 1 12.6104 1 12.08C1 11.5496 1.21071 11.0409 1.58579 10.6658C1.96086 10.2907 2.46957 10.08 3 10.08H3.09C3.42099 10.0723 3.742 9.96512 4.0113 9.77251C4.28059 9.5799 4.48572 9.31074 4.6 9C4.73312 8.69838 4.77282 8.36381 4.714 8.03941C4.65519 7.71502 4.50054 7.41568 4.27 7.18L4.21 7.12C4.02405 6.93425 3.87653 6.71368 3.77588 6.47088C3.67523 6.22808 3.62343 5.96783 3.62343 5.705C3.62343 5.44217 3.67523 5.18192 3.77588 4.93912C3.87653 4.69632 4.02405 4.47575 4.21 4.29C4.39575 4.10405 4.61632 3.95653 4.85912 3.85588C5.10192 3.75523 5.36217 3.70343 5.625 3.70343C5.88783 3.70343 6.14808 3.75523 6.39088 3.85588C6.63368 3.95653 6.85425 4.10405 7.04 4.29L7.1 4.35C7.33568 4.58054 7.63502 4.73519 7.95941 4.794C8.28381 4.85282 8.61838 4.81312 8.92 4.68H9C9.29577 4.55324 9.54802 4.34276 9.72569 4.07447C9.90337 3.80618 9.99872 3.49179 10 3.17V3C10 2.46957 10.2107 1.96086 10.5858 1.58579C10.9609 1.21071 11.4696 1 12 1C12.5304 1 13.0391 1.21071 13.4142 1.58579C13.7893 1.96086 14 2.46957 14 3V3.09C14.0013 3.41179 14.0966 3.72618 14.2743 3.99447C14.452 4.26276 14.7042 4.47324 15 4.6C15.3016 4.73312 15.6362 4.77282 15.9606 4.714C16.285 4.65519 16.5843 4.50054 16.82 4.27L16.88 4.21C17.0657 4.02405 17.2863 3.87653 17.5291 3.77588C17.7719 3.67523 18.0322 3.62343 18.295 3.62343C18.5578 3.62343 18.8181 3.67523 19.0609 3.77588C19.3037 3.87653 19.5243 4.02405 19.71 4.21C19.896 4.39575 20.0435 4.61632 20.1441 4.85912C20.2448 5.10192 20.2966 5.36217 20.2966 5.625C20.2966 5.88783 20.2448 6.14808 20.1441 6.39088C20.0435 6.63368 19.896 6.85425 19.71 7.04L19.65 7.1C19.4195 7.33568 19.2648 7.63502 19.206 7.95941C19.1472 8.28381 19.1869 8.61838 19.32 8.92V9C19.4468 9.29577 19.6572 9.54802 19.9255 9.72569C20.1938 9.90337 20.5082 9.99872 20.83 10H21C21.5304 10 22.0391 10.2107 22.4142 10.5858C22.7893 10.9609 23 11.4696 23 12C23 12.5304 22.7893 13.0391 22.4142 13.4142C22.0391 13.7893 21.5304 14 21 14H20.91C20.5882 14.0013 20.2738 14.0966 20.0055 14.2743C19.7372 14.452 19.5268 14.7042 19.4 15V15Z" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -0,0 +1,4 @@
<svg width="16" height="28" viewBox="0 0 16 28" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 1.16663V26.8333" stroke="white" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
<path d="M13.8333 5.83337H5.08333C4.00037 5.83337 2.96175 6.26358 2.19598 7.02936C1.43021 7.79513 1 8.83374 1 9.91671C1 10.9997 1.43021 12.0383 2.19598 12.8041C2.96175 13.5698 4.00037 14 5.08333 14H10.9167C11.9996 14 13.0382 14.4302 13.804 15.196C14.5698 15.9618 15 17.0004 15 18.0834C15 19.1663 14.5698 20.205 13.804 20.9707C13.0382 21.7365 11.9996 22.1667 10.9167 22.1667H1" stroke="white" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</svg>;

After

Width:  |  Height:  |  Size: 670 B

View File

@ -0,0 +1,6 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<rect x="0" fill="none" width="24" height="24" />
<g>
<path d="M7 10l5 5 5-5" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 163 B

View File

@ -0,0 +1,7 @@
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.6">
<path d="M4 4H20C21.1 4 22 4.9 22 6V18C22 19.1 21.1 20 20 20H4C2.9 20 2 19.1 2 18V6C2 4.9 2.9 4 4 4Z" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
<path d="M22 6L12 13L2 6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 379 B

8
src/assets/svg/exit.svg Normal file
View File

@ -0,0 +1,8 @@
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.6">
<path d="M9 21H5C4.46957 21 3.96086 20.7893 3.58579 20.4142C3.21071 20.0391 3 19.5304 3 19V5C3 4.46957 3.21071 3.96086 3.58579 3.58579C3.96086 3.21071 4.46957 3 5 3H9" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
<path d="M16 17L21 12L16 7" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
<path d="M21 12H9" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 537 B

View File

@ -0,0 +1,8 @@
<svg viewBox="0 0 24 24" stroke="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.6">
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.94996 3.18608C9.58956 2.52283 11.367 2.27241 13.126 2.45681C14.885 2.64122 16.5718 3.2548 18.0382 4.24366C19.5046 5.23252 20.7057 6.56639 21.536 8.12806C22.3663 9.68973 22.8003 11.4314 22.8 13.2001C22.8 13.5183 22.6735 13.8236 22.4485 14.0486C22.2234 14.2737 21.9182 14.4001 21.6 14.4001C21.2817 14.4001 20.9765 14.2737 20.7514 14.0486C20.5264 13.8236 20.4 13.5183 20.4 13.2001C20.4005 11.8243 20.0631 10.4695 19.4175 9.25459C18.7718 8.03973 17.8377 7.00204 16.6971 6.23273C15.5565 5.46342 14.2445 4.98603 12.8762 4.84252C11.5079 4.69901 10.1253 4.89377 8.84996 5.40968C8.70292 5.47461 8.54433 5.50933 8.38361 5.51179C8.2229 5.51424 8.06332 5.48439 7.91437 5.42399C7.76541 5.36359 7.6301 5.27389 7.51648 5.16019C7.40286 5.0465 7.31323 4.91114 7.25293 4.76215C7.19262 4.61315 7.16286 4.45356 7.16542 4.29284C7.16797 4.13213 7.20279 3.97356 7.26781 3.82656C7.33282 3.67956 7.4267 3.54712 7.54389 3.43709C7.66107 3.32707 7.79916 3.24171 7.94996 3.18608ZM5.59436 5.95088C5.8328 6.16147 5.97787 6.45812 5.99767 6.77562C6.01747 7.09313 5.91039 7.4055 5.69996 7.64408C4.3438 9.17679 3.59665 11.1535 3.59996 13.2001C3.59996 13.5183 3.47353 13.8236 3.24849 14.0486C3.02344 14.2737 2.71822 14.4001 2.39996 14.4001C2.0817 14.4001 1.77648 14.2737 1.55143 14.0486C1.32639 13.8236 1.19996 13.5183 1.19996 13.2001C1.19662 10.5689 2.15711 8.02766 3.89996 6.05648C4.00425 5.93824 4.13082 5.84171 4.27243 5.77241C4.41404 5.7031 4.56792 5.66238 4.72528 5.65258C4.88263 5.64277 5.04038 5.66407 5.1895 5.71525C5.33862 5.76644 5.4762 5.84651 5.59436 5.95088Z" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.99994 13.2002C5.99994 11.6089 6.63208 10.0828 7.7573 8.95755C8.88252 7.83234 10.4086 7.2002 11.9999 7.2002C13.5912 7.2002 15.1174 7.83234 16.2426 8.95755C17.3678 10.0828 17.9999 11.6089 17.9999 13.2002C17.9999 13.5185 17.8735 13.8237 17.6485 14.0487C17.4234 14.2738 17.1182 14.4002 16.7999 14.4002C16.4817 14.4002 16.1765 14.2738 15.9514 14.0487C15.7264 13.8237 15.5999 13.5185 15.5999 13.2002C15.5999 12.2454 15.2207 11.3297 14.5455 10.6546C13.8704 9.97948 12.9547 9.6002 11.9999 9.6002C11.0452 9.6002 10.1295 9.97948 9.45436 10.6546C8.77922 11.3297 8.39994 12.2454 8.39994 13.2002C8.39994 15.2126 7.98594 17.1314 7.23834 18.875C7.11279 19.1675 6.87619 19.3981 6.58059 19.5161C6.285 19.6342 5.95462 19.6299 5.66214 19.5044C5.36966 19.3788 5.13903 19.1422 5.021 18.8466C4.90296 18.5511 4.90719 18.2207 5.03274 17.9282C5.67314 16.4343 6.00224 14.8256 5.99994 13.2002ZM16.7051 15.6146C16.8609 15.6393 17.0102 15.6944 17.1446 15.7768C17.279 15.8592 17.3959 15.9674 17.4885 16.095C17.5811 16.2226 17.6476 16.3672 17.6843 16.5205C17.721 16.6738 17.7271 16.8329 17.7023 16.9886C17.5459 17.9757 17.3274 18.9521 17.0483 19.9118C17.0073 20.0664 16.9358 20.2113 16.838 20.3379C16.7402 20.4645 16.6181 20.5702 16.4788 20.649C16.3396 20.7277 16.1859 20.7777 16.027 20.7962C15.8681 20.8147 15.7071 20.8012 15.5535 20.7566C15.3999 20.7119 15.2568 20.637 15.1325 20.5362C15.0083 20.4355 14.9054 20.3109 14.83 20.1698C14.7546 20.0287 14.7082 19.8739 14.6935 19.7146C14.6788 19.5553 14.6961 19.3947 14.7443 19.2422C14.9927 18.3866 15.1895 17.5082 15.3323 16.6118C15.3825 16.2978 15.5552 16.0165 15.8126 15.8297C16.07 15.643 16.391 15.566 16.7051 15.6158V15.6146Z" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.9999 12C12.3182 12 12.6234 12.1264 12.8484 12.3515C13.0735 12.5765 13.1999 12.8817 13.1999 13.2C13.1999 15.8832 12.6479 18.4416 11.6519 20.7648C11.5897 20.9096 11.4997 21.0408 11.3868 21.1508C11.2739 21.2608 11.1405 21.3475 10.9942 21.4059C10.8478 21.4644 10.6914 21.4934 10.5338 21.4914C10.3762 21.4894 10.2205 21.4564 10.0757 21.3942C9.93089 21.332 9.79973 21.2419 9.68973 21.1291C9.57972 21.0162 9.49302 20.8828 9.43457 20.7365C9.37613 20.5901 9.34708 20.4336 9.3491 20.2761C9.35111 20.1185 9.38415 19.9628 9.44631 19.818C10.3425 17.7269 10.803 15.4751 10.7999 13.2C10.7999 12.8817 10.9263 12.5765 11.1514 12.3515C11.3764 12.1264 11.6817 12 11.9999 12Z" fill="white" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

8
src/assets/svg/globe.svg Normal file
View File

@ -0,0 +1,8 @@
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.6">
<path d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2 12H22" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 2C14.5013 4.73835 15.9228 8.29203 16 12C15.9228 15.708 14.5013 19.2616 12 22C9.49872 19.2616 8.07725 15.708 8 12C8.07725 8.29203 9.49872 4.73835 12 2V2Z" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 625 B

View File

@ -0,0 +1,3 @@
<svg width="52" height="60" viewBox="0 0 52 60" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M23 1.73205C24.8564 0.660254 27.1436 0.660254 29 1.73205L48.9808 13.2679C50.8372 14.3397 51.9808 16.3205 51.9808 18.4641V41.5359C51.9808 43.6795 50.8372 45.6603 48.9808 46.7321L29 58.2679C27.1436 59.3397 24.8564 59.3397 23 58.2679L3.01924 46.7321C1.16283 45.6603 0.0192375 43.6795 0.0192375 41.5359V18.4641C0.0192375 16.3205 1.16283 14.3397 3.01924 13.2679L23 1.73205Z" fillOpacity="0.6" />
</svg>;

After

Width:  |  Height:  |  Size: 506 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2">
<path strokeLinecap="round" strokeLinejoin="round" d="M10 6H5a2 2 0 00-2 2v9a2 2 0 002 2h14a2 2 0 002-2V8a2 2 0 00-2-2h-5m-4 0V5a2 2 0 114 0v1m-4 0a2 2 0 104 0m-5 8a2 2 0 100-4 2 2 0 000 4zm0 0c1.306 0 2.417.835 2.83 2M9 14a3.001 3.001 0 00-2.83 2M15 11h3m-3 4h2" />
</svg>;

After

Width:  |  Height:  |  Size: 408 B

7
src/assets/svg/lock.svg Normal file
View File

@ -0,0 +1,7 @@
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.6">
<path d="M19 11H5C3.89543 11 3 11.8954 3 13V20C3 21.1046 3.89543 22 5 22H19C20.1046 22 21 21.1046 21 20V13C21 11.8954 20.1046 11 19 11Z" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
<path d="M7 11V7C7 5.67392 7.52678 4.40215 8.46447 3.46447C9.40215 2.52678 10.6739 2 12 2C13.3261 2 14.5979 2.52678 15.5355 3.46447C16.4732 4.40215 17 5.67392 17 7V11" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 556 B

View File

@ -0,0 +1,5 @@
<svg width="320" height="124" viewBox="0 0 320 124" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="42.625" cy="62" r="31" fill="#FF0000"/>
<circle cx="96.875" cy="81.375" r="11.625" fill="#0075FF"/>
<path d="M143.136 57.928V70.792C143.136 71.688 143.344 72.344 143.76 72.76C144.208 73.144 144.944 73.336 145.968 73.336H149.088V79H144.864C139.2 79 136.368 76.248 136.368 70.744V57.928H133.2V52.408H136.368V45.832H143.136V52.408H149.088V57.928H143.136ZM178.641 65.128C178.641 66.088 178.577 66.952 178.449 67.72H159.009C159.169 69.64 159.841 71.144 161.025 72.232C162.209 73.32 163.665 73.864 165.393 73.864C167.889 73.864 169.665 72.792 170.721 70.648H177.969C177.201 73.208 175.729 75.32 173.553 76.984C171.377 78.616 168.705 79.432 165.537 79.432C162.977 79.432 160.673 78.872 158.625 77.752C156.609 76.6 155.025 74.984 153.873 72.904C152.753 70.824 152.193 68.424 152.193 65.704C152.193 62.952 152.753 60.536 153.873 58.456C154.993 56.376 156.561 54.776 158.577 53.656C160.593 52.536 162.913 51.976 165.537 51.976C168.065 51.976 170.321 52.52 172.305 53.608C174.321 54.696 175.873 56.248 176.961 58.264C178.081 60.248 178.641 62.536 178.641 65.128ZM171.681 63.208C171.649 61.48 171.025 60.104 169.809 59.08C168.593 58.024 167.105 57.496 165.345 57.496C163.681 57.496 162.273 58.008 161.121 59.032C160.001 60.024 159.313 61.416 159.057 63.208H171.681ZM181.818 65.704C181.818 62.952 182.378 60.552 183.498 58.504C184.618 56.424 186.17 54.824 188.154 53.704C190.138 52.552 192.41 51.976 194.97 51.976C198.266 51.976 200.986 52.808 203.13 54.472C205.306 56.104 206.762 58.408 207.498 61.384H200.25C199.866 60.232 199.21 59.336 198.282 58.696C197.386 58.024 196.266 57.688 194.922 57.688C193.002 57.688 191.482 58.392 190.362 59.8C189.242 61.176 188.682 63.144 188.682 65.704C188.682 68.232 189.242 70.2 190.362 71.608C191.482 72.984 193.002 73.672 194.922 73.672C197.642 73.672 199.418 72.456 200.25 70.024H207.498C206.762 72.904 205.306 75.192 203.13 76.888C200.954 78.584 198.234 79.432 194.97 79.432C192.41 79.432 190.138 78.872 188.154 77.752C186.17 76.6 184.618 75 183.498 72.952C182.378 70.872 181.818 68.456 181.818 65.704ZM227.397 52.024C229.413 52.024 231.205 52.472 232.773 53.368C234.341 54.232 235.557 55.528 236.421 57.256C237.317 58.952 237.765 61 237.765 63.4V79H231.045V64.312C231.045 62.2 230.517 60.584 229.461 59.464C228.405 58.312 226.965 57.736 225.141 57.736C223.285 57.736 221.813 58.312 220.725 59.464C219.669 60.584 219.141 62.2 219.141 64.312V79H212.421V43.48H219.141V55.72C220.005 54.568 221.157 53.672 222.597 53.032C224.037 52.36 225.637 52.024 227.397 52.024ZM250.876 56.248C251.74 55.032 252.924 54.024 254.428 53.224C255.964 52.392 257.708 51.976 259.66 51.976C261.932 51.976 263.98 52.536 265.804 53.656C267.66 54.776 269.116 56.376 270.172 58.456C271.26 60.504 271.804 62.888 271.804 65.608C271.804 68.328 271.26 70.744 270.172 72.856C269.116 74.936 267.66 76.552 265.804 77.704C263.98 78.856 261.932 79.432 259.66 79.432C257.708 79.432 255.98 79.032 254.476 78.232C253.004 77.432 251.804 76.424 250.876 75.208V91.672H244.156V52.408H250.876V56.248ZM264.94 65.608C264.94 64.008 264.604 62.632 263.932 61.48C263.292 60.296 262.428 59.4 261.34 58.792C260.284 58.184 259.132 57.88 257.884 57.88C256.668 57.88 255.516 58.2 254.428 58.84C253.372 59.448 252.508 60.344 251.836 61.528C251.196 62.712 250.876 64.104 250.876 65.704C250.876 67.304 251.196 68.696 251.836 69.88C252.508 71.064 253.372 71.976 254.428 72.616C255.516 73.224 256.668 73.528 257.884 73.528C259.132 73.528 260.284 73.208 261.34 72.568C262.428 71.928 263.292 71.016 263.932 69.832C264.604 68.648 264.94 67.24 264.94 65.608ZM274.959 65.608C274.959 62.92 275.487 60.536 276.543 58.456C277.631 56.376 279.087 54.776 280.911 53.656C282.767 52.536 284.831 51.976 287.103 51.976C289.087 51.976 290.815 52.376 292.287 53.176C293.791 53.976 294.991 54.984 295.887 56.2V52.408H302.655V79H295.887V75.112C295.023 76.36 293.823 77.4 292.287 78.232C290.783 79.032 289.039 79.432 287.055 79.432C284.815 79.432 282.767 78.856 280.911 77.704C279.087 76.552 277.631 74.936 276.543 72.856C275.487 70.744 274.959 68.328 274.959 65.608ZM295.887 65.704C295.887 64.072 295.567 62.68 294.927 61.528C294.287 60.344 293.423 59.448 292.335 58.84C291.247 58.2 290.079 57.88 288.831 57.88C287.583 57.88 286.431 58.184 285.375 58.792C284.319 59.4 283.455 60.296 282.783 61.48C282.143 62.632 281.823 64.008 281.823 65.608C281.823 67.208 282.143 68.616 282.783 69.832C283.455 71.016 284.319 71.928 285.375 72.568C286.463 73.208 287.615 73.528 288.831 73.528C290.079 73.528 291.247 73.224 292.335 72.616C293.423 71.976 294.287 71.08 294.927 69.928C295.567 68.744 295.887 67.336 295.887 65.704ZM315.938 43.48V79H309.218V43.48H315.938Z" fill="white"/>
</svg>;

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@ -0,0 +1,5 @@
<svg width="200" height="200" viewBox="0 0 268 243" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="103.125" cy="81" r="75" fill="#FF0000" />
<circle cx="209.125" cy="127.875" r="28.125" fill="#0075FF" />
<path d="M31.92 200.66V216.74C31.92 217.86 32.18 218.68 32.7 219.2C33.26 219.68 34.18 219.92 35.46 219.92H39.36V227H34.08C27 227 23.46 223.56 23.46 216.68V200.66H19.5V193.76H23.46V185.54H31.92V193.76H39.36V200.66H31.92ZM76.3017 209.66C76.3017 210.86 76.2217 211.94 76.0617 212.9H51.7617C51.9617 215.3 52.8017 217.18 54.2817 218.54C55.7617 219.9 57.5817 220.58 59.7417 220.58C62.8617 220.58 65.0817 219.24 66.4017 216.56H75.4617C74.5017 219.76 72.6617 222.4 69.9417 224.48C67.2217 226.52 63.8817 227.54 59.9217 227.54C56.7217 227.54 53.8417 226.84 51.2817 225.44C48.7617 224 46.7817 221.98 45.3417 219.38C43.9417 216.78 43.2417 213.78 43.2417 210.38C43.2417 206.94 43.9417 203.92 45.3417 201.32C46.7417 198.72 48.7017 196.72 51.2217 195.32C53.7417 193.92 56.6417 193.22 59.9217 193.22C63.0817 193.22 65.9017 193.9 68.3817 195.26C70.9017 196.62 72.8417 198.56 74.2017 201.08C75.6017 203.56 76.3017 206.42 76.3017 209.66ZM67.6017 207.26C67.5617 205.1 66.7817 203.38 65.2617 202.1C63.7417 200.78 61.8817 200.12 59.6817 200.12C57.6017 200.12 55.8417 200.76 54.4017 202.04C53.0017 203.28 52.1417 205.02 51.8217 207.26H67.6017ZM80.273 210.38C80.273 206.94 80.973 203.94 82.373 201.38C83.773 198.78 85.713 196.78 88.193 195.38C90.673 193.94 93.513 193.22 96.713 193.22C100.833 193.22 104.233 194.26 106.913 196.34C109.633 198.38 111.453 201.26 112.373 204.98H103.313C102.833 203.54 102.013 202.42 100.853 201.62C99.733 200.78 98.333 200.36 96.653 200.36C94.253 200.36 92.353 201.24 90.953 203C89.553 204.72 88.853 207.18 88.853 210.38C88.853 213.54 89.553 216 90.953 217.76C92.353 219.48 94.253 220.34 96.653 220.34C100.053 220.34 102.273 218.82 103.313 215.78H112.373C111.453 219.38 109.633 222.24 106.913 224.36C104.193 226.48 100.793 227.54 96.713 227.54C93.513 227.54 90.673 226.84 88.193 225.44C85.713 224 83.773 222 82.373 219.44C80.973 216.84 80.273 213.82 80.273 210.38ZM137.247 193.28C139.767 193.28 142.007 193.84 143.967 194.96C145.927 196.04 147.447 197.66 148.527 199.82C149.647 201.94 150.207 204.5 150.207 207.5V227H141.807V208.64C141.807 206 141.147 203.98 139.827 202.58C138.507 201.14 136.707 200.42 134.427 200.42C132.107 200.42 130.267 201.14 128.907 202.58C127.587 203.98 126.927 206 126.927 208.64V227H118.527V182.6H126.927V197.9C128.007 196.46 129.447 195.34 131.247 194.54C133.047 193.7 135.047 193.28 137.247 193.28ZM166.595 198.56C167.675 197.04 169.155 195.78 171.035 194.78C172.955 193.74 175.135 193.22 177.575 193.22C180.415 193.22 182.975 193.92 185.255 195.32C187.575 196.72 189.395 198.72 190.715 201.32C192.075 203.88 192.755 206.86 192.755 210.26C192.755 213.66 192.075 216.68 190.715 219.32C189.395 221.92 187.575 223.94 185.255 225.38C182.975 226.82 180.415 227.54 177.575 227.54C175.135 227.54 172.975 227.04 171.095 226.04C169.255 225.04 167.755 223.78 166.595 222.26V242.84H158.195V193.76H166.595V198.56ZM184.175 210.26C184.175 208.26 183.755 206.54 182.915 205.1C182.115 203.62 181.035 202.5 179.675 201.74C178.355 200.98 176.915 200.6 175.355 200.6C173.835 200.6 172.395 201 171.035 201.8C169.715 202.56 168.635 203.68 167.795 205.16C166.995 206.64 166.595 208.38 166.595 210.38C166.595 212.38 166.995 214.12 167.795 215.6C168.635 217.08 169.715 218.22 171.035 219.02C172.395 219.78 173.835 220.16 175.355 220.16C176.915 220.16 178.355 219.76 179.675 218.96C181.035 218.16 182.115 217.02 182.915 215.54C183.755 214.06 184.175 212.3 184.175 210.26ZM196.699 210.26C196.699 206.9 197.359 203.92 198.679 201.32C200.039 198.72 201.859 196.72 204.139 195.32C206.459 193.92 209.039 193.22 211.879 193.22C214.359 193.22 216.519 193.72 218.359 194.72C220.239 195.72 221.739 196.98 222.859 198.5V193.76H231.319V227H222.859V222.14C221.779 223.7 220.279 225 218.359 226.04C216.479 227.04 214.299 227.54 211.819 227.54C209.019 227.54 206.459 226.82 204.139 225.38C201.859 223.94 200.039 221.92 198.679 219.32C197.359 216.68 196.699 213.66 196.699 210.26ZM222.859 210.38C222.859 208.34 222.459 206.6 221.659 205.16C220.859 203.68 219.779 202.56 218.419 201.8C217.059 201 215.599 200.6 214.039 200.6C212.479 200.6 211.039 200.98 209.719 201.74C208.399 202.5 207.319 203.62 206.479 205.1C205.679 206.54 205.279 208.26 205.279 210.26C205.279 212.26 205.679 214.02 206.479 215.54C207.319 217.02 208.399 218.16 209.719 218.96C211.079 219.76 212.519 220.16 214.039 220.16C215.599 220.16 217.059 219.78 218.419 219.02C219.779 218.22 220.859 217.1 221.659 215.66C222.459 214.18 222.859 212.42 222.859 210.38ZM247.923 182.6V227H239.523V182.6H247.923Z" fill="white" />
</svg>

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@ -0,0 +1,4 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="11" cy="16" r="8" fill="#FF0000" />
<circle cx="25" cy="21" r="3" fill="#0075FF" />
</svg>

After

Width:  |  Height:  |  Size: 203 B

3
src/assets/svg/moon.svg Normal file
View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M20.9999 12.79C20.8426 14.4922 20.2038 16.1144 19.1581 17.4668C18.1125 18.8192 16.7034 19.8458 15.0956 20.4265C13.4878 21.0073 11.7479 21.1181 10.0794 20.7461C8.41092 20.3741 6.8829 19.5345 5.67413 18.3258C4.46536 17.117 3.62584 15.589 3.25381 13.9205C2.88178 12.252 2.99262 10.5121 3.57336 8.9043C4.15411 7.29651 5.18073 5.88737 6.53311 4.84175C7.8855 3.79614 9.5077 3.15731 11.2099 3C10.2133 4.34827 9.73375 6.00945 9.85843 7.68141C9.98312 9.35338 10.7038 10.9251 11.8893 12.1106C13.0748 13.2961 14.6465 14.0168 16.3185 14.1415C17.9905 14.2662 19.6516 13.7866 20.9999 12.79Z" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
</svg>;

After

Width:  |  Height:  |  Size: 757 B

3
src/assets/svg/phone.svg Normal file
View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2">
<path strokeLinecap="round" strokeLinejoin="round" d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z" />
</svg>;

After

Width:  |  Height:  |  Size: 413 B

View File

@ -0,0 +1,7 @@
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.6">
<path d="M11 19C15.4183 19 19 15.4183 19 11C19 6.58172 15.4183 3 11 3C6.58172 3 3 6.58172 3 11C3 15.4183 6.58172 19 11 19Z" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
<path d="M20.9999 21L16.6499 16.65" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 411 B

View File

@ -0,0 +1,11 @@
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2" y="2" width="4" height="4" rx="1" />
<rect x="10" y="2" width="4" height="4" rx="1" />
<rect x="18" y="2" width="4" height="4" rx="1" />
<rect x="2" y="10" width="4" height="4" rx="1" />
<rect x="10" y="10" width="4" height="4" rx="1" />
<rect x="18" y="10" width="4" height="4" rx="1" />
<rect x="2" y="18" width="4" height="4" rx="1" />
<rect x="10" y="18" width="4" height="4" rx="1" />
<rect x="18" y="18" width="4" height="4" rx="1" />
</svg>

After

Width:  |  Height:  |  Size: 550 B

View File

@ -0,0 +1,7 @@
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.6">
<path d="M4 3H20C20.5304 3 21.0391 3.21071 21.4142 3.58579C21.7893 3.96086 22 4.46957 22 5V11C22 13.6522 20.9464 16.1957 19.0711 18.0711C17.1957 19.9464 14.6522 21 12 21C10.6868 21 9.38642 20.7413 8.17317 20.2388C6.95991 19.7362 5.85752 18.9997 4.92893 18.0711C3.05357 16.1957 2 13.6522 2 11V5C2 4.46957 2.21071 3.96086 2.58579 3.58579C2.96086 3.21071 3.46957 3 4 3V3Z" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
<path d="M8 10L12 14L16 10" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 649 B

3
src/assets/svg/speed.svg Normal file
View File

@ -0,0 +1,3 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M27.1729 11.4266L25.5329 13.8933C26.3238 15.4707 26.711 17.2197 26.6598 18.9836C26.6086 20.7474 26.1206 22.4711 25.2396 24H6.75958C5.61447 22.0134 5.13997 19.7108 5.40643 17.4334C5.67289 15.156 6.66613 13.0251 8.23888 11.3565C9.81164 9.688 11.8802 8.57068 14.1379 8.17022C16.3956 7.76976 18.7222 8.10747 20.7729 9.13329L23.2396 7.49329C20.7282 5.88291 17.7493 5.1613 14.7794 5.44387C11.8095 5.72645 9.02017 6.99689 6.85757 9.05197C4.69497 11.1071 3.28406 13.8281 2.85054 16.7797C2.41701 19.7314 2.98591 22.7431 4.46625 25.3333C4.69893 25.7363 5.03303 26.0715 5.43535 26.3054C5.83768 26.5393 6.29421 26.6638 6.75958 26.6666H25.2262C25.6961 26.6685 26.1582 26.5462 26.5656 26.312C26.973 26.0779 27.3113 25.7402 27.5462 25.3333C28.7747 23.2052 29.3913 20.779 29.3277 18.3226C29.2642 15.8661 28.5231 13.4751 27.1862 11.4133L27.1729 11.4266ZM14.1196 20.5466C14.3672 20.7946 14.6613 20.9913 14.9851 21.1254C15.3088 21.2596 15.6558 21.3287 16.0062 21.3287C16.3567 21.3287 16.7037 21.2596 17.0274 21.1254C17.3511 20.9913 17.6453 20.7946 17.8929 20.5466L25.4396 9.22662L14.1196 16.7733C13.8716 17.021 13.675 17.3151 13.5408 17.6388C13.4066 17.9625 13.3375 18.3095 13.3375 18.66C13.3375 19.0104 13.4066 19.3574 13.5408 19.6811C13.675 20.0049 13.8716 20.299 14.1196 20.5466V20.5466Z" fill="white"/>
</svg>;

After

Width:  |  Height:  |  Size: 1.4 KiB

7
src/assets/svg/times.svg Normal file
View File

@ -0,0 +1,7 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.6">
<path d="M18 6L6 18" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
<path d="M6 6L18 18" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 316 B

View File

@ -0,0 +1,9 @@
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.6">
<path d="M16 21V19C16 17.9391 15.5786 16.9217 14.8284 16.1716C14.0783 15.4214 13.0609 15 12 15H5C3.93913 15 2.92172 15.4214 2.17157 16.1716C1.42143 16.9217 1 17.9391 1 19V21" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
<path d="M8.5 11C10.7091 11 12.5 9.20914 12.5 7C12.5 4.79086 10.7091 3 8.5 3C6.29086 3 4.5 4.79086 4.5 7C4.5 9.20914 6.29086 11 8.5 11Z" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
<path d="M20 8V14" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
<path d="M23 11H17" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 744 B

7
src/assets/svg/user.svg Normal file
View File

@ -0,0 +1,7 @@
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.6">
<path d="M20 21V19C20 17.9391 19.5786 16.9217 18.8284 16.1716C18.0783 15.4214 17.0609 15 16 15H8C6.93913 15 5.92172 15.4214 5.17157 16.1716C4.42143 16.9217 4 17.9391 4 19V21" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
<path d="M12 11C14.2091 11 16 9.20914 16 7C16 4.79086 14.2091 3 12 3C9.79086 3 8 4.79086 8 7C8 9.20914 9.79086 11 12 11Z" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 548 B

9
src/assets/svg/users.svg Normal file
View File

@ -0,0 +1,9 @@
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.6">
<path d="M17 21V19C17 17.9391 16.5786 16.9217 15.8284 16.1716C15.0783 15.4214 14.0609 15 13 15H5C3.93913 15 2.92172 15.4214 2.17157 16.1716C1.42143 16.9217 1 17.9391 1 19V21" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
<path d="M9 11C11.2091 11 13 9.20914 13 7C13 4.79086 11.2091 3 9 3C6.79086 3 5 4.79086 5 7C5 9.20914 6.79086 11 9 11Z" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
<path d="M23 21V19C22.9993 18.1137 22.7044 17.2528 22.1614 16.5523C21.6184 15.8519 20.8581 15.3516 20 15.13" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
<path d="M16 3.13C16.8604 3.35031 17.623 3.85071 18.1676 4.55232C18.7122 5.25392 19.0078 6.11683 19.0078 7.005C19.0078 7.89318 18.7122 8.75608 18.1676 9.45769C17.623 10.1593 16.8604 10.6597 16 10.88" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 996 B

View File

@ -0,0 +1,50 @@
import React from "react";
import { AuthStore } from "auth/domain/authStore";
import { authenticationUseCase } from "auth/useCases/authenticationUseCase";
import { authInitUseCase } from "auth/useCases/authInitUseCase";
import { signoutUseCase } from "auth/useCases/signoutUseCase";
function useAuthViewModel(store: AuthStore) {
const authenticate = React.useCallback(
function (code: string) {
authenticationUseCase(
{
authenticate: store.authenticate,
isLogedIn: store.isLogedIn,
},
code
);
},
[store.isLogedIn, store.authenticate]
);
const init = React.useCallback(
function () {
authInitUseCase({
init: store.init,
});
},
[store.init]
);
const signOut = React.useCallback(
function() {
console.warn("Sign out!")
signoutUseCase({
signOut: store.signOut
})
},
[store.signOut]
);
return {
isLogedIn: store.isLogedIn,
isLoading: store.isLoading,
isFailed: store.isFailed,
authenticate,
init,
signOut,
};
}
export { useAuthViewModel };

View File

@ -0,0 +1,6 @@
export const AUTH_INIT = "@authentication/state.init";
export const AUTH_LOGIN = "@authentication/login.exec";
export const DROP_AUTH = "@authentication/state.drop";
export const AUTH_LOGIN_COMPLETE = "@authentication/login.complete";
export const AUTH_LOGIN_FAILED = "@authentication/login.failure";
export const AUTH_LOGIN_REFRESH = "@authentication/login.refresh";

View File

@ -0,0 +1,39 @@
import { AuthCredentials } from "auth/domain/authEntity";
import * as actionTypes from "./authActionTypes";
import { auth, dropTokens, getTokens, signout } from "./authService";
const authInitAction = () => (dispatch: any) => {
dispatch({ type: actionTypes.AUTH_LOGIN });
const [access, refresh] = getTokens();
if (access && refresh) {
dispatch({ type: actionTypes.AUTH_LOGIN_COMPLETE });
return;
}
dispatch({ type: actionTypes.AUTH_LOGIN_FAILED });
};
const authenticateAction =
(code: string) =>
(dispatch: any): Promise<AuthCredentials | void> => {
dispatch({ type: actionTypes.AUTH_LOGIN });
return auth(code)
.then((credentials) => {
dispatch({ type: actionTypes.AUTH_LOGIN_COMPLETE });
return credentials;
})
.catch((reason) => {
dispatch({ type: actionTypes.AUTH_LOGIN_FAILED });
});
};
const dropAuth =
() =>
async (dispatch: any): Promise<void> => {
try {
await signout();
} catch (error) {}
dropTokens();
dispatch({ type: actionTypes.DROP_AUTH });
};
export { authenticateAction, authInitAction, dropAuth };

View File

@ -0,0 +1,33 @@
import { AnyAction } from "@reduxjs/toolkit";
import { AuthStore } from "auth/domain/authStore";
import * as actionTypes from "./authActionTypes";
type AuthStoreState = Omit<AuthStore, "authenticate" | "init" | "signOut">;
const INITIAL_STATE: AuthStoreState = {
isFailed: false,
isLoading: true,
isLogedIn: false,
};
const authReducer = (
state: AuthStoreState = INITIAL_STATE,
action: AnyAction
): AuthStoreState => {
switch (action.type) {
case actionTypes.AUTH_LOGIN_REFRESH:
case actionTypes.AUTH_LOGIN:
return { ...state, isLoading: true };
case actionTypes.AUTH_LOGIN_COMPLETE:
return { ...state, isLoading: false, isFailed: false, isLogedIn: true };
case actionTypes.AUTH_LOGIN_FAILED:
return { ...state, isLoading: false, isFailed: true, isLogedIn: false };
case actionTypes.DROP_AUTH:
return { ...state, isLoading: false, isFailed: false, isLogedIn: false };
default:
return state;
}
};
export { authReducer };
export type { AuthStoreState };

View File

@ -0,0 +1,172 @@
import { AuthCredentials } from "auth/domain/authEntity";
import axios, { AxiosError, AxiosRequestConfig } from "axios";
import { AuthDTO } from "./dto";
const BASE_URL = process.env.REACT_APP_INTEGRATOR_URL;
export const GRAPHQL_URL = process.env.REACT_APP_GRAPHQL_URL ?? "";
const instance = axios.create({
baseURL: BASE_URL + (process.env.REACT_APP_INTEGRATOR_API_VERSION ?? ""),
});
export const graphQlConfig: AxiosRequestConfig = {
baseURL: BASE_URL + (GRAPHQL_URL ?? ""),
headers: {
"X-Activity-Trace-Method": "GRAPHQL",
},
};
const integratorApiClient = axios.create({
baseURL: BASE_URL + (process.env.REACT_APP_INTEGRATOR_API_VERSION ?? ""),
});
integratorApiClient.interceptors.request.use(
async (config) => {
const [access] = getTokens();
config.headers = Object.assign({}, config.headers, {
Authorization: `Bearer ${access}`,
Accept: "application/json",
"Content-Type": "application/json",
});
return config;
},
(error) => {
Promise.reject(error);
}
);
integratorApiClient.interceptors.response.use(
(response) => {
return response;
},
async function (error: AxiosError) {
const originalRequest: AxiosRequestConfig & { _retry?: boolean } =
error.config;
if (error.response?.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
try {
await refresh();
} catch (e) {
const replacement: AxiosError = {
...error,
response: {
...error.response,
status: 401,
},
};
return Promise.reject(replacement);
}
return integratorApiClient(originalRequest);
}
return Promise.reject(error);
}
);
/**
* Returns user authoriztion tokens
* @returns {[string, string]}
*/
function getTokens() {
return [
localStorage.getItem("accessToken"),
localStorage.getItem("refreshToken"),
];
}
/**
* Stores user authentication tokens
* @param accessToken User authentication access token
* @param refreshToken User authentication refresh token
*/
function setTokens(accessToken: string, refreshToken: string) {
localStorage.setItem("accessToken", accessToken);
localStorage.setItem("refreshToken", refreshToken);
}
/**
* Drops authentication tokens from storage
*/
function dropTokens() {
localStorage.removeItem("accessToken");
localStorage.removeItem("refreshToken");
}
/**
* User authorisation service call
* @returns Promised authentication credentials information
*/
function auth(code: string): Promise<AuthCredentials> {
return new Promise((resolve, reject) => {
instance
.post<AuthDTO>("/account/login", {
code: code,
})
.then((response) => {
const content = response.data;
setTokens(content.data.access_token, content.data.refresh_token);
resolve({
accessToken: content.data.access_token,
refreshToken: content.data.refresh_token,
});
})
.catch((reason) => {
reject(reason);
});
});
}
/**
* Terminates user session
* @returns
*/
async function signout(): Promise<void> {
const refresh = getTokens()[1];
if (!refresh) {
dropTokens();
}
await instance.post("/account/logout", {
refresh_token: refresh,
});
}
/**
* User authorisation refresh service call
* @returns Promised authentication credentials information
*/
function refresh(): Promise<AuthCredentials> {
const [access, refresh] = getTokens();
return new Promise((resolve, reject) => {
instance
.post<AuthDTO>(
"/account/refresh-token",
{
client_id: "techpal",
refresh_token: refresh,
grant_type: "refresh_token",
},
{
headers: {
Authorization: `Bearer: ${access}`,
},
}
)
.then((response) => {
const content = response.data;
setTokens(content.data.access_token, content.data.refresh_token);
resolve({
accessToken: content.data.access_token,
refreshToken: content.data.refresh_token,
});
})
.catch((reason) => {
reject(reason);
});
});
}
export {
getTokens,
setTokens,
dropTokens,
auth,
refresh,
signout,
integratorApiClient,
};

View File

@ -0,0 +1,34 @@
import React from "react";
import type { AuthStore } from "auth/domain/authStore";
import type { AuthStoreState } from "./authReducer";
import { authenticateAction, authInitAction, dropAuth } from "./authActions";
import { RootState, useAppDispatch, useAppSelector } from "store";
const authSelector = (state: RootState): AuthStoreState => state.auth;
const useAuthStore = (): AuthStore => {
const { isFailed, isLoading, isLogedIn } = useAppSelector(authSelector);
const dispatch = useAppDispatch();
const authenticate = React.useCallback(
(code: string) => authenticateAction(code)(dispatch),
[dispatch]
);
const init = React.useCallback(() => authInitAction()(dispatch), [dispatch]);
const signOut = React.useCallback(() => dropAuth()(dispatch), [dispatch]);
return {
isLogedIn,
isFailed,
isLoading,
authenticate,
signOut,
init,
};
};
export { useAuthStore };

21
src/auth/data/dto.ts Normal file
View File

@ -0,0 +1,21 @@
import { DTOModel } from "core/dto_model";
export interface AuthDTO
extends DTOModel<{
access_token: string;
refresh_token: string;
token_type: string;
expires_in: number;
refresh_expires_in: number;
}> {}
export interface AuthRequest {
code: string;
}
export interface AccessTokenDTO {
email: string,
given_name: string;
family_name: string;
preferred_username: string;
}

View File

@ -0,0 +1,4 @@
export interface AuthCredentials {
accessToken: string;
refreshToken: string;
}

View File

@ -0,0 +1,28 @@
import { AuthCredentials } from "./authEntity";
const create = (
accessToken: AuthCredentials["accessToken"],
refreshToken: AuthCredentials["refreshToken"]
): AuthCredentials => ({
accessToken: accessToken,
refreshToken: refreshToken,
});
const update = (
credentials: AuthCredentials,
payload: Partial<AuthCredentials>
) => ({
...credentials,
...payload,
});
const refreshTokens = (
credentials: AuthCredentials,
payload: Required<Pick<AuthCredentials, "accessToken" | "refreshToken">>
) =>
update(credentials, {
accessToken: payload.accessToken,
refreshToken: payload.refreshToken,
});
export { create, update, refreshTokens };

View File

@ -0,0 +1,12 @@
import { AuthCredentials } from "./authEntity";
interface AuthStore {
isLogedIn: boolean,
isLoading: boolean,
isFailed: boolean,
authenticate(code: string): Promise<AuthCredentials | void>,
signOut(): Promise<void>,
init(): void;
}
export type { AuthStore };

76
src/auth/hoc/withAuth.tsx Normal file
View File

@ -0,0 +1,76 @@
/* -------------------------------------------------------------------------- */
/* Libraries */
/* -------------------------------------------------------------------------- */
import React, { useEffect } from "react";
/* -------------------------------------------------------------------------- */
/* Types */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* Misc */
/* -------------------------------------------------------------------------- */
import { useAuthViewModel } from "auth/controller/useAuthViewModel";
import { useAuthStore } from "auth/data/authSlice";
/* -------------------------------------------------------------------------- */
/* Helpers */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* Components */
/* -------------------------------------------------------------------------- */
import AppLoader from "components/parts/Loader";
import { useLocation, useNavigate, useSearchParams } from "react-router-dom";
import AuthFailure from "pages/AuthFailure";
/* -------------------------------------------------------------------------- */
/* Authentication logic HOC component */
/* -------------------------------------------------------------------------- */
const withAuth = <P extends {}>(
Component: React.ComponentType<P>,
componentName = Component.displayName ?? Component.name
): {
(props: P): JSX.Element;
displayName: string;
} => {
function WithAuthComponent(props: P) {
const store = useAuthStore();
const [searchParams] = useSearchParams();
const navigate = useNavigate();
const location = useLocation();
const { init, isLoading, isFailed, isLogedIn, authenticate } =
useAuthViewModel(store);
const code = searchParams.get("code");
useEffect(() => {
if(isFailed) {
return;
}
if (code) {
authenticate(code);
navigate(location.pathname, {
replace: true,
});
return;
}
if (!isLogedIn) {
init();
navigate(location.pathname, {
replace: true,
});
}
}, [isFailed, isLogedIn, code, authenticate, init, navigate, location]);
if (isLoading) {
return <AppLoader />;
}
if (!isLogedIn) {
return <AuthFailure />;
}
return <Component {...props} />;
}
WithAuthComponent.displayName = `withAuth(${componentName})`;
return WithAuthComponent;
};
export { withAuth };

View File

@ -0,0 +1,9 @@
import { AuthStore } from "auth/domain/authStore";
type AuthInitStore = Pick<AuthStore, "init">;
const authInitUseCase = (store: AuthInitStore) => {
store.init();
}
export {authInitUseCase};

View File

@ -0,0 +1,9 @@
import { AuthStore } from "auth/domain/authStore";
type AuthenticationStore = Pick<AuthStore, "authenticate" | "isLogedIn">
const authenticationUseCase = (store: AuthenticationStore, code: string) => {
store.authenticate(code);
};
export { authenticationUseCase };

View File

@ -0,0 +1,10 @@
import { AuthStore } from "auth/domain/authStore";
import { is } from "immer/dist/internal";
type LogoutStore = Pick<AuthStore, "signOut">;
const signOutUseCase = (store: LogoutStore) => {
store.signOut();
};
export { signOutUseCase as signoutUseCase };

View File

@ -0,0 +1,30 @@
import React from "react";
export default function CircleLoader() {
return (
<svg
className="pl w-full h-full"
viewBox="0 0 128 128"
xmlns="http://www.w3.org/2000/svg"
>
<defs>
<linearGradient id="pl-grad" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor="rgb(0,117,255)" />
<stop offset="100%" stopColor="rgb(0,48,102)" />
</linearGradient>
</defs>
<path
className="pl__worm"
d="M92,15.492S78.194,4.967,66.743,16.887c-17.231,17.938-28.26,96.974-28.26,96.974L119.85,59.892l-99-31.588,57.528,89.832L97.8,19.349,13.636,88.51l89.012,16.015S81.908,38.332,66.1,22.337C50.114,6.156,36,15.492,36,15.492a56,56,0,1,0,56,0Z"
fill="none"
stroke="url(#pl-grad)"
strokeWidth="16"
strokeLinecap="round"
strokeLinejoin="round"
strokeDasharray="44 1111"
strokeDashoffset="10"
/>
</svg>
);
}

View File

@ -0,0 +1,69 @@
import classNames from "classnames";
import { StyleColorVariants, StyleColorVariantsMap } from "core/_variants";
import React from "react";
type Props = {
className?: string | undefined;
children: string;
fontSize?: number;
variant?: StyleColorVariants | undefined;
};
const hexagonStyles: StyleColorVariantsMap<string> = {
gray: "fill-gray-500",
pink: "fill-pink-500",
blue: "fill-blue-500",
purple: "fill-purple-500",
red: "fill-red-500",
yellow: "fill-yellow-600",
emerald: "fill-emerald-500",
sky: "fill-sky-500",
"dark-coral": "fill-dark-coral-500"
};
/**
* Hexagon sign
* @param {string} children Characters to exclude from svg figure
* @param {string|undefined} className Classes used to customize svg element
* @param {number} fontSize Font size for excluding characters
* @return {JSX.Element}
*/
export default function Hexagon({
className,
children,
fontSize = 24,
variant = "blue",
}: Props): JSX.Element {
const classes = hexagonStyles[variant];
return (
<svg
viewBox="0 0 60 60"
xmlns="http://www.w3.org/2000/svg"
className={classNames(className, classes)}
>
{fontSize && (
<defs>
<mask id={children} maskUnits="userSpaceOnUse">
<rect width="100%" height="100%" fill="white" />
<text
textAnchor="middle"
x="30"
y="38"
fontSize={fontSize}
fontWeight="bold"
fontFamily="Poppins"
>
{children}
</text>
</mask>
</defs>
)}
<path
// eslint-disable-next-line max-len
d="M27 1.73205C28.8564 0.660254 31.1436 0.660254 33 1.73205L52.9808 13.2679C54.8372 14.3397 55.9808 16.3205 55.9808 18.4641V41.5359C55.9808 43.6795 54.8372 45.6603 52.9808 46.7321L33 58.2679C31.1436 59.3397 28.8564 59.3397 27 58.2679L7.01924 46.7321C5.16283 45.6603 4.01924 43.6795 4.01924 41.5359V18.4641C4.01924 16.3205 5.16283 14.3397 7.01924 13.2679L27 1.73205Z"
fillRule="evenodd"
mask={fontSize ? `url(#${children})` : ""}
/>
</svg>
);
}

View File

@ -0,0 +1,65 @@
import classNames from "classnames";
import { StyleColorVariants, StyleColorVariantsMap } from "core/_variants";
import React from "react";
type Props = {
className?: string | undefined;
children: string;
fontSize?: number;
variant?: StyleColorVariants | undefined;
};
const hexagonStyles: StyleColorVariantsMap<string> = {
gray: "stroke-gray-500",
pink: "stroke-pink-500",
blue: "stroke-blue-500",
purple: "stroke-purple-500",
red: "stroke-red-500",
yellow: "stroke-yellow-600",
emerald: "stroke-emerald-500",
sky: "stroke-sky-500",
"dark-coral": "stroke-dark-coral-500",
};
/**
* Hexagon sign
* @param {string} children Characters to exclude from svg figure
* @param {string|undefined} className Classes used to customize svg element
* @param {number} fontSize Font size for excluding characters
* @return {JSX.Element}
*/
export default function HexagonOutlined({
className,
children,
fontSize = 24,
variant,
}: Props): JSX.Element {
const classes = variant ? hexagonStyles[variant] : "stroke-white";
return (
<svg
viewBox="0 0 60 60"
xmlns="http://www.w3.org/2000/svg"
className={classNames(className, classes)}
>
<path
// eslint-disable-next-line max-len
d="M27 1.73205C28.8564 0.660254 31.1436 0.660254 33 1.73205L52.9808 13.2679C54.8372 14.3397 55.9808 16.3205 55.9808 18.4641V41.5359C55.9808 43.6795 54.8372 45.6603 52.9808 46.7321L33 58.2679C31.1436 59.3397 28.8564 59.3397 27 58.2679L7.01924 46.7321C5.16283 45.6603 4.01924 43.6795 4.01924 41.5359V18.4641C4.01924 16.3205 5.16283 14.3397 7.01924 13.2679L27 1.73205Z"
fillRule="evenodd"
fill="none"
/>
<text
x="50%"
y="50%"
dominantBaseline="middle"
textAnchor="middle"
fontSize={fontSize}
fontWeight="bold"
fontFamily="Poppins"
fill="white"
stroke="none"
>
{children}
</text>
</svg>
);
}

View File

@ -0,0 +1,27 @@
import React from 'react';
import {ReactComponent as SVGLogotype} from 'assets/svg/logotype.svg';
import { Link } from 'react-router-dom';
type Props = {
name?: string;
}
/**
* Horizontal variant of logotype component
* @param {string} name Name of service to attach to logotype
* @return {React.ReactNode}
*/
export default function Logotype({name}: Props): JSX.Element {
return (
<div className="inline-flex flex-row flex-nowrap items-center">
<div className="flex-none">
<Link to="/">
<SVGLogotype className="w-8 h-8 mr-2" />
</Link>
</div>
<div className="flex-initial text-2xl font-bold">
{name ?? ''} {process.env.REACT_APP_CMS_APP_NAME?.toLowerCase()}
</div>
</div>
);
}

55
src/components/Page.tsx Normal file
View File

@ -0,0 +1,55 @@
import classNames from "classnames";
import React, { useEffect, useLayoutEffect } from "react";
import Scrollbar from "react-scrollbars-custom";
import { WithRouteProps } from "routes";
import { withRouteParams } from "routes/withRoute";
import { useUIViewModel } from "ui/controller/uiViewModel";
import { useUIStore } from "ui/data/uiSlice";
import DrawerController from "ui/views/DrawerController";
import Header from "./parts/Header";
import SideNav from "./parts/sidenav/SideNav";
type Props = {
title?: string;
withOutlet?: boolean;
children: React.ReactElement<WithRouteProps>;
} & WithRouteProps;
const Page = ({ title, withOutlet, children, activePath }: Props) => {
const uiStore = useUIStore();
const { isDrawerCollapsed, initDrawer } = useUIViewModel(uiStore);
useLayoutEffect(() => {
initDrawer();
}, [initDrawer]);
return (
<div className="grid grid-flow-col grid-rows-page grid-cols-layout max-h-screen overflow-hidden transition-all">
<header className="col-span-2">
<Header title={title} />
</header>
<aside
className={classNames(
"group overflow-hidden space-y-1 pt-6 bg-aside border-serv-800 transition-[width]",
isDrawerCollapsed ? "w-24" : "1.5xl:w-80 2xl:w-96"
)}
>
<Scrollbar>
<div className="px-6 py-1">
<SideNav collapsed={isDrawerCollapsed} />
</div>
</Scrollbar>
</aside>
<main className="relative rounded-lg m-2 pl-24 bg-main shadow-lg shadow-serv-900/20">
<div className="absolute -left-5 top-6">
<DrawerController />
</div>
<Scrollbar>
<div className="px-8 pt-20">{children}</div>
</Scrollbar>
</main>
</div>
);
};
export default withRouteParams(Page);

View File

@ -0,0 +1,22 @@
import { withAuth } from "auth/hoc/withAuth";
import React from "react";
import { RouteObject, useRoutes } from "react-router-dom";
import { RoutePathDefinition } from "routes";
import { mapDefinitionToRoute } from "routes/mapDefinitionToRoute";
type Props = {
routes: RoutePathDefinition[];
};
const RoutesRenderer = ({ routes }: Props) => {
const mappedRoutes = React.useMemo<RouteObject[]>( () => {
return routes.map<RouteObject>((props) => mapDefinitionToRoute(props));
}, [routes]);
const Renderer = useRoutes(mappedRoutes);
return Renderer;
}
export default withAuth(RoutesRenderer);

View File

@ -0,0 +1,37 @@
import React from 'react';
import classNames from 'classnames';
import ServiceComponent from './containers/ServiceComponent';
import { Service } from 'services/domain/serviceEntity';
type Props = {
service: Service;
disabled?: boolean | undefined;
};
/**
* Service link component
* @param {Service} service Service object
* @return {JSX.Element}
*/
export default function ServiceLink({service, disabled = false}: Props) {
return (
<a
href={service.href}
className={classNames([
'box-border flex',
'transition-colors rounded-lg px-3 py-2',
'my-1 hover:bg-gray-400/10',
{'opacity-20 pointer-events-none': disabled},
])}
>
<ServiceComponent variant={service.variant} clipText={service.shortName}>
<div className="text-lg font-bold leading-tight">{service.name}</div>
{disabled ? (
<span className="text-xs text-right text-gray">soon</span>
) : (
<span className="text-xs text-gray-500">{service.href}</span>
)}
</ServiceComponent>
</a>
);
}

View File

@ -0,0 +1,16 @@
import React from "react";
import { WithRouteProps } from "routes";
type Props = {
children: React.ReactElement<WithRouteProps>;
};
export default function StandalonePage({ children }: Props) {
return (
<div className="grid grid-flow-col grid-rows-page grid-cols-layout max-h-screen overflow-hidden transition-all">
<main className="col-span-2 row-span-2 relative rounded-lg m-2 pl-24 bg-main shadow-lg shadow-serv-900/20">
{children}
</main>
</div>
);
}

View File

@ -0,0 +1,35 @@
/* -------------------------------------------------------------------------- */
/* Libraries */
/* -------------------------------------------------------------------------- */
import React from "react";
/* -------------------------------------------------------------------------- */
/* SVG */
/* -------------------------------------------------------------------------- */
import { ReactComponent as SVGUserIcon } from "assets/svg/user.svg";
import classNames from "classnames";
/* -------------------------------------------------------------------------- */
/* Avatar container */
/* -------------------------------------------------------------------------- */
type Props = {
children?: React.ReactNode;
width?: string;
className?:string |undefined;
};
export default function Avatar({ children, width, className }: Props) {
return (
<div
className="relative w-9 h-9 rounded-full bg-gray-400/30 overflow-hidden"
style={{ width: width, paddingTop: width }}
>
<div className={classNames(["absolute top-0 left-0 w-full h-full", className])}>
{children ? (
children
) : (
<SVGUserIcon className="w-full h-full stroke-current" />
)}
</div>
</div>
);
}

View File

@ -0,0 +1,43 @@
import classNames from "classnames";
import { StyleColorVariants, StyleColorVariantsMap } from "core/_variants";
import React from "react";
type Props = {
children: React.ReactNode;
className?: string;
variant?: StyleColorVariants;
};
const backgrounds: StyleColorVariantsMap<string> = {
blue: "bg-blue-500",
emerald: "bg-emerald-500",
gray: "bg-gray-800",
pink: "bg-pink-500",
purple: "bg-purple-500",
red: "bg-red-500",
sky: "bg-sky-500",
yellow: "bg-yellow-500",
"dark-coral": "bg-dark-coral-500",
};
/**
* Card component
* @param {string|undefined} className Card customization classes
* @param {React.ReactNode} children Children to paste inside Card component
* @return {JSX.Element}
*/
export default function Card({ children, className, variant }: Props) {
return (
<div
className={classNames([
"rounded-lg w-full px-3 py-4",
{
[`${backgrounds[variant ?? "blue"]}`]: variant,
},
className,
])}
>
{children}
</div>
);
}

View File

@ -0,0 +1,39 @@
import classNames from 'classnames';
import {StyleColorVariants, StyleColorVariantsMap} from 'core/_variants';
import React from 'react';
type Props = {
variant: StyleColorVariants;
children: React.ReactNode;
};
const markerVariant: StyleColorVariantsMap<string> = {
gray: 'bg-gray-500 shadow-gray-500',
blue: 'bg-blue-500 shadow-blue-500',
pink: 'bg-pink-500 shadow-pink-500',
red: 'bg-red-500 shadow-red-500',
purple: 'bg-purple-500 shadow-purple-500',
yellow: 'bg-yellow-500 shadow-yellow-500',
emerald: 'bg-emerald-500 shadow-emerald-500',
sky: 'bg-sky-500 shadow-sky-500',
"dark-coral": "bg-dark-coral-500 shadow-dark-coral-500",
};
/**
* Cirlce shape to wrap [children]
* @param {React.ReactNode} children Children to paste inside circle shape
* @param {StyleColorVariants} variant Varant of marker
* @return {JSX.Element}
*/
export default function CircleMarker({variant, children}: Props) {
return (
<div
className={classNames([
'w-11 h-11 rounded-full shadow-xl flex items-center justify-center p-3',
markerVariant[variant],
])}
>
{children}
</div>
);
}

View File

@ -0,0 +1,32 @@
import classNames from 'classnames';
import React from 'react';
type Props = {
marker: React.ReactNode;
children: React.ReactNode;
className?: string | undefined;
};
/**
* Marked children
* @param {React.ReactNode} marker Marker component
* @return {React.ReactNode}
*/
export default function MarkedItem({
marker,
children,
className,
}: Props): JSX.Element {
return (
<div
className={classNames(
'flex flex-col sm:flex-row text-center',
'sm:text-left items-center sm:items-start',
className,
)}
>
<div className="flex-none mb-4 sm:mb-0">{marker}</div>
<div className="flex-1 sm:ml-6">{children}</div>
</div>
);
}

View File

@ -0,0 +1,24 @@
import Hexagon from 'components/Hexagon'
import { StyleColorVariants } from 'core/_variants';
import React from 'react'
type Props = {
variant?: StyleColorVariants | undefined;
children: React.ReactNode;
clipText: string;
}
export default function ServiceComponent({variant, children, clipText}: Props) {
return (
<div className="flex flex-row items-center">
<div className="inline-block w-12 h-12 mr-4">
<Hexagon variant={variant} className="w-full h-full transition-colors" fontSize={24}>
{clipText}
</Hexagon>
</div>
<div className="flex-1">
{children}
</div>
</div>
)
}

View File

@ -0,0 +1,13 @@
import React from 'react'
type Props = {
children: React.ReactNode;
}
export default function Area({children}: Props) {
return (
<section className='mb-20'>
{children}
</section>
)
}

View File

@ -0,0 +1,14 @@
import classNames from 'classnames';
import React from 'react'
type Props = {
className?: string | undefined;
children?: string | undefined;
secondary?: boolean;
}
export default function AreaCaption({children, className, secondary}: Props) {
return (
<h3 className={classNames("text-xl font-medium leading-none", className, secondary? "text-white/60": "")}>{children}</h3>
)
}

View File

@ -0,0 +1,13 @@
import React from 'react'
type Props = {
children?: React.ReactNode;
}
export default function AreaDescription({children}: Props) {
return (
<div className="text-sm text-gray-300/50 mt-2.5">
{children}
</div>
)
}

View File

@ -0,0 +1,11 @@
import React from 'react'
type Props = {
children: React.ReactNode;
}
export default function AreaValue({children}: Props) {
return (
<h3 className="text-2xl text-current font-bold leading-relaxed">{children}</h3>
);
}

View File

@ -0,0 +1,23 @@
import React from 'react'
import AreaCaption from './AreaCaption';
type Props = {
caption: string;
icon?: React.ReactNode;
}
export default function IconedAreaCaption({icon, caption}: Props) {
if(icon) {
return (
<div className="flex items-center space-x-2">
<div className="flex-none w-6 h-6">
{icon}
</div>
<AreaCaption secondary={true} className='flex-1'>{caption}</AreaCaption>
</div>
)
}
return (
<AreaCaption>{caption}</AreaCaption>
)
}

Some files were not shown because too many files have changed in this diff Show More