Commit 8878a344 authored by Ли Джен Сеп's avatar Ли Джен Сеп 💬

Merge branch '3-frontend-boilerplate' into 'master'

Frontend merge

Closes #3

See merge request !7
parents e4cc928d 1d9750ed
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# env files (can opt-in for committing if needed)
.env*
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
## Getting Started
First, run the development server:
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
import { dirname } from "path";
import { fileURLToPath } from "url";
import { FlatCompat } from "@eslint/eslintrc";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname,
});
const eslintConfig = [
...compat.extends("next/core-web-vitals", "next/typescript"),
];
export default eslintConfig;
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
/* config options here */
};
export default nextConfig;
This diff is collapsed.
{
"name": "frontend",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.0",
"@mui/icons-material": "^6.2.1",
"@mui/material": "^6.2.1",
"next": "15.1.1",
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"devDependencies": {
"@eslint/eslintrc": "^3",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"eslint": "^9",
"eslint-config-next": "15.1.1",
"typescript": "^5"
}
}
import { Grid2, TextField, Typography } from "@mui/material";
import { ChangeEvent } from "react";
interface Props {
name: "Decoded" | "Encoded" | "Password";
value: string;
onChange: (e: ChangeEvent<HTMLInputElement>) => void;
}
export default function InputField({ name, value, onChange }: Props) {
let labelText: string = "";
switch (name) {
case "Decoded":
labelText = `Decoded message`;
break;
case "Encoded":
labelText = `Encoded message`;
break;
case "Password":
labelText = "";
break;
default:
break;
}
return (
<Grid2 container alignItems="center" paddingY={2} spacing={2}>
<Grid2 flexGrow={1}>
<Typography
component="label"
htmlFor={`${name}-input`}
sx={{
fontSize: {
xs: "16px",
sm: "20px",
},
}}
>
{labelText}
</Typography>
</Grid2>
<Grid2
size={name === "Password" ? 6 : 8}
sx={{ "@media (max-width: 900px)": { width: "100%" } }}
>
<TextField
fullWidth
multiline={name !== "Password"}
rows={name === "Password" ? 1 : 6}
variant="outlined"
id={`${name}-input`}
name={name}
label={name}
value={value}
onChange={onChange}
/>
</Grid2>
</Grid2>
);
}
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body>
{children}
</body>
</html>
);
}
"use client";
import { Box, Button, Container, Grid2, Typography } from "@mui/material";
import ArrowDownwardIcon from "@mui/icons-material/ArrowDownward";
import { ChangeEvent, FormEvent, useState } from "react";
import InputField from "./components/InputField";
interface IFormData {
decoded: string;
encoded: string;
password: string;
}
export default function Home() {
const [formData, setFormData] = useState<IFormData>({
encoded: "",
decoded: "",
password: "",
});
const submitFormHandler = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
};
const onInputChangeHandler = (e: ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
setFormData((prevData) => ({
...prevData,
[name.toLowerCase()]: value,
}));
};
return (
<div className="App">
<Container sx={{ marginTop: 2 }} maxWidth="lg">
<Typography
variant="h3"
sx={{
fontSize: {
xs: "24px",
sm: "36px",
},
}}
>
Cypher Coder/Decoder
</Typography>
<Box
sx={{
maxWidth: {
xs: "90%",
sm: "80%",
lg: "70%",
},
}}
component="form"
autoComplete="off"
onSubmit={submitFormHandler}
paddingY={2}
>
<Grid2 container direction="column" spacing={2}>
<InputField
name="Decoded"
value={formData.decoded}
onChange={onInputChangeHandler}
/>
<Grid2
container
alignItems="center"
sx={{
flexDirection: {
xs: "column",
md: "row",
},
}}
>
<Grid2 size={7}>
<InputField
name="Password"
value={formData.password}
onChange={onInputChangeHandler}
/>
</Grid2>
<Grid2 container justifyContent={{}}>
<Grid2>
<Button
size="small"
variant="contained"
startIcon={<ArrowDownwardIcon />}
>
<Typography
sx={{
display: { xs: "none", md: "inline" },
}}
>
Encode
</Typography>
</Button>
</Grid2>
<Grid2>
<Button
size="small"
variant="contained"
startIcon={
<ArrowDownwardIcon sx={{ transform: "rotate(180deg)" }} />
}
>
<Typography
sx={{
display: { xs: "none", md: "inline" },
}}
>
Decode
</Typography>
</Button>
</Grid2>
</Grid2>
</Grid2>
<InputField
name="Encoded"
value={formData.encoded}
onChange={onInputChangeHandler}
/>
</Grid2>
</Box>
</Container>
</div>
);
}
{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment