mirror of https://github.com/usbharu/Hideout.git
feat: WebUIを追加
This commit is contained in:
parent
9c5da79389
commit
6b1b6f8bf2
|
@ -37,3 +37,4 @@ out/
|
|||
*.db
|
||||
/src/main/resources/static/
|
||||
/node_modules/
|
||||
/src/main/web/generated/
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json",
|
||||
"spaces": 2,
|
||||
"generator-cli": {
|
||||
"version": "6.6.0",
|
||||
"generators": {
|
||||
"v3.0": {
|
||||
"generatorName": "typescript-fetch",
|
||||
"output": "src/main/web/generated",
|
||||
"glob": "src/main/resources/openapi/api.yaml",
|
||||
"additionalProperties": {
|
||||
"modelPropertyNaming": "camelCase",
|
||||
"supportsES6": true,
|
||||
"withInterfaces": true,
|
||||
"typescriptThreePlus": true,
|
||||
"useSingleRequestParameter": false,
|
||||
"prependFormOrBodyParameters": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
14
package.json
14
package.json
|
@ -2,18 +2,24 @@
|
|||
"name": "hideout",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"solid-js": "^1.7.3"
|
||||
"@solid-primitives/storage": "^1.3.11",
|
||||
"@solidjs/router": "^0.8.2",
|
||||
"@suid/icons-material": "^0.6.3",
|
||||
"@suid/material": "^0.12.3",
|
||||
"solid-js": "^1.7.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@openapitools/openapi-generator-cli": "^2.6.0",
|
||||
"@suid/vite-plugin": "^0.1.3",
|
||||
"typescript": "^5.0.4",
|
||||
"vite": "^4.2.1",
|
||||
"vite-plugin-solid": "^2.7.0",
|
||||
"@suid/vite-plugin": "^0.1.3"
|
||||
"vite-plugin-solid": "^2.7.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "vite",
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"serve": "vite preview"
|
||||
"serve": "vite preview",
|
||||
"gen-api": "openapi-generator-cli generate"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ paths:
|
|||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Post"
|
||||
$ref: "#/components/schemas/PostResponse"
|
||||
401:
|
||||
$ref: "#/components/responses/Unauthorized"
|
||||
403:
|
||||
|
@ -37,7 +37,7 @@ paths:
|
|||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Post"
|
||||
$ref: "#/components/schemas/PostRequest"
|
||||
responses:
|
||||
200:
|
||||
description: 成功
|
||||
|
@ -65,7 +65,7 @@ paths:
|
|||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Post"
|
||||
$ref: "#/components/schemas/PostResponse"
|
||||
401:
|
||||
$ref: "#/components/responses/Unauthorized"
|
||||
403:
|
||||
|
@ -90,7 +90,7 @@ paths:
|
|||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Post"
|
||||
$ref: "#/components/schemas/PostResponse"
|
||||
401:
|
||||
$ref: "#/components/responses/Unauthorized"
|
||||
403:
|
||||
|
@ -114,7 +114,7 @@ paths:
|
|||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Post"
|
||||
$ref: "#/components/schemas/PostResponse"
|
||||
401:
|
||||
$ref: "#/components/responses/Unauthorized"
|
||||
403:
|
||||
|
@ -137,7 +137,7 @@ paths:
|
|||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/User"
|
||||
$ref: "#/components/schemas/UserResponse"
|
||||
|
||||
post:
|
||||
summary: ユーザーを作成する
|
||||
|
@ -181,7 +181,7 @@ paths:
|
|||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/User"
|
||||
$ref: "#/components/schemas/UserResponse"
|
||||
404:
|
||||
$ref: "#/components/responses/NotFound"
|
||||
|
||||
|
@ -198,7 +198,7 @@ paths:
|
|||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/User"
|
||||
$ref: "#/components/schemas/UserResponse"
|
||||
post:
|
||||
summary: ユーザーをフォローする
|
||||
security:
|
||||
|
@ -228,7 +228,7 @@ paths:
|
|||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/User"
|
||||
$ref: "#/components/schemas/UserResponse"
|
||||
|
||||
components:
|
||||
responses:
|
||||
|
@ -261,8 +261,22 @@ components:
|
|||
type: string
|
||||
|
||||
schemas:
|
||||
User:
|
||||
Visibility:
|
||||
type: string
|
||||
enum:
|
||||
- public
|
||||
- unlisted
|
||||
- followers
|
||||
- direct
|
||||
UserResponse:
|
||||
type: object
|
||||
required:
|
||||
- id
|
||||
- name
|
||||
- domain
|
||||
- screenName
|
||||
- description
|
||||
- createdAt
|
||||
properties:
|
||||
id:
|
||||
type: number
|
||||
|
@ -277,14 +291,24 @@ components:
|
|||
type: string
|
||||
description:
|
||||
type: string
|
||||
nullable: true
|
||||
url:
|
||||
type: string
|
||||
readOnly: true
|
||||
createdAt:
|
||||
type: number
|
||||
readOnly: true
|
||||
Post:
|
||||
PostResponse:
|
||||
type: object
|
||||
required:
|
||||
- id
|
||||
- userId
|
||||
- text
|
||||
- createdAt
|
||||
- visibility
|
||||
- url
|
||||
- sensitive
|
||||
- apId
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
|
@ -303,12 +327,7 @@ components:
|
|||
format: int64
|
||||
readOnly: true
|
||||
visibility:
|
||||
type: string
|
||||
enum:
|
||||
- public
|
||||
- unlisted
|
||||
- followers
|
||||
- direct
|
||||
$ref: "#/components/schemas/Visibility"
|
||||
url:
|
||||
type: string
|
||||
format: uri
|
||||
|
@ -328,6 +347,24 @@ components:
|
|||
format: url
|
||||
readOnly: true
|
||||
|
||||
PostRequest:
|
||||
type: object
|
||||
properties:
|
||||
overview:
|
||||
type: string
|
||||
text:
|
||||
type: string
|
||||
visibility:
|
||||
$ref: "#/components/schemas/Visibility"
|
||||
repostId:
|
||||
type: integer
|
||||
format: int64
|
||||
replyId:
|
||||
type: integer
|
||||
format: int64
|
||||
sensitive:
|
||||
type: boolean
|
||||
|
||||
|
||||
securitySchemes:
|
||||
BearerAuth:
|
||||
|
|
|
@ -1,58 +1,24 @@
|
|||
import {Component, createSignal} from "solid-js";
|
||||
import {Component} from "solid-js";
|
||||
import {Route, Router, Routes} from "@solidjs/router";
|
||||
import {TopPage} from "./pages/TopPage";
|
||||
import {createTheme, CssBaseline, ThemeProvider, useMediaQuery} from "@suid/material";
|
||||
|
||||
export const App: Component = () => {
|
||||
const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
|
||||
|
||||
const fn = (form: HTMLButtonElement) => {
|
||||
console.log(form)
|
||||
}
|
||||
|
||||
const [username, setUsername] = createSignal("")
|
||||
const [password, setPassword] = createSignal("")
|
||||
|
||||
const theme = createTheme({
|
||||
palette: {
|
||||
mode: prefersDarkMode() ? 'dark' : 'light',
|
||||
}
|
||||
})
|
||||
return (
|
||||
<form onSubmit={function (e: SubmitEvent) {
|
||||
e.preventDefault()
|
||||
fetch("/login", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({username: username(), password: password()}),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}).then(res => res.json())
|
||||
// .then(res => fetch("/auth-check", {
|
||||
// method: "GET",
|
||||
// headers: {
|
||||
// 'Authorization': 'Bearer ' + res.token
|
||||
// }
|
||||
// }))
|
||||
// .then(res => res.json())
|
||||
.then(res => {
|
||||
console.log(res.token);
|
||||
fetch("/refresh-token", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({refreshToken: res.refreshToken}),
|
||||
}).then(res=> res.json()).then(res => console.log(res.token))
|
||||
})
|
||||
}
|
||||
|
||||
}>
|
||||
<input name="username" type="text" placeholder="Username" required
|
||||
onChange={(e) => setUsername(e.currentTarget.value)}/>
|
||||
<input name="password" type="password" placeholder="Password" required
|
||||
onChange={(e) => setPassword(e.currentTarget.value)}/>
|
||||
<button type="submit">Submit</button>
|
||||
</form>
|
||||
<ThemeProvider theme={theme}>
|
||||
<CssBaseline/>
|
||||
<Router>
|
||||
<Routes>
|
||||
<Route path="/" component={TopPage}/>
|
||||
</Routes>
|
||||
</Router>
|
||||
</ThemeProvider>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
declare module 'solid-js' {
|
||||
namespace JSX {
|
||||
interface Directives {
|
||||
fn: (form: HTMLFormElement) => void
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
import {Avatar as SuidAvatar} from "@suid/material";
|
||||
import {Component, JSXElement} from "solid-js";
|
||||
|
||||
export const Avatar: Component<{ src: string }> = (props): JSXElement => {
|
||||
return (
|
||||
<SuidAvatar src={props.src}/>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
import {Component, createSignal, Match, Switch} from "solid-js";
|
||||
import {PostResponse} from "../generated";
|
||||
import {Box, Card, CardActions, CardContent, CardHeader, IconButton, Menu, MenuItem, Typography} from "@suid/material";
|
||||
import {Avatar} from "../atoms/Avatar";
|
||||
import {Favorite, Home, Lock, Mail, MoreVert, Public, Reply, ScreenRotationAlt} from "@suid/icons-material";
|
||||
|
||||
export const Post: Component<{ post: PostResponse }> = (props) => {
|
||||
const [anchorEl, setAnchorEl] = createSignal<null | HTMLElement>(null)
|
||||
const open = () => Boolean(anchorEl());
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
}
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader avatar={<Avatar src={""}/>} title={"test user"} subheader={"test@test"}
|
||||
action={<IconButton onclick={(event) => {
|
||||
setAnchorEl(event.currentTarget)
|
||||
}}><MoreVert/><Menu disableScrollLock anchorEl={anchorEl()} open={open()} onClose={handleClose}><MenuItem
|
||||
onclick={handleClose}>aaa</MenuItem></Menu> </IconButton>}/>
|
||||
<CardContent>
|
||||
<Typography>
|
||||
{props.post.text}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
<CardActions disableSpacing>
|
||||
<IconButton>
|
||||
<Reply/>
|
||||
</IconButton>
|
||||
<IconButton>
|
||||
<ScreenRotationAlt/>
|
||||
</IconButton>
|
||||
<IconButton>
|
||||
<Favorite/>
|
||||
</IconButton>
|
||||
<Box sx={{marginLeft: "auto"}}>
|
||||
<Typography>{new Date(props.post.createdAt).toDateString()}</Typography>
|
||||
</Box>
|
||||
<Switch fallback={<Public/>}>
|
||||
<Match when={props.post.visibility == "public"}>
|
||||
<IconButton>
|
||||
<Public/>
|
||||
</IconButton>
|
||||
</Match>
|
||||
<Match when={props.post.visibility == "direct"}>
|
||||
<IconButton>
|
||||
<Mail/>
|
||||
</IconButton>
|
||||
</Match>
|
||||
<Match when={props.post.visibility == "followers"}>
|
||||
<IconButton>
|
||||
<Lock/>
|
||||
</IconButton>
|
||||
</Match>
|
||||
<Match when={props.post.visibility == "unlisted"}>
|
||||
<IconButton>
|
||||
<Home/>
|
||||
</IconButton>
|
||||
</Match>
|
||||
</Switch>
|
||||
</CardActions>
|
||||
</Card>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
import {Component} from "solid-js";
|
||||
import {Button, IconButton, Paper, Stack, TextField, Typography} from "@suid/material";
|
||||
import {Avatar} from "../atoms/Avatar";
|
||||
import {AddPhotoAlternate, Poll, Public} from "@suid/icons-material";
|
||||
|
||||
export const PostForm: Component<{ label: string }> = (props) => {
|
||||
return (
|
||||
<Paper>
|
||||
<Stack>
|
||||
<Stack direction={"row"} spacing={2} sx={{padding: 2}}>
|
||||
<Avatar src={""}/>
|
||||
<TextField label={props.label} multiline rows={4} variant={"standard"} fullWidth/>
|
||||
</Stack>
|
||||
<Stack direction={"row"} justifyContent={"space-between"} sx={{padding: 2}}>
|
||||
<Stack direction={"row"} justifyContent={"flex-start"} alignItems={"center"}>
|
||||
<IconButton>
|
||||
<AddPhotoAlternate/>
|
||||
</IconButton>
|
||||
<IconButton>
|
||||
<Poll/>
|
||||
</IconButton>
|
||||
<IconButton>
|
||||
<Public/>
|
||||
</IconButton>
|
||||
</Stack>
|
||||
<Stack direction={"row"} alignItems={"center"} spacing={2}>
|
||||
<Typography>
|
||||
aaa
|
||||
</Typography>
|
||||
<Button variant={"contained"}>
|
||||
投稿する
|
||||
</Button>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Paper>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
import {Component} from "solid-js";
|
||||
import {MainPage} from "../templates/MainPage";
|
||||
import {PostForm} from "../organisms/PostForm";
|
||||
import {Stack} from "@suid/material";
|
||||
import {Post} from "../organisms/Post";
|
||||
import {PostResponse} from "../generated";
|
||||
|
||||
export const TopPage: Component = () => {
|
||||
return (
|
||||
<MainPage>
|
||||
<Stack spacing={1}>
|
||||
<PostForm label={"投稿する"}/>
|
||||
<Post post={{
|
||||
text: "テスト~",
|
||||
sensitive: false,
|
||||
apId: "https://example.com",
|
||||
id: 1234,
|
||||
createdAt: Date.now(),
|
||||
url: "https://example.com",
|
||||
userId: 1234,
|
||||
visibility: "public"
|
||||
} as PostResponse}></Post>
|
||||
<Post post={{
|
||||
text: "テスト 公開範囲",
|
||||
sensitive: false,
|
||||
apId: "https://example.com",
|
||||
id: 1234,
|
||||
createdAt: 1234567,
|
||||
url: "https://example.com",
|
||||
userId: 1234,
|
||||
visibility: "direct"
|
||||
} as PostResponse}></Post>
|
||||
<Post post={{
|
||||
text: "テスト~",
|
||||
sensitive: false,
|
||||
apId: "https://example.com",
|
||||
id: 1234,
|
||||
createdAt: 1234567,
|
||||
url: "https://example.com",
|
||||
userId: 1234,
|
||||
visibility: "unlisted"
|
||||
} as PostResponse}></Post>
|
||||
<Post post={{
|
||||
text: "テスト~",
|
||||
sensitive: false,
|
||||
apId: "https://example.com",
|
||||
id: 1234,
|
||||
createdAt: 1234567,
|
||||
url: "https://example.com",
|
||||
userId: 1234,
|
||||
visibility: "followers"
|
||||
} as PostResponse}></Post>
|
||||
</Stack>
|
||||
</MainPage>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
import {ParentComponent} from "solid-js";
|
||||
import {Grid} from "@suid/material";
|
||||
import {Sidebar} from "./Sidebar";
|
||||
|
||||
export const MainPage: ParentComponent = (props) => {
|
||||
|
||||
return (
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={0} md={3}>
|
||||
<Sidebar/>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={5}>
|
||||
{props.children}
|
||||
</Grid>
|
||||
<Grid item xs={0} md={3}>
|
||||
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import {Component} from "solid-js";
|
||||
import {Stack} from "@suid/material";
|
||||
|
||||
export const Sidebar: Component = () => {
|
||||
return (
|
||||
<Stack>
|
||||
|
||||
</Stack>
|
||||
)
|
||||
}
|
Loading…
Reference in New Issue