[front]: form
This commit is contained in:
parent
d435cde55c
commit
fd5c724342
6
front/package-lock.json
generated
6
front/package-lock.json
generated
@ -2811,7 +2811,7 @@
|
||||
"version": "15.7.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz",
|
||||
"integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/@types/qs": {
|
||||
"version": "6.9.16",
|
||||
@ -2829,7 +2829,7 @@
|
||||
"version": "18.3.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.8.tgz",
|
||||
"integrity": "sha512-syBUrW3/XpnW4WJ41Pft+I+aPoDVbrBVQGEnbD7NijDGlVC+8gV/XKRY+7vMDlfPpbwYt0l1vd/Sj8bJGMbs9Q==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
"csstype": "^3.0.2"
|
||||
@ -4262,7 +4262,7 @@
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.3.7",
|
||||
|
12
front/public/images/svg/delete.svg
Normal file
12
front/public/images/svg/delete.svg
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 26.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 13 13" style="enable-background:new 0 0 13 13;" xml:space="preserve">
|
||||
<g>
|
||||
<path d="M11.5,3H11H9V2.5C9,1.67,8.33,1,7.5,1h-2C4.67,1,4,1.67,4,2.5V3H2H1.5C1.22,3,1,3.22,1,3.5S1.22,4,1.5,4H2v5.5
|
||||
C2,10.88,3.12,12,4.5,12h4c1.38,0,2.5-1.12,2.5-2.5V4h0.5C11.78,4,12,3.78,12,3.5S11.78,3,11.5,3z M5,2.5C5,2.22,5.22,2,5.5,2h2
|
||||
C7.78,2,8,2.22,8,2.5V3H5V2.5z M10,9.5c0,0.83-0.67,1.5-1.5,1.5h-4C3.67,11,3,10.33,3,9.5V4h7V9.5z"/>
|
||||
<path d="M5.25,9.5c0.28,0,0.5-0.22,0.5-0.5V6c0-0.28-0.22-0.5-0.5-0.5S4.75,5.72,4.75,6v3C4.75,9.28,4.97,9.5,5.25,9.5z"/>
|
||||
<path d="M7.75,9.5c0.28,0,0.5-0.22,0.5-0.5V6c0-0.28-0.22-0.5-0.5-0.5S7.25,5.72,7.25,6v3C7.25,9.28,7.47,9.5,7.75,9.5z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 959 B |
7
front/public/images/svg/plus.svg
Normal file
7
front/public/images/svg/plus.svg
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 26.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 13 13" style="enable-background:new 0 0 13 13;" xml:space="preserve">
|
||||
<path d="M9.5,6H7V3.5C7,3.22,6.78,3,6.5,3S6,3.22,6,3.5V6H3.5C3.22,6,3,6.22,3,6.5S3.22,7,3.5,7H6v2.5C6,9.78,6.22,10,6.5,10
|
||||
S7,9.78,7,9.5V7h2.5C9.78,7,10,6.78,10,6.5S9.78,6,9.5,6z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 541 B |
0
front/src/api/floris/index.ts
Normal file
0
front/src/api/floris/index.ts
Normal file
@ -2,7 +2,7 @@ import './styles.scss';
|
||||
import '@public/fonts/styles.css';
|
||||
|
||||
import { MainLayout } from '@components/layouts';
|
||||
import { FormPage, HomePage } from '@components/pages';
|
||||
import { HomePage } from '@components/pages';
|
||||
import React from 'react';
|
||||
import { BrowserRouter, Route, Routes } from 'react-router-dom';
|
||||
|
||||
@ -12,7 +12,6 @@ function App() {
|
||||
<Routes>
|
||||
<Route element={<MainLayout />}>
|
||||
<Route path={'/'} element={<HomePage />} />
|
||||
<Route path={'/form'} element={<FormPage />} />
|
||||
</Route>
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
|
@ -1,12 +0,0 @@
|
||||
import { LoginForm } from '@components/ux';
|
||||
import React from 'react';
|
||||
|
||||
import styles from './styles.module.scss';
|
||||
|
||||
export function FormPage() {
|
||||
return (
|
||||
<div className={styles.about}>
|
||||
<LoginForm className={styles.form} />
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1 +0,0 @@
|
||||
export { FormPage } from './component';
|
@ -1,11 +0,0 @@
|
||||
.about {
|
||||
display: grid;
|
||||
padding: 20px;
|
||||
grid-template:
|
||||
'. form .' auto
|
||||
/ auto minmax(0, 380px) auto;
|
||||
}
|
||||
|
||||
.form {
|
||||
grid-area: form;
|
||||
}
|
@ -1,10 +1,4 @@
|
||||
import { ButtonPreview } from '@components/ui/button';
|
||||
import { CheckboxGroupPreview } from '@components/ui/checkbox-group';
|
||||
import { DateInputPreview } from '@components/ui/date-input';
|
||||
import { PasswordInputPreview } from '@components/ui/password-input';
|
||||
import { RadioGroupPreview } from '@components/ui/radio-group';
|
||||
import { SelectPreview } from '@components/ui/select';
|
||||
import { TextInputPreview } from '@components/ui/text-input';
|
||||
import { WindmillForm } from '@components/ux';
|
||||
import React from 'react';
|
||||
|
||||
import styles from './styles.module.scss';
|
||||
@ -12,14 +6,8 @@ import styles from './styles.module.scss';
|
||||
export function HomePage() {
|
||||
return (
|
||||
<div className={styles.home}>
|
||||
<div className={styles.content}>
|
||||
<ButtonPreview />
|
||||
<TextInputPreview />
|
||||
<PasswordInputPreview />
|
||||
<SelectPreview />
|
||||
<DateInputPreview />
|
||||
<CheckboxGroupPreview />
|
||||
<RadioGroupPreview />
|
||||
<div className={styles.about}>
|
||||
<WindmillForm className={styles.form} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -1,14 +1,11 @@
|
||||
.home {
|
||||
.about {
|
||||
display: grid;
|
||||
padding: 20px;
|
||||
grid-template:
|
||||
'. content .' auto
|
||||
/ auto minmax(0, 1000px) auto;
|
||||
'. form .' auto
|
||||
/ auto minmax(0, 380px) auto;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 20px 20px 60px 20px;
|
||||
gap: 30px;
|
||||
grid-area: content;
|
||||
.form {
|
||||
grid-area: form;
|
||||
}
|
||||
|
@ -1,2 +1 @@
|
||||
export { FormPage } from './form-page';
|
||||
export { HomePage } from './home-page';
|
||||
|
@ -1,6 +1,6 @@
|
||||
export type CalendarProps = {
|
||||
value?: string;
|
||||
onChange: (value: string) => void;
|
||||
onChange?: (value: string) => void;
|
||||
min: Date | null;
|
||||
max: Date | null;
|
||||
} & Omit<React.ComponentProps<'div'>, 'onChange'>;
|
||||
|
@ -9,18 +9,10 @@ import styles from './styles.module.scss';
|
||||
import { CheckboxProps } from './types';
|
||||
|
||||
function CheckboxInner(
|
||||
{
|
||||
scale = 'm',
|
||||
label = {},
|
||||
required,
|
||||
checked,
|
||||
...props
|
||||
}: Omit<CheckboxProps, 'ref'>,
|
||||
{ scale = 'm', label = {}, required, ...props }: Omit<CheckboxProps, 'ref'>,
|
||||
ref: ForwardedRef<HTMLInputElement>,
|
||||
) {
|
||||
const wrapperClassName = clsx(styles.wrapper, styles[scale], {
|
||||
[styles.checked]: checked,
|
||||
});
|
||||
const wrapperClassName = clsx(styles.wrapper, styles[scale]);
|
||||
|
||||
const labelProps: LabelProps = {
|
||||
position: 'right',
|
||||
@ -37,7 +29,6 @@ function CheckboxInner(
|
||||
type="checkbox"
|
||||
ref={ref}
|
||||
required={required}
|
||||
checked={checked}
|
||||
{...props}
|
||||
/>
|
||||
<div className={styles.checkbox}>
|
||||
|
@ -19,6 +19,24 @@
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
opacity: 0;
|
||||
|
||||
&:checked {
|
||||
& ~ .checkbox {
|
||||
border-width: 0;
|
||||
background-color: var(--clr-primary);
|
||||
|
||||
.icon {
|
||||
width: 100%;
|
||||
fill: white;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
& ~ .checkbox {
|
||||
background-color: var(--clr-primary-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.checkbox {
|
||||
@ -36,24 +54,6 @@
|
||||
transition: all var(--td-100) ease-in-out;
|
||||
}
|
||||
|
||||
.checked {
|
||||
.checkbox {
|
||||
border-width: 0;
|
||||
background-color: var(--clr-primary);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.checkbox {
|
||||
background-color: var(--clr-primary-hover);
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 100%;
|
||||
fill: white;
|
||||
}
|
||||
}
|
||||
|
||||
.s {
|
||||
padding: 3px;
|
||||
|
||||
|
@ -58,16 +58,16 @@ export function DateInput({
|
||||
(!minDate || date >= minDate) &&
|
||||
(!maxDate || date <= maxDate)
|
||||
) {
|
||||
onChange(newValue);
|
||||
onChange?.(newValue);
|
||||
} else {
|
||||
onChange('');
|
||||
onChange?.('');
|
||||
}
|
||||
}
|
||||
setDirtyDate(newDirtyDate);
|
||||
};
|
||||
|
||||
const handleCalendarChange = (newValue: string) => {
|
||||
onChange(newValue);
|
||||
onChange?.(newValue);
|
||||
setCalendarVisible(false);
|
||||
};
|
||||
|
||||
|
@ -2,7 +2,7 @@ import { TextInputProps } from '../text-input';
|
||||
|
||||
export type DateInputProps = {
|
||||
value?: string;
|
||||
onChange: (value: string) => void;
|
||||
onChange?: (value: string) => void;
|
||||
max?: string;
|
||||
min?: string;
|
||||
} & Omit<TextInputProps, 'type' | 'value' | 'onChange'>;
|
||||
|
@ -13,6 +13,7 @@
|
||||
}
|
||||
|
||||
.wrapperFocus {
|
||||
z-index: 1;
|
||||
border-color: var(--clr-primary);
|
||||
background-color: var(--clr-layer-200);
|
||||
outline-width: 3px;
|
||||
|
@ -1,5 +1,4 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { ThemeSelect } from '../theme-select';
|
||||
import styles from './styles.module.scss';
|
||||
@ -8,10 +7,6 @@ export function Header() {
|
||||
return (
|
||||
<header className={styles.header}>
|
||||
<ThemeSelect />
|
||||
<div className={styles.linkBox}>
|
||||
<Link to="/">Home</Link>
|
||||
<Link to="/form">Form</Link>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
export { Header } from './header';
|
||||
export { LoginForm } from './login-form';
|
||||
export { ThemeSelect } from './theme-select';
|
||||
export { WindmillForm } from './windmill-form';
|
||||
export { WindmillTable } from './windmill-table';
|
||||
|
@ -1,57 +0,0 @@
|
||||
import {
|
||||
Button,
|
||||
Paragraph,
|
||||
PasswordInput,
|
||||
Select,
|
||||
TextInput,
|
||||
} from '@components/ui';
|
||||
import { Controller, useForm } from '@utils/form';
|
||||
import clsx from 'clsx';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { fruits, initialValues } from './constants';
|
||||
import styles from './styles.module.scss';
|
||||
import { LoginFormProps, LoginFormStore } from './types';
|
||||
|
||||
export function LoginForm({ className, ...props }: LoginFormProps) {
|
||||
const [result, setResult] = useState<string>('');
|
||||
const { register, control, getValues, reset } = useForm<LoginFormStore>({
|
||||
initialValues,
|
||||
});
|
||||
const classNames = clsx(className, styles.form);
|
||||
|
||||
const handleSubmit = (event: React.FormEvent) => {
|
||||
event.preventDefault();
|
||||
setResult(JSON.stringify(getValues(), null, 4));
|
||||
};
|
||||
|
||||
const handleResetButtonClick = () => {
|
||||
reset({ email: 'haha' });
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit} className={classNames} {...props}>
|
||||
<TextInput {...register('email')} label={{ text: 'Email' }} />
|
||||
<PasswordInput {...register('password')} label={{ text: 'Password' }} />
|
||||
<Controller
|
||||
{...control('fruit')}
|
||||
render={(params) => (
|
||||
<Select
|
||||
options={fruits}
|
||||
getOptionKey={(o) => o.id}
|
||||
getOptionLabel={(o) => o.name}
|
||||
label={{ text: 'Fruit' }}
|
||||
{...params}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<div className={styles.buttonBox}>
|
||||
<Button type="submit">Login</Button>
|
||||
<Button variant="secondary" onClick={handleResetButtonClick}>
|
||||
Reset
|
||||
</Button>
|
||||
</div>
|
||||
{result && <Paragraph className={styles.result}>{result}</Paragraph>}
|
||||
</form>
|
||||
);
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
import { FormValues } from '@utils/form';
|
||||
|
||||
import { Fruit, LoginFormStore } from './types';
|
||||
|
||||
export const fruits: Fruit[] = [
|
||||
{ id: 1, name: 'banana' },
|
||||
{ id: 2, name: 'apple' },
|
||||
{ id: 3, name: 'orange' },
|
||||
];
|
||||
|
||||
export const initialValues: FormValues<LoginFormStore> = {
|
||||
email: 'aaa',
|
||||
fruit: fruits[1],
|
||||
};
|
@ -1 +0,0 @@
|
||||
export { LoginForm } from './component';
|
@ -1,12 +0,0 @@
|
||||
export type Fruit = {
|
||||
id: number;
|
||||
name: string;
|
||||
};
|
||||
|
||||
export type LoginFormStore = {
|
||||
email: string;
|
||||
password: string;
|
||||
fruit: Fruit;
|
||||
};
|
||||
|
||||
export type LoginFormProps = {} & React.ComponentProps<'form'>;
|
50
front/src/components/ux/windmill-form/component.tsx
Normal file
50
front/src/components/ux/windmill-form/component.tsx
Normal file
@ -0,0 +1,50 @@
|
||||
import { Button, DateInput, Heading } from '@components/ui';
|
||||
import { Controller, useForm } from '@utils/form';
|
||||
import clsx from 'clsx';
|
||||
import React from 'react';
|
||||
|
||||
import { WindmillTable } from '../windmill-table';
|
||||
import { initialValues } from './constants';
|
||||
import styles from './styles.module.scss';
|
||||
import { WindmillFormProps, WindmillFormStore } from './types';
|
||||
|
||||
export function WindmillForm({ className, ...props }: WindmillFormProps) {
|
||||
const { control, reset } = useForm<WindmillFormStore>({
|
||||
initialValues,
|
||||
});
|
||||
const classNames = clsx(className, styles.form);
|
||||
|
||||
const handleSubmit = (event: React.FormEvent) => {
|
||||
event.preventDefault();
|
||||
};
|
||||
|
||||
const handleResetButtonClick = () => {
|
||||
reset({});
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit} className={classNames} {...props}>
|
||||
<Heading tag="h3">Windmill power</Heading>
|
||||
<div className={styles.dateRangeBox}>
|
||||
<Controller
|
||||
{...control('dateFrom')}
|
||||
render={(params) => <DateInput placeholder="from" {...params} />}
|
||||
/>
|
||||
<Controller
|
||||
{...control('dateTo')}
|
||||
render={(params) => <DateInput placeholder="to" {...params} />}
|
||||
/>
|
||||
</div>
|
||||
<Controller
|
||||
{...control('windmills')}
|
||||
render={(params) => <WindmillTable {...params} />}
|
||||
/>
|
||||
<div className={styles.buttonBox}>
|
||||
<Button type="submit">Submit</Button>
|
||||
<Button variant="secondary" onClick={handleResetButtonClick}>
|
||||
Reset
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
}
|
5
front/src/components/ux/windmill-form/constants.ts
Normal file
5
front/src/components/ux/windmill-form/constants.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { FormValues } from '@utils/form';
|
||||
|
||||
import { WindmillFormStore } from './types';
|
||||
|
||||
export const initialValues: FormValues<WindmillFormStore> = {};
|
2
front/src/components/ux/windmill-form/index.tsx
Normal file
2
front/src/components/ux/windmill-form/index.tsx
Normal file
@ -0,0 +1,2 @@
|
||||
export { WindmillForm } from './component';
|
||||
export { type WindmillConfig } from './types';
|
@ -11,16 +11,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
.dateRangeBox {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.buttonBox {
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.result {
|
||||
overflow: auto;
|
||||
padding: 10px;
|
||||
border-radius: 7px;
|
||||
background-color: var(--clr-layer-100);
|
||||
white-space: pre;
|
||||
}
|
13
front/src/components/ux/windmill-form/types.ts
Normal file
13
front/src/components/ux/windmill-form/types.ts
Normal file
@ -0,0 +1,13 @@
|
||||
export type WindmillConfig = {
|
||||
x: string;
|
||||
y: string;
|
||||
angle: string;
|
||||
};
|
||||
|
||||
export type WindmillFormStore = {
|
||||
dateFrom: string;
|
||||
dateTo: string;
|
||||
windmills: WindmillConfig[];
|
||||
};
|
||||
|
||||
export type WindmillFormProps = {} & React.ComponentProps<'form'>;
|
60
front/src/components/ux/windmill-table/component.tsx
Normal file
60
front/src/components/ux/windmill-table/component.tsx
Normal file
@ -0,0 +1,60 @@
|
||||
import { IconButton, Span } from '@components/ui';
|
||||
import DeleteIcon from '@public/images/svg/delete.svg';
|
||||
import PlusIcon from '@public/images/svg/plus.svg';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { WindmillConfig } from '../windmill-form';
|
||||
import { WindmillRableRow } from './parts/windmill-table-row';
|
||||
import styles from './styles.module.scss';
|
||||
import { WindmillTableProps } from './types';
|
||||
|
||||
export function WindmillTable({ value, onChange }: WindmillTableProps) {
|
||||
const [selectedRows, setSelectedRows] = useState<Record<string, boolean>>({});
|
||||
const localValue = value ?? [];
|
||||
|
||||
const handleDeleteButtonClick = () => {
|
||||
onChange?.(localValue.filter((_, i) => !selectedRows[i]));
|
||||
setSelectedRows({});
|
||||
};
|
||||
|
||||
const handlePlusButtonClick = () => {
|
||||
onChange?.([...localValue, { x: '', y: '', angle: '' }]);
|
||||
};
|
||||
|
||||
const handleRowChange = (index: number, windmill: WindmillConfig) => {
|
||||
onChange?.(localValue.with(index, windmill));
|
||||
};
|
||||
|
||||
const handleRowSelect = (index: number) => {
|
||||
const checked = !selectedRows[index];
|
||||
setSelectedRows({ ...selectedRows, [index]: checked });
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<header className={styles.header}>
|
||||
<Span className={styles.span} />
|
||||
<Span className={styles.span}>x</Span>
|
||||
<Span className={styles.span}>y</Span>
|
||||
<Span className={styles.span}>angle</Span>
|
||||
</header>
|
||||
{localValue.map((v, i) => (
|
||||
<WindmillRableRow
|
||||
key={i}
|
||||
value={v}
|
||||
onChange={(windmill) => handleRowChange(i, windmill)}
|
||||
onSelect={() => handleRowSelect(i)}
|
||||
selected={selectedRows[i] ?? false}
|
||||
/>
|
||||
))}
|
||||
<footer className={styles.footer}>
|
||||
<IconButton onClick={handleDeleteButtonClick}>
|
||||
<DeleteIcon />
|
||||
</IconButton>
|
||||
<IconButton onClick={handlePlusButtonClick}>
|
||||
<PlusIcon />
|
||||
</IconButton>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
}
|
1
front/src/components/ux/windmill-table/index.tsx
Normal file
1
front/src/components/ux/windmill-table/index.tsx
Normal file
@ -0,0 +1 @@
|
||||
export * from './component';
|
26
front/src/components/ux/windmill-table/styles.module.scss
Normal file
26
front/src/components/ux/windmill-table/styles.module.scss
Normal file
@ -0,0 +1,26 @@
|
||||
.header {
|
||||
display: grid;
|
||||
grid-template-columns: 46px 1fr 1fr 1fr;
|
||||
}
|
||||
|
||||
.span {
|
||||
padding: 13px;
|
||||
border: 1px solid var(--clr-border-200);
|
||||
background-color: var(--clr-layer-300);
|
||||
text-align: center;
|
||||
|
||||
&:first-of-type {
|
||||
border-top-left-radius: 10px;
|
||||
}
|
||||
|
||||
&:last-of-type {
|
||||
border-top-right-radius: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
padding: 5px;
|
||||
border: 1px solid var(--clr-border-200);
|
||||
border-radius: 0 0 10px 10px;
|
||||
background-color: var(--clr-layer-300);
|
||||
}
|
6
front/src/components/ux/windmill-table/types.ts
Normal file
6
front/src/components/ux/windmill-table/types.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { WindmillConfig } from '../windmill-form';
|
||||
|
||||
export type WindmillTableProps = {
|
||||
value?: WindmillConfig[];
|
||||
onChange?: (value: WindmillConfig[]) => void;
|
||||
};
|
@ -31,4 +31,4 @@ typing_extensions==4.12.2
|
||||
uvicorn==0.30.6
|
||||
watchfiles==0.24.0
|
||||
websockets==13.1
|
||||
PyMySQL=1.1.1
|
||||
PyMySQL==1.1.1
|
||||
|
Loading…
Reference in New Issue
Block a user