feat: login page
This commit is contained in:
5
bun.lock
5
bun.lock
@@ -10,6 +10,7 @@
|
|||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"postcss": "^8.5.3",
|
"postcss": "^8.5.3",
|
||||||
"preact": "^10.26.2",
|
"preact": "^10.26.2",
|
||||||
|
"preact-iso": "^2.9.1",
|
||||||
"tailwind-merge": "^3.0.2",
|
"tailwind-merge": "^3.0.2",
|
||||||
"tailwind-variants": "^1.0.0",
|
"tailwind-variants": "^1.0.0",
|
||||||
"tailwindcss": "^4.0.17",
|
"tailwindcss": "^4.0.17",
|
||||||
@@ -564,6 +565,10 @@
|
|||||||
|
|
||||||
"preact": ["preact@10.26.4", "", {}, "sha512-KJhO7LBFTjP71d83trW+Ilnjbo+ySsaAgCfXOXUlmGzJ4ygYPWmysm77yg4emwfmoz3b22yvH5IsVFHbhUaH5w=="],
|
"preact": ["preact@10.26.4", "", {}, "sha512-KJhO7LBFTjP71d83trW+Ilnjbo+ySsaAgCfXOXUlmGzJ4ygYPWmysm77yg4emwfmoz3b22yvH5IsVFHbhUaH5w=="],
|
||||||
|
|
||||||
|
"preact-iso": ["preact-iso@2.9.1", "", { "peerDependencies": { "preact": ">=10", "preact-render-to-string": ">=6.4.0" } }, "sha512-65+oY5FHeSC3mjq2Dg6v72HYjsTYTqI9hXl1BK6vtUkxwfCqDJ5aqk33zjOH3aSuCY7duWiulyqMQ53GXpPIIQ=="],
|
||||||
|
|
||||||
|
"preact-render-to-string": ["preact-render-to-string@6.5.13", "", { "peerDependencies": { "preact": ">=10" } }, "sha512-iGPd+hKPMFKsfpR2vL4kJ6ZPcFIoWZEcBf0Dpm3zOpdVvj77aY8RlLiQji5OMrngEyaxGogeakTb54uS2FvA6w=="],
|
||||||
|
|
||||||
"prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="],
|
"prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="],
|
||||||
|
|
||||||
"prettier": ["prettier@3.5.3", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw=="],
|
"prettier": ["prettier@3.5.3", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw=="],
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"postcss": "^8.5.3",
|
"postcss": "^8.5.3",
|
||||||
"preact": "^10.26.2",
|
"preact": "^10.26.2",
|
||||||
|
"preact-iso": "^2.9.1",
|
||||||
"tailwind-merge": "^3.0.2",
|
"tailwind-merge": "^3.0.2",
|
||||||
"tailwind-variants": "^1.0.0",
|
"tailwind-variants": "^1.0.0",
|
||||||
"tailwindcss": "^4.0.17"
|
"tailwindcss": "^4.0.17"
|
||||||
|
|||||||
24
src/app.tsx
24
src/app.tsx
@@ -1,13 +1,25 @@
|
|||||||
import { useSignal } from "@preact/signals";
|
import { FunctionComponent } from "preact";
|
||||||
|
import { ErrorBoundary, LocationProvider, Route, Router, useLocation } from "preact-iso";
|
||||||
import "preact/debug";
|
import "preact/debug";
|
||||||
import classes from "./app.module.scss";
|
import LoginPage from "./pages/login";
|
||||||
import Button from "./components/ui/Button";
|
|
||||||
|
const HomePage: FunctionComponent = () => {
|
||||||
|
const location = useLocation();
|
||||||
|
location.route("/login");
|
||||||
|
return <div>Redirecting to login...</div>;
|
||||||
|
};
|
||||||
|
|
||||||
export function App() {
|
export function App() {
|
||||||
const counter = useSignal(0);
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<h1 class={classes.text}>Hello, World!</h1>
|
<LocationProvider>
|
||||||
<Button onClick={() => counter.value++}>Count: {counter.value}</Button>
|
<ErrorBoundary>
|
||||||
|
<Router>
|
||||||
|
<Route path="/" component={HomePage} />
|
||||||
|
<Route path="/login" component={LoginPage} />
|
||||||
|
</Router>
|
||||||
|
</ErrorBoundary>
|
||||||
|
</LocationProvider>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@reference '../../index.scss';
|
@reference '../../index.scss';
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
@apply rounded-2xl border-2 border-black p-5 text-white;
|
@apply rounded-2xl border-2 py-3 font-semibold text-white transition-colors hover:cursor-pointer;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ const button = tv({
|
|||||||
base: classes.button,
|
base: classes.button,
|
||||||
variants: {
|
variants: {
|
||||||
color: {
|
color: {
|
||||||
primary: "bg-blue-400",
|
primary: "bg-blue-400 hover:bg-blue-500",
|
||||||
secondary: "bg-red-400",
|
secondary: "bg-red-400 hover:bg-red-500",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1 +1,5 @@
|
|||||||
@reference "../../index.scss";
|
@reference "../../index.scss";
|
||||||
|
|
||||||
|
.input_field {
|
||||||
|
@apply rounded-md border border-gray-300 p-2;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,17 +1,34 @@
|
|||||||
import { FunctionComponent } from "preact";
|
import { FunctionComponent } from "preact";
|
||||||
import { tv } from "tailwind-variants";
|
import { tv } from "tailwind-variants";
|
||||||
|
import classes from "./Input.module.scss";
|
||||||
|
|
||||||
const input = tv({
|
const input = tv({
|
||||||
base: "rounded-md border border-gray-300 p-2",
|
base: classes.input_field,
|
||||||
|
variants: {
|
||||||
|
"text-align": {
|
||||||
|
center: "text-center",
|
||||||
|
left: "text-left",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
"text-align": "left",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
interface InputProps {
|
interface InputProps {
|
||||||
isPassword?: boolean;
|
isPassword?: boolean;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
|
textAlign?: "center" | "left";
|
||||||
}
|
}
|
||||||
|
|
||||||
const Input: FunctionComponent<InputProps> = ({ isPassword = false, placeholder = "" }: InputProps) => {
|
const Input: FunctionComponent<InputProps> = ({ isPassword = false, placeholder = "", textAlign }: InputProps) => {
|
||||||
return <input type={isPassword ? "password" : "text"} class={input()} placeholder={placeholder} />;
|
return (
|
||||||
|
<input
|
||||||
|
type={isPassword ? "password" : "text"}
|
||||||
|
class={input({ "text-align": textAlign })}
|
||||||
|
placeholder={placeholder}
|
||||||
|
/>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Input;
|
export default Input;
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
@reference "../index.scss";
|
@reference "../index.scss";
|
||||||
|
|
||||||
.login_container {
|
.login_container {
|
||||||
@apply flex flex-row justify-center gap-2 align-middle;
|
@apply flex min-h-screen flex-col items-center justify-center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login_card {
|
||||||
|
@apply flex w-[95%] min-w-[300px] flex-col justify-center gap-2 rounded-md border-gray-400 p-5 shadow-md md:w-[350px];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,12 @@ import classes from "./login.module.scss";
|
|||||||
const LoginPage: FunctionComponent = () => {
|
const LoginPage: FunctionComponent = () => {
|
||||||
return (
|
return (
|
||||||
<div class={classes.login_container}>
|
<div class={classes.login_container}>
|
||||||
<Input placeholder="Login" />
|
<div class={classes.login_card}>
|
||||||
<Input isPassword placeholder="Password" />
|
<Input placeholder="Login" textAlign="center" />
|
||||||
|
<Input isPassword placeholder="Password" textAlign="center" />
|
||||||
<Button onClick={() => {}}>Login</Button>
|
<Button onClick={() => {}}>Login</Button>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user