main
Anton Zhuravlev 1 year ago
parent efd487f632
commit 0608c44723

@ -1,13 +1,21 @@
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import styles from './app.module.scss';
import NxWelcome from './nx-welcome';
import {Routes, Route} from "react-router-dom"
// eslint-disable-next-line @nx/enforce-module-boundaries
import Main from "../../../../page/src/lib//main/main"
// eslint-disable-next-line @nx/enforce-module-boundaries
import {Navbar} from "@perm-hack/ui";
import {Statistics} from "@perm-hack/page";
export function App() {
return (
<div>
<NxWelcome title="crud" />
</div>
<main>
<Navbar/>
<Routes>
<Route element={<Main/>} path="/"/>
<Route element={<Statistics/>} path="/statistics"/>
</Routes>
</main>
);
}

@ -2,12 +2,15 @@ import { StrictMode } from 'react';
import * as ReactDOM from 'react-dom/client';
import App from './app/app';
import {BrowserRouter} from "react-router-dom";
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<StrictMode>
<App />
<BrowserRouter>
<App />
</BrowserRouter>
</StrictMode>
);

@ -1,4 +1,29 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
/* You can add global styles to this file, and also import other style files */
@font-face {
font-family: "Bion";
font-weight: 400;
src: local('Bion'), url(../assets/fonts/bion-book.otf) format("otf");
src: local('Bion'), url(../assets/fonts/bion-book.ttf) format("ttf");
src: local('Bion'), url(../assets/fonts/bion-book.woff) format("woff");
src: local('Bion'), url(../assets/fonts/bion-book.woff2) format("woff2");
}
#root {
--bg: #D9D9D9;
--white: #fff;
--black: #000;
--gray: #4A4A4A;
--green: #65843F;
--border-large: 42px;
--border-medium: 28px;
font-family: "Bion", sans-serif;
font-size: 20px;
}

1023
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -9,11 +9,16 @@
"@nestjs/core": "^10.0.2",
"@nestjs/platform-express": "^10.0.2",
"@swc/helpers": "~0.5.2",
"@tanstack/react-query": "^5.0.5",
"@types/classnames": "^2.3.1",
"@types/react-router-dom": "^5.3.3",
"antd": "^5.10.2",
"axios": "^1.0.0",
"classnames": "^2.3.2",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-router-dom": "^6.17.0",
"react-switch-selector": "^2.2.1",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.8.0",
"tslib": "^2.3.0"

@ -1 +1,3 @@
export * from './lib/statistics/statistics';
export * from './lib/main/main';
export * from './lib/page';

@ -0,0 +1,8 @@
.container {
margin: 0 20px;
padding: 20px;
border-radius: 42px;
background-color: var(--bg);
display: flex;
gap: 0 50px;
}

@ -0,0 +1,10 @@
import { render } from '@testing-library/react';
import Main from './main';
describe('Main', () => {
it('should render successfully', () => {
const { baseElement } = render(<Main />);
expect(baseElement).toBeTruthy();
});
});

@ -0,0 +1,19 @@
import styles from './main.module.scss';
// eslint-disable-next-line @nx/enforce-module-boundaries
import {Camera, Sidebar} from "@perm-hack/ui";
/* eslint-disable-next-line */
export interface MainProps {
}
export function Main(props: MainProps) {
return (
<div className={styles.container}>
<Sidebar/>
<Camera/>
</div>
);
}
export default Main;

@ -0,0 +1,5 @@
.container {
padding: 20px;
display: flex;
flex-direction: column;
}

@ -0,0 +1,10 @@
import { render } from '@testing-library/react';
import Statistics from './statistics';
describe('Statistics', () => {
it('should render successfully', () => {
const { baseElement } = render(<Statistics />);
expect(baseElement).toBeTruthy();
});
});

@ -0,0 +1,15 @@
import cls from './statistics.module.scss';
import {Filters} from "@perm-hack/ui";
/* eslint-disable-next-line */
export interface StatisticsProps {}
export function Statistics(props: StatisticsProps) {
return (
<div className={cls.container}>
<Filters/>
</div>
);
}
export default Statistics;

@ -1 +1,7 @@
export * from './lib/filters/filters';
export * from './lib/button/button';
export * from './lib/sidebar-item/sidebar-item';
export * from './lib/camera/camera';
export * from './lib/sidebar/sidebar';
export * from './lib/navbar/navbar';
export * from './lib/ui';

@ -0,0 +1,15 @@
.button {
font-size: 18px;
font-style: normal;
font-weight: 300;
line-height: normal;
border: 1px solid var(--black);
border-radius: var(--border-medium);
padding: 2px 10px;
& a {
display: flex;
align-items: center;
gap: 2px;
}
}

@ -0,0 +1,10 @@
import { render } from '@testing-library/react';
import Button from './button';
describe('Button', () => {
it('should render successfully', () => {
const { baseElement } = render(<Button />);
expect(baseElement).toBeTruthy();
});
});

@ -0,0 +1,25 @@
import cls from './button.module.scss';
import {DetailedHTMLProps, HTMLAttributes, ReactNode} from "react";
import {Link} from "react-router-dom";
import cn from "classnames"
/* eslint-disable-next-line */
export interface ButtonProps extends DetailedHTMLProps<HTMLAttributes<HTMLButtonElement>, HTMLButtonElement>{
children: ReactNode
link: string
}
export function Button({link, children, className, ...props}: ButtonProps) {
return (
<button className={cn(cls.button, className)}>
<Link to={link}>
{children}
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.375 10.625L10.625 4.375" stroke="#4A4A4A" strokeLinecap="round" strokeLinejoin="round"/>
<path d="M4.375 4.375H10.625V10.625" stroke="#4A4A4A" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
</Link>
</button>
);
}
export default Button;

@ -0,0 +1,64 @@
.container {
display: flex;
flex-direction: column;
align-items: end;
flex: 1 1 auto;
padding: 20px;
background-color: var(--white);
border-radius: var(--border-large);
}
.select {
border: 1px solid var(--black);
border-radius: 15px;
display: flex;
align-items: center;
& div {
padding: 5px 15px;
display: flex;
flex-direction: column;
align-items: end;
}
& div:not(:first-child) {
flex-direction: row;
gap: 5px;
align-items: center;
}
& .date {
color: var(--green);
font-size: 16px;
font-style: normal;
font-weight: 300;
line-height: normal;
}
& .time {
font-size: 16px;
font-style: normal;
font-weight: 300;
line-height: normal;
}
& .line {
height: 100%;
width: 1px;
background-color: var(--black);
}
& .name {
color: var(--green);
font-size: 20px;
font-style: normal;
font-weight: 300;
line-height: normal;
}
& .number {
font-size: 24px;
font-style: normal;
font-weight: 300;
line-height: normal;
}
}

@ -0,0 +1,10 @@
import { render } from '@testing-library/react';
import Camera from './camera';
describe('Camera', () => {
it('should render successfully', () => {
const { baseElement } = render(<Camera />);
expect(baseElement).toBeTruthy();
});
});

@ -0,0 +1,42 @@
import cls from './camera.module.scss';
/* eslint-disable-next-line */
export interface CameraProps {
}
export function Camera(props: CameraProps) {
return (
<div className={cls.container}>
<div className={cls.select}>
<div>
<p className={cls.date}>
2020-23-21
</p>
<p className={cls.time}>
14:32
</p>
</div>
<span className={cls.line}></span>
<div>
<p className={cls.name}>
Cum
</p>
<p className={cls.number}>
69
</p>
<svg width="24" height="22" viewBox="0 0 24 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21 9.16699H3" stroke="black" strokeLinecap="round" strokeLinejoin="round"/>
<path d="M21 5.5H3" stroke="black" strokeLinecap="round" strokeLinejoin="round"/>
<path d="M21 12.833H3" stroke="black" strokeLinecap="round" strokeLinejoin="round"/>
<path d="M21 16.5H3" stroke="black" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
</div>
</div>
<div>
here camera
</div>
</div>
);
}
export default Camera;

@ -0,0 +1,12 @@
.container {
display: flex;
flex-direction: row;
gap: 30px;
}
.button {
font-size: 14px;
border-radius: 20px;
padding: 5px 10px;
color: var(--white);
background-color: #94BF5E;
}

@ -0,0 +1,10 @@
import { render } from '@testing-library/react';
import Filters from './filters';
describe('Filters', () => {
it('should render successfully', () => {
const { baseElement } = render(<Filters />);
expect(baseElement).toBeTruthy();
});
});

@ -0,0 +1,64 @@
import cls from './filters.module.scss';
import {ConfigProvider, DatePicker} from "antd";
import SwitchSelector from "react-switch-selector";
import dayjs from 'dayjs';
import customParseFormat from 'dayjs/plugin/customParseFormat';
import {useState} from "react";
/* eslint-disable-next-line */
enum timeFormatEnum {
DATE = "date",
PERIOD = "period"
}
export function Filters() {
const [timeFormat, setTimeFormat] = useState<timeFormatEnum>(timeFormatEnum.DATE)
const options = [
{
label: "Дата",
value: "date",
selectedBackgroundColor: "#94BF5E"
},
{
label: "Период",
value: "period",
selectedBackgroundColor: "#94BF5E"
},
]
const handleChange = (time: never, timeString: string) => {
console.log(timeString)
}
const onChange = (newValue: timeFormatEnum) => {
setTimeFormat(newValue)
};
return (
<div className={cls.container}>
<div className="your-required-wrapper" style={{width: 200, height: 30}}>
<SwitchSelector
onChange={onChange}
options={options}
fontSize={16}
backgroundColor={"#fff"}
fontColor={"#94BF5E"}
border={"1px solid #94BF5E"}
/>
</div>
<ConfigProvider theme={{
token: {
colorPrimary: "#94BF5E"
}
}}>
{timeFormat === timeFormatEnum.PERIOD ?
<DatePicker.RangePicker placeholder={["Время начала", "Время конца"]} onChange={handleChange} showTime/> :
<DatePicker onChange={handleChange} showTime placeholder="Дата и время"/>
}
</ConfigProvider>
<button className={cls.button}>Показать</button>
</div>
);
}
export default Filters;

@ -0,0 +1,24 @@
.wrapper {
display: flex;
align-items: center;
background-color: var(--bg);
padding: 10px;
border-radius: var(--border-medium);
margin: 10px;
gap: 20px;
-webkit-box-shadow: 0px 5px 9px -8px rgba(34, 60, 80, 0.6);
-moz-box-shadow: 0px 5px 9px -8px rgba(34, 60, 80, 0.6);
box-shadow: 0px 5px 9px -8px rgba(34, 60, 80, 0.6);
}
.container {
flex: 1;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
}
.logo {
padding: 5px 10px;
border-radius: 20px;
background-color: var(--white);
}

@ -0,0 +1,10 @@
import { render } from '@testing-library/react';
import Navbar from './navbar';
describe('Navbar', () => {
it('should render successfully', () => {
const { baseElement } = render(<Navbar />);
expect(baseElement).toBeTruthy();
});
});

@ -0,0 +1,20 @@
import styles from './navbar.module.scss';
import {Link} from "react-router-dom";
/* eslint-disable-next-line */
export interface NavbarProps {}
export function Navbar(props: NavbarProps) {
return (
<div className={styles.wrapper}>
<Link to={"/"} className={styles.logo}>Logo</Link>
<ul className={styles.container}>
<li>link1</li>
<li>link2</li>
<li>link3</li>
</ul>
</div>
);
}
export default Navbar;

@ -0,0 +1,59 @@
.item {
background: var(--white);
border-radius: var(--border-medium);
padding: 10px 20px;
display: flex;
gap: 0 8px;
justify-content: space-between;
}
.line {
width: 1px;
background-color: var(--black);
}
.heading {
display: flex;
flex-direction: column;
gap: 0 10px;
justify-content: center;
.text {
text-align: end;
color: var(--gray);
font-size: 20px;
font-style: normal;
font-weight: 300;
line-height: normal;
}
.percent {
font-size: 54px;
font-style: normal;
font-weight: 300;
line-height: normal;
}
}
.info {
padding: 10px;
display: flex;
flex-direction: column;
gap: 5px;
& p {
padding: 0;
margin: 0;
font-size: 36px;
font-style: normal;
font-weight: 300;
line-height: normal;
color: var(--black
);
}
& span {
font-size: 20px;
font-style: normal;
font-weight: 300;
line-height: normal;
}
}

@ -0,0 +1,10 @@
import { render } from '@testing-library/react';
import SidebarItem from './sidebar-item';
describe('SidebarItem', () => {
it('should render successfully', () => {
const { baseElement } = render(<SidebarItem />);
expect(baseElement).toBeTruthy();
});
});

@ -0,0 +1,63 @@
import styles from './sidebar-item.module.scss';
import Button from "../button/button";
/* eslint-disable-next-line */
export interface SidebarItemProps {
name: string
percent: number | string
weight: number | string
href: string
}
export function SidebarItem() {
const obj: SidebarItemProps[] = [
{
name: "Дерево",
href: "some",
percent: "10%",
weight: 200
},
{
name: "Металл",
href: "some",
percent: "10%",
weight: 200
},
{
name: "Пластик",
href: "some",
percent: "10%",
weight: 200
},
{
name: "Стекло",
href: "some",
percent: "10%",
weight: 200
}
]
return (
<>
{obj.map((item, i) => (
<div className={styles.item} key={i * 2}>
<div className={styles.heading}>
<p className={styles.text}>
{item.name}
</p>
<p className={styles.percent}>
{item.percent}
</p>
</div>
<span className={styles.line}></span>
<div className={styles.info}>
<p>{item.weight}</p>
<span>Тонн</span>
<Button link={"some"} className={styles.link}>Аналитика</Button>
</div>
</div>
))}
</>
);
}
export default SidebarItem;

@ -0,0 +1,6 @@
.container {
flex: 0 0 20%;
display: flex;
flex-direction: column;
gap: 30px;
}

@ -0,0 +1,10 @@
import { render } from '@testing-library/react';
import Sidebar from './sidebar';
describe('Sidebar', () => {
it('should render successfully', () => {
const { baseElement } = render(<Sidebar />);
expect(baseElement).toBeTruthy();
});
});

@ -0,0 +1,15 @@
import styles from './sidebar.module.scss';
import SidebarItem from "../sidebar-item/sidebar-item";
/* eslint-disable-next-line */
export interface SidebarProps {}
export function Sidebar(props: SidebarProps) {
return (
<div className={styles['container']}>
<SidebarItem/>
</div>
);
}
export default Sidebar;

@ -1,7 +1,6 @@
/*
* Replace this with your own classes
*
* e.g.
* .container {
* }
*/
.container {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}

Loading…
Cancel
Save