parent
9be964ef8f
commit
9d4019f3e4
@ -1,7 +1,123 @@
|
||||
import { Component } from 'solid-js';
|
||||
import { Component, createEffect, createSignal } from 'solid-js';
|
||||
import RestClient from '../api/RestClient';
|
||||
import { setStore, store, User } from '../App';
|
||||
import Button from '../ui/Button';
|
||||
|
||||
type LoginRequest = {
|
||||
login: string;
|
||||
password: string;
|
||||
};
|
||||
|
||||
const [loggedInUser, setLoggedInUser] = createSignal();
|
||||
export { loggedInUser };
|
||||
|
||||
const Login: Component = () => {
|
||||
return <h1 class='text-4xl'>Login</h1>;
|
||||
const [loginRequest, setLoginRequest] = createSignal<LoginRequest>({
|
||||
login: '',
|
||||
password: '',
|
||||
});
|
||||
const [login, setLogin] = createSignal('');
|
||||
const [password, setPassword] = createSignal('');
|
||||
|
||||
// Populate the current user outside the JSX (we need createEffect for this!)
|
||||
createEffect(async () => {
|
||||
if (loginRequest().login.trim() === '' || loginRequest().password.trim() === '') {
|
||||
return;
|
||||
}
|
||||
const user = (await RestClient.POST(
|
||||
'/login',
|
||||
JSON.stringify(loginRequest())
|
||||
)) as User;
|
||||
if (user.id === undefined) {
|
||||
console.log(user);
|
||||
return;
|
||||
}
|
||||
setStore({
|
||||
...store,
|
||||
user,
|
||||
});
|
||||
window.location.href = '/';
|
||||
});
|
||||
|
||||
return (
|
||||
<div class='grid h-screen place-items-center'>
|
||||
<div class='block p-6 rounded-lg shadow-lg bg-white max-w-sm'>
|
||||
<form>
|
||||
<div class='form-group mb-6'>
|
||||
<label for='username' class='form-label inline-block mb-2 text-gray-700'>
|
||||
Login
|
||||
</label>
|
||||
<input
|
||||
type='text'
|
||||
class='form-control
|
||||
block
|
||||
w-full
|
||||
px-3
|
||||
py-1.5
|
||||
text-base
|
||||
font-normal
|
||||
text-gray-700
|
||||
bg-white bg-clip-padding
|
||||
border border-solid border-gray-300
|
||||
rounded
|
||||
transition
|
||||
ease-in-out
|
||||
m-0
|
||||
focus:text-gray-700 focus:bg-white focus:border-blue-600 focus:outline-none'
|
||||
id='username'
|
||||
placeholder='Username'
|
||||
onInput={(e) => setLogin(e.currentTarget.value)}
|
||||
value={login()}
|
||||
/>
|
||||
</div>
|
||||
<div class='form-group mb-6'>
|
||||
<label for='Password' class='form-label inline-block mb-2 text-gray-700'>
|
||||
Password
|
||||
</label>
|
||||
<input
|
||||
type='password'
|
||||
class='form-control block
|
||||
w-full
|
||||
px-3
|
||||
py-1.5
|
||||
text-base
|
||||
font-normal
|
||||
text-gray-700
|
||||
bg-white bg-clip-padding
|
||||
border border-solid border-gray-300
|
||||
rounded
|
||||
transition
|
||||
ease-in-out
|
||||
m-0
|
||||
focus:text-gray-700 focus:bg-white focus:border-blue-600 focus:outline-none'
|
||||
id='Password'
|
||||
placeholder='Password'
|
||||
onInput={(e) => setPassword(e.currentTarget.value)}
|
||||
value={password()}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
fullWidth
|
||||
onClick={() => {
|
||||
console.log(login(), password());
|
||||
setLoginRequest({ login: login(), password: password() });
|
||||
}}
|
||||
>
|
||||
Sign in
|
||||
</Button>
|
||||
<p class='text-gray-800 mt-6 text-center'>
|
||||
Want to track your todo{"'"}s?{' '}
|
||||
<a
|
||||
href='#!'
|
||||
class='text-blue-600 hover:text-blue-700 focus:text-blue-700 transition duration-200 ease-in-out'
|
||||
>
|
||||
Register
|
||||
</a>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Login;
|
||||
|
@ -0,0 +1,53 @@
|
||||
import { Component, JSX } from 'solid-js';
|
||||
|
||||
type ButtonProps = {
|
||||
backgroundColor?: string;
|
||||
color?: string;
|
||||
fullWidth?: boolean;
|
||||
onClick?: Function;
|
||||
children?: JSX.Element;
|
||||
};
|
||||
|
||||
const backgroundColors: { [key: string]: string } = {
|
||||
blue: 'bg-sh-blue hover:bg-sh-blueM1 focus:bg-sh-blueM1 active:bg-sh-blueM1',
|
||||
red: 'bg-red-600 hover:bg-red-700 focus:bg-red-700 active:bg-red-800',
|
||||
green: 'bg-green-600 hover:bg-green-700 focus:bg-green-700 active:bg-green-800',
|
||||
yellow: 'bg-sh-yellow hover:bg-sh-yellowM1 focus:bg-sh-yellowM1 active:bg-sh-yellowM1',
|
||||
magenta:
|
||||
'bg-sh-magenta hover:bg-sh-magentaM1 focus:bg-sh-magentaM1 active:bg-sh-magentaM1',
|
||||
gray: 'bg-gray-700 hover:bg-gray-800 focus:bg-gray-800 active:bg-gray-800',
|
||||
cyan: 'bg-cyan-700 hover:bg-cyan-900 focus:bg-cyan-900 active:bg-cyan-800',
|
||||
};
|
||||
|
||||
const colors: { [key: string]: string } = {
|
||||
white: 'text-white',
|
||||
black: 'text-black',
|
||||
};
|
||||
|
||||
const Button: Component<ButtonProps> = (props) => {
|
||||
const backgroundColor = backgroundColors[props.backgroundColor || 'blue'];
|
||||
const color = colors[props.color || 'white'];
|
||||
const fullWidth = props.fullWidth ? 'w-full' : '';
|
||||
const fun =
|
||||
props.onClick !== undefined
|
||||
? (e: MouseEvent) => {
|
||||
e.preventDefault();
|
||||
(props.onClick as () => void)();
|
||||
}
|
||||
: (e: MouseEvent) => {
|
||||
e.preventDefault();
|
||||
console.log(
|
||||
'Default behavior of Button component is invoked!',
|
||||
'You might want to change the onClick function?'
|
||||
);
|
||||
};
|
||||
const btnStyle = `${color} ${backgroundColor} ${fullWidth} inline-block px-6 py-2.5 font-medium text-xs leading-tight uppercase rounded-full shadow-md hover:shadow-lg focus:shadow-lg focus:outline-none focus:ring-0 active:shadow-lg transition duration-150 ease-in-out`;
|
||||
|
||||
return (
|
||||
<button class={btnStyle} onClick={fun}>
|
||||
{props.children}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
export default Button;
|
@ -0,0 +1,51 @@
|
||||
import { A } from '@solidjs/router';
|
||||
import { Component, Show } from 'solid-js';
|
||||
import RestClient from '../api/RestClient';
|
||||
import { setStore, store, User } from '../App';
|
||||
import Button from './Button';
|
||||
|
||||
const Navbar: Component = () => {
|
||||
return (
|
||||
<div class='flex justify-between items-center bg-sh-bg p-3'>
|
||||
<div class='flex items-center'>
|
||||
<a
|
||||
href='/'
|
||||
class='pl-2 text-xl font-bold no-underline text-sh-yellow hover:text-sh-yellowM1'
|
||||
>
|
||||
Just todo it!
|
||||
</a>
|
||||
</div>
|
||||
<h1 class='flex -ml-20 text-xl font-bold no-underline text-sh-yellow'>
|
||||
Hey {store.user.login}!
|
||||
</h1>
|
||||
<Show
|
||||
when={store.user.login !== ''}
|
||||
fallback={
|
||||
<>
|
||||
<Button
|
||||
onClick={() => (window.location.href = '/login')}
|
||||
backgroundColor='yellow'
|
||||
color='black'
|
||||
>
|
||||
Login
|
||||
</Button>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<Button
|
||||
onClick={() => {
|
||||
RestClient.DELETE('/logout');
|
||||
setStore({ todos: [], user: { id: '', login: '' } });
|
||||
window.location.href = '/login';
|
||||
}}
|
||||
backgroundColor='magenta'
|
||||
color='black'
|
||||
>
|
||||
Logout
|
||||
</Button>
|
||||
</Show>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Navbar;
|
@ -0,0 +1,65 @@
|
||||
import { Component, For, JSX } from 'solid-js';
|
||||
import { Priority, Status, Todo } from '../pages/Home';
|
||||
|
||||
type TableProps = {
|
||||
data: Todo[];
|
||||
};
|
||||
|
||||
type TableRowProps = {
|
||||
children: JSX.Element;
|
||||
};
|
||||
|
||||
type TableDataProps = {
|
||||
children?: JSX.Element;
|
||||
};
|
||||
|
||||
type TableHeadProps = {
|
||||
children?: JSX.Element;
|
||||
};
|
||||
|
||||
export const TableHead: Component<TableHeadProps> = (props) => {
|
||||
return (
|
||||
<th scope='col' class='text-sm font-medium px-6 py-4'>
|
||||
{props.children}
|
||||
</th>
|
||||
);
|
||||
};
|
||||
|
||||
export const TableData: Component<TableDataProps> = (props) => {
|
||||
return <td class='text-sm text-gray-900 font-light px-6 py-4 '>{props.children}</td>;
|
||||
};
|
||||
|
||||
export const TableRow: Component<TableRowProps> = (props) => {
|
||||
const rowClass = 'border-b';
|
||||
return <tr class={rowClass}>{props.children}</tr>;
|
||||
};
|
||||
|
||||
const Table: Component<TableProps> = (props) => {
|
||||
if (props.data.length < 1) {
|
||||
return <></>;
|
||||
}
|
||||
return (
|
||||
<div class='overflow-hidden mt-10 mx-10'>
|
||||
<table class='min-w-full text-center'>
|
||||
<thead class='border-b text-sh-bgM1 bg-sh-yellow'>
|
||||
{Object.keys(props.data[0]).map((key) => (
|
||||
<TableHead>{key}</TableHead>
|
||||
))}
|
||||
</thead>
|
||||
<tbody>
|
||||
<For each={props.data}>
|
||||
{(child) => (
|
||||
<TableRow>
|
||||
{Object.values(child).map((val) => (
|
||||
<TableData>{val}</TableData>
|
||||
))}
|
||||
</TableRow>
|
||||
)}
|
||||
</For>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Table;
|
@ -1,8 +1,48 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: ["./src/**/*.{js,jsx,ts,tsx}"],
|
||||
content: ['./src/**/*.{js,jsx,ts,tsx}'],
|
||||
theme: {
|
||||
extend: {},
|
||||
extend: {
|
||||
colors: {
|
||||
'sh-bgM2': '#000306',
|
||||
'sh-bgM1': '#020E18',
|
||||
'sh-bg': '#0D1F2D',
|
||||
'sh-bgP1': '#1E3141',
|
||||
'sh-bgP2': '#3C5161',
|
||||
'sh-fgM2': '#546A7B',
|
||||
'sh-fgM1': '#9EA3B0',
|
||||
'sh-fg': '#C3C9E9',
|
||||
'sh-fgP1': '#BDD3DD',
|
||||
'sh-white': '#FEFEFE',
|
||||
'sh-black': '#000306',
|
||||
'sh-yellowM1': '#DA7F05',
|
||||
'sh-yellow': '#FDAA3A',
|
||||
'sh-yellowP1': '#FFC16E',
|
||||
'sh-orangeM1': '#C45A00',
|
||||
'sh-orange': '#FF7F11',
|
||||
'sh-orangeP1': '#FFA251',
|
||||
'sh-redM2': '#960004',
|
||||
'sh-redM1': '#CD1419',
|
||||
'sh-red': '#ED474A',
|
||||
'sh-redP1': '#FD7E81',
|
||||
'sh-greenM1': '#739F2F',
|
||||
'sh-green': '#A5CC69',
|
||||
'sh-greenP1': '#D5EEAE',
|
||||
'sh-greenP2': '#A2DFED',
|
||||
'sh-blueM2': '#0683A0',
|
||||
'sh-blueM1': '#36A1BB',
|
||||
'sh-blue': '#64BFD6',
|
||||
'sh-blueP1': '#A2DFED',
|
||||
'sh-magentaM2': '#690635',
|
||||
'sh-magentaM1': '#902B5B',
|
||||
'sh-magenta': '#B95F8A',
|
||||
'sh-magentaP1': '#DBA1BC',
|
||||
'sh-purpleM2': '#630DAE',
|
||||
'sh-purpleM1': '#863FC4',
|
||||
'sh-purple': '#A86CDC',
|
||||
'sh-purpleP1': '#CEA7F0',
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
};
|
||||
|
Loading…
Reference in new issue