parent
8b5b117e5f
commit
29f8c0401e
@ -0,0 +1,18 @@
|
||||
FROM node:20
|
||||
WORKDIR /app/
|
||||
|
||||
COPY ./sherlock-web/frontend/package.json ./sherlock-web/frontend/package-lock.json ./
|
||||
RUN npm i
|
||||
|
||||
COPY ./sherlock-web/frontend/tsconfig.json ./tsconfig.json
|
||||
COPY ./sherlock-web/frontend/next-env.d.ts ./next-env.d.ts
|
||||
COPY ./sherlock-web/frontend/next.config.mjs ./src/next.config.mjs
|
||||
|
||||
COPY ./sherlock-web/frontend/app/ ./app/
|
||||
COPY ./sherlock-web/frontend/public/ ./public/
|
||||
|
||||
COPY ./sherlock/resources/data.json ./
|
||||
|
||||
RUN npm run build
|
||||
|
||||
CMD npm run start
|
@ -0,0 +1,110 @@
|
||||
"use client"
|
||||
import { Grid, Input, Divider, Stack, Checkbox, Button } from "@mui/joy";
|
||||
|
||||
import SiteCheckbox from "./siteCheckbox";
|
||||
|
||||
import * as data from "../../data.json";
|
||||
import { ChangeEvent, FormEvent, useState } from "react";
|
||||
|
||||
type pageList = {
|
||||
name: string,
|
||||
url: string
|
||||
}[];
|
||||
|
||||
let sites: pageList = [];
|
||||
let sitesWithNSFW: pageList = [];
|
||||
|
||||
const checkedSitesDefault: Record<string, boolean> = {};
|
||||
|
||||
for (const [name, values] of Object.entries(data)) {
|
||||
const {url, isNSFW} = values as any;
|
||||
|
||||
const parsedData = {name, url};
|
||||
|
||||
sitesWithNSFW.push(parsedData);
|
||||
|
||||
checkedSitesDefault[name] = true;
|
||||
|
||||
if (!isNSFW)
|
||||
sites.push(parsedData)
|
||||
}
|
||||
|
||||
export default function Form() {
|
||||
const [withNSFW, setWithNSFW] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const [checkedSites, setCheckedSites] = useState(checkedSitesDefault);
|
||||
|
||||
const clickNSFW = (e: ChangeEvent<HTMLInputElement>) => setWithNSFW(e.target.checked);
|
||||
|
||||
const clickCheckAll = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
const {checked} = e.target;
|
||||
|
||||
let newCheckedSites = {...checkedSites};
|
||||
for (let key in checkedSites)
|
||||
newCheckedSites[key] = checked;
|
||||
|
||||
setCheckedSites(newCheckedSites);
|
||||
};
|
||||
|
||||
const onSubmit = async (e: FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
|
||||
setLoading(true);
|
||||
|
||||
const response = await fetch("/api/submit", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: JSON.stringify({
|
||||
username: e.currentTarget.username.value,
|
||||
sites: Object.entries(checkedSites).filter(([_, value]) => value).map(([key, _]) => key)
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
const currentSite = withNSFW ? sitesWithNSFW : sites;
|
||||
|
||||
const required = !Object.values(checkedSites).some(value => value);
|
||||
|
||||
return (
|
||||
<form style={{ height: "95%"}} onSubmit={onSubmit}>
|
||||
<Stack direction="column" spacing={2} sx={{height: "100%"}}>
|
||||
<Input name="username" required />
|
||||
|
||||
<Divider>
|
||||
<Stack direction="row" spacing={3}>
|
||||
<Checkbox label="With NSFW" onChange={clickNSFW} />
|
||||
<Checkbox label="Check All" onChange={clickCheckAll} />
|
||||
</Stack>
|
||||
</Divider>
|
||||
|
||||
<Grid container spacing={2} columns={{ xs: 4, sm: 6, md: 8, lg: 10, xl: 12 }} sx={{maxHeight: "100%", overflow: "auto"}} flexGrow={1}>
|
||||
{currentSite.map(
|
||||
({name, url}) => {
|
||||
const change = (value: boolean) => setCheckedSites({
|
||||
...checkedSites,
|
||||
[name]: value
|
||||
});
|
||||
|
||||
return (
|
||||
<SiteCheckbox
|
||||
name={name}
|
||||
url={url}
|
||||
key={"site-"+name}
|
||||
checked={checkedSites[name]}
|
||||
onChange={change}
|
||||
required={required}
|
||||
/>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</Grid>
|
||||
|
||||
<Button type="submit" loading={loading}>Send</Button>
|
||||
</Stack>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
"use client"
|
||||
import { Checkbox, Grid, Tooltip } from "@mui/joy"
|
||||
import { ChangeEvent } from "react";
|
||||
|
||||
type props = {
|
||||
name: string,
|
||||
url: string,
|
||||
checked: boolean | undefined,
|
||||
onChange: (value: boolean) => void,
|
||||
required: boolean,
|
||||
}
|
||||
|
||||
export default function SiteCheckBox({name, url, checked, onChange, required}: props) {
|
||||
const change = (e: ChangeEvent<HTMLInputElement>) => onChange(e.target.checked);
|
||||
|
||||
return (
|
||||
<Grid xs={2} sm={2} md={2} lg={2} >
|
||||
<Tooltip title={url}>
|
||||
<Checkbox
|
||||
name={"site["+name+"]"}
|
||||
label={name}
|
||||
checked={checked}
|
||||
onChange={change}
|
||||
required={required}
|
||||
/>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
);
|
||||
}
|
After Width: | Height: | Size: 25 KiB |
@ -0,0 +1,16 @@
|
||||
html,
|
||||
body,
|
||||
#__next {
|
||||
background: #000000;
|
||||
}
|
||||
|
||||
#__next {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
width: calc(100vw - 5vh);
|
||||
height: 95vh;
|
||||
margin: 2.5vh;
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
declare module '*.json' {
|
||||
const value: any;
|
||||
export default value;
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
export const metadata = {
|
||||
title: 'Sherlock',
|
||||
description: 'Find your username in many websites.',
|
||||
}
|
||||
|
||||
import "../node_modules/reset-css/reset.css";
|
||||
import "./global.css";
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Sherlock</title>
|
||||
</head>
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
)
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
import { CssVarsProvider } from '@mui/joy/styles';
|
||||
|
||||
import '../node_modules/reset-css/reset.css';
|
||||
import { Sheet, Typography } from '@mui/joy';
|
||||
import Form from './components/form';
|
||||
|
||||
const mainSheetStyle = {
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
padding: "10px",
|
||||
boxSizing: "border-box",
|
||||
overflow: "hidden"
|
||||
};
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<CssVarsProvider defaultMode="dark" modeStorageKey="theme">
|
||||
<Sheet sx={mainSheetStyle}>
|
||||
<Typography level="h1" textAlign="center">
|
||||
Sherlock
|
||||
</Typography>
|
||||
|
||||
<Form />
|
||||
</Sheet>
|
||||
</CssVarsProvider>
|
||||
);
|
||||
}
|
@ -0,0 +1 @@
|
||||
../../sherlock/resources/data.json
|
@ -0,0 +1,5 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
@ -0,0 +1,4 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {};
|
||||
|
||||
export default nextConfig;
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,27 @@
|
||||
{
|
||||
"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.11.3",
|
||||
"@emotion/styled": "^11.11.0",
|
||||
"@fontsource/inter": "^5.0.16",
|
||||
"@mui/joy": "^5.0.0-beta.21",
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
"next": "14.1.2",
|
||||
"reset-css": "^5.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18"
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 629 B |
@ -0,0 +1,39 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"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"
|
||||
]
|
||||
}
|
Loading…
Reference in new issue