Skip to content

Commit

Permalink
feat: photos and images
Browse files Browse the repository at this point in the history
  • Loading branch information
BIYUEHU committed Aug 13, 2024
1 parent 35cedff commit 6ea2083
Show file tree
Hide file tree
Showing 52 changed files with 4,737 additions and 2,983 deletions.
Empty file added TODO.md
Empty file.
4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
"common": "pnpm --filter @moehub/common",
"dev:core": "nodemon --watch",
"dev:client": "pnpm --filter @moehub/client dev",
"lint": "eslint \"packages/*/src/*.ts\" --fix",
"format": "prettier --config .prettierrc \"packages/*/src/*.ts\" --write",
"version": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0"
},
"devDependencies": {
Expand All @@ -29,7 +27,7 @@
"node": ">=17.9.0"
},
"nodemonConfig": {
"exec": "pnpm common build && tsx packages/core/src",
"exec": "pnpm common exec tsc --build && tsx packages/core/src",
"ext": "ts",
"ignore": ["packages/common", "packages/client"]
}
Expand Down
Binary file added packages/client/client.zip
Binary file not shown.
7 changes: 5 additions & 2 deletions packages/client/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<link
rel="icon"
type="image/svg+xml"
href="https://biyuehu.github.io/images/avatar.png"
href="https://hotaru.icu/api/qqavatar/index.php?qq=FrTFF7fjGbS2Fg%3D%3D&size=640"
/>
<meta
name="viewport"
Expand All @@ -16,7 +16,10 @@
name="description"
content="Your anime character collection gallery, easily build, freely share."
/>
<meta name="keywords" content="MoeHub,acg,ACG,GalGame,gal,GAL,galgame,anime,character,gallery,二次元,动漫,角色,二刺猿,游戏,视觉小说,avg,adv,漫画,动画,轻小说,acgn,ACGN" />
<meta
name="keywords"
content="MoeHub,acg,ACG,GalGame,gal,GAL,galgame,anime,character,gallery,二次元,动漫,角色,二刺猿,游戏,视觉小说,avg,adv,漫画,动画,轻小说,acgn,ACGN"
/>
</head>

<body>
Expand Down
3 changes: 3 additions & 0 deletions packages/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
},
"dependencies": {
"@ant-design/icons": "^5.3.7",
"@kotori-bot/core": "1.6.0-rc.1",
"@kotori-bot/i18n": "^1.3.2",
"@moehub/common": "workspace:^",
"@reduxjs/toolkit": "^2.2.6",
"antd": "^5.18.1",
Expand All @@ -19,6 +21,7 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-helmet-async": "^2.0.5",
"react-masonry-css": "^1.0.16",
"react-redux": "^9.1.2",
"react-router-dom": "^6.23.1",
"redux-persist": "^6.0.0",
Expand Down
51 changes: 29 additions & 22 deletions packages/client/src/components/CharacterForm/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Button, ColorPicker, DatePicker, Form, Input, InputNumber, Radio, Select, Space, Tabs } from 'antd'
import { Button, ColorPicker, DatePicker, Form, Input, InputNumber, Radio, Select, Space, Switch, Tabs } from 'antd'
import type { MoehubDataCharacter, MoehubDataCharacterSubmit } from '@moehub/common'
import dayjs from 'dayjs'
import { getTags } from '@/http'
import useSWR from 'swr'
import { useEffect } from 'react'
import ListForm from '../ListForm'
import { t } from '@/i18n'

export type MoehubDataCharacterHandle = Omit<MoehubDataCharacterSubmit, 'birthday' | 'color'> & {
birthday?: dayjs.Dayjs
Expand All @@ -28,48 +29,48 @@ interface CharacterFormProps {
const items = (isDisabled: boolean, tags?: { label: string; value: string }[]) => [
{
key: '1',
label: '基本信息',
label: t`com.characterForm.label.1`,
children: (
<>
<Form.Item name="name" label="角色名" rules={[{ required: true }]}>
<Form.Item name="name" label={t`com.characterForm.name`} rules={[{ required: true }]}>
<Input disabled={isDisabled} />
</Form.Item>
<Form.Item name="romaji" label="罗马音" rules={[{ required: true }]}>
<Form.Item name="romaji" label={t`com.characterForm.romaji`} rules={[{ required: true }]}>
<Input />
</Form.Item>
<Form.Item name="gender" label="性别" rules={[{ required: true }]}>
<Form.Item name="gender" label={t`com.characterForm.gender`} rules={[{ required: true }]}>
<Radio.Group>
<Radio.Button value="MALE">男性</Radio.Button>
<Radio.Button value="FEMALE">女性</Radio.Button>
<Radio.Button value="OTHER">其它/未知</Radio.Button>
<Radio.Button value="MALE">{t`com.characterForm.gender.male`}</Radio.Button>
<Radio.Button value="FEMALE">{t`com.characterForm.gender.female`}</Radio.Button>
<Radio.Button value="OTHER">{t`com.characterForm.gender.other`}</Radio.Button>
</Radio.Group>
</Form.Item>
<Form.Item name="series" label="作品名" rules={[{ required: true }]}>
<Form.Item name="series" label={t`com.characterForm.series`} rules={[{ required: true }]}>
<Input />
</Form.Item>
<Form.Item name="seriesGenre" label="作品类型" rules={[{ required: true }]}>
<Form.Item name="seriesGenre" label={t`com.characterForm.seriesGenre`} rules={[{ required: true }]}>
<Radio.Group>
<Radio value="ANIME">动画</Radio>
<Radio value="COMIC">漫画</Radio>
<Radio value="GALGAME">Galgame</Radio>
<Radio value="GAME">游戏</Radio>
<Radio value="NOVEL">轻小说</Radio>
<Radio value="OTHER">其它</Radio>
<Radio value="ANIME">{t`com.characterForm.seriesGenre.anime`}</Radio>
<Radio value="COMIC">{t`com.characterForm.seriesGenre.comic`}</Radio>
<Radio value="GALGAME">{t`com.characterForm.seriesGenre.galgame`}</Radio>
<Radio value="GAME">{t`com.characterForm.seriesGenre.game`}</Radio>
<Radio value="NOVEL">{t`com.characterForm.seriesGenre.novel`}</Radio>
<Radio value="OTHER">{t`com.characterForm.seriesGenre.other`}</Radio>
</Radio.Group>
</Form.Item>
</>
)
},
{
key: '2',
label: '详细信息',
label: t`com.characterForm.label.2`,
children: (
<>
<Form.Item name="alias" label="角色别名">
<Form.Item name="alias" label={t`com.characterForm.images.alias`}>
<Select mode="tags" />
</Form.Item>
<Form.Item label="相关图片">
<ListForm name="images" addButtonText="添加图片链接">
<Form.Item label={t`com.characterForm.images`}>
<ListForm name="images" addButtonText={t`com.characterForm.images.button`}>
{(name) => (
<Form.Item name={name} rules={[{ required: true }]}>
<Input />
Expand Down Expand Up @@ -103,7 +104,7 @@ const items = (isDisabled: boolean, tags?: { label: string; value: string }[]) =
},
{
key: '3',
label: '其它信息',
label: t`com.characterForm.label.3`,
children: (
<>
<Form.Item name="voice" label="声优">
Expand Down Expand Up @@ -144,6 +145,12 @@ const items = (isDisabled: boolean, tags?: { label: string; value: string }[]) =
<Form.Item name="url" label="相关链接">
<Select mode="tags" />
</Form.Item>
<Form.Item name="order" label="权重(值越小排列越靠前)" rules={[{ type: 'number' }]}>
<InputNumber min={1} />
</Form.Item>
<Form.Item name="hide" label="是否隐藏">
<Switch checkedChildren="隐藏" unCheckedChildren="显示" />
</Form.Item>
</>
)
}
Expand All @@ -170,7 +177,7 @@ const CharacterForm: React.FC<CharacterFormProps> = ({ onSubmit, data }) => {
<Form.Item>
<Space>
<Button type="primary" htmlType="submit" className="cardButton">
提交
{t`com.characterForm.submit`}
</Button>
</Space>
</Form.Item>
Expand Down
13 changes: 9 additions & 4 deletions packages/client/src/components/Layout/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Flex, Layout as AntLayout, Avatar } from 'antd'
import { LoginOutlined } from '@ant-design/icons'
import { PictureOutlined, PoweroffOutlined } from '@ant-design/icons'
import { Link, useNavigate } from 'react-router-dom'
import styles from './styles.module.css'
import { useEffect } from 'react'
Expand Down Expand Up @@ -41,9 +41,14 @@ const Layout: React.FC<LayoutProps> = ({ title, outlet, isPrivate }) => {
{settings.site_name}
</Link>
</h1>
<Link to="/admin">
<Avatar style={{ background: 'none', color: '#eee' }} icon={<LoginOutlined />} />
</Link>
<div>
<Link to="/photos">
<Avatar style={{ background: 'none', color: '#eee' }} icon={<PictureOutlined />} />
</Link>
<Link to="/admin">
<Avatar style={{ background: 'none', color: '#eee' }} icon={<PoweroffOutlined />} />
</Link>
</div>
</AntLayout.Header>
<AntLayout.Content className={styles.content}>{outlet}</AntLayout.Content>
<AntLayout.Footer className={styles.footer}>
Expand Down
4 changes: 4 additions & 0 deletions packages/client/src/http/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,7 @@ export async function postLogin(email: string, password: string): Promise<Moehub
export async function updateLogin(newPassword: string, oldPassword: string): Promise<MoehubApiBase<204>> {
return await httpNoCatcher.put('/settings/login', { newPassword, oldPassword })
}

export async function getImgs(): Promise<string[]> {
return (await http.get('/settings/imgs')).data
}
15 changes: 15 additions & 0 deletions packages/client/src/i18n/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import I18n from '@kotori-bot/i18n'
import locales from './locales'

const i18n = new I18n()

i18n.use(locales.en_US, 'en_US')
i18n.use(locales.ja_JP, 'ja_JP')
i18n.use(locales.zh_TW, 'zh_TW')
i18n.use(locales.zh_CN, 'zh_CN')

i18n.set('zh_CN')

export const t = i18n.t.bind(i18n)

export default i18n
53 changes: 53 additions & 0 deletions packages/client/src/i18n/locales.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
export default {
zh_CN: {
'com.characterForm.label.1': '基础信息',
'com.characterForm.label.2': '详细信息',
'com.characterForm.label.3': '其它信息',
'com.characterForm.submit': '提交',
'com.characterForm.name': '角色名',
'com.characterForm.romaji': '罗马音',
'com.characterForm.gender': '性别',
'com.characterForm.gender.male': '男性',
'com.characterForm.gender.female': '女性',
'com.characterForm.gender.other': '其它/未知',
'com.characterForm.series': '作品名',
'com.characterForm.seriesGenre': '作品类型',
/*
<Radio value="ANIME">{t`com.characterForm.seriesGenre.anime`}</Radio>
<Radio value="COMIC">{t`com.characterForm.seriesGenre.comic`}</Radio>
<Radio value="GALGAME">{t`com.characterForm.seriesGenre.galgame`}</Radio>
<Radio value="GAME">{t`com.characterForm.seriesGenre.game`}</Radio>
<Radio value="NOVEL">{t`com.characterForm.seriesGenre.novel`}</Radio>
<Radio value="OTHER">{t`com.characterForm.seriesGenre.other`}</Radio>
*/
'com.characterForm.seriesGenre.anime': '动画',
'com.characterForm.seriesGenre.comic': '漫画',
'com.characterForm.seriesGenre.galgame': 'Galgame/视觉小说',
'com.characterForm.seriesGenre.game': '游戏',
'com.characterForm.seriesGenre.novel': '轻小说',
'com.characterForm.seriesGenre.other': '其它',
'com.characterForm.tags': '萌点',
'com.characterForm.birthday': '生日',
'com.characterForm.color': '颜色',
'com.characterForm.description': '描述',
'com.characterForm.image': '图片',
'com.characterForm.image.upload': '上传图片',
'com.characterForm.image.upload.tip': '上传图片,支持 jpg、png、webp 格式,大小不超过 5MB',
'com.characterForm.image.upload.error': '上传失败,请重试'
},
en_US: {
'com.characterForm.label.1': 'Basis',
'com.characterForm.label.2': 'Details',
'com.characterForm.label.3': 'Others'
},
ja_JP: {
'com.characterForm.label.1': 'Basis',
'com.characterForm.label.2': 'Details',
'com.characterForm.label.3': 'Others'
},
zh_TW: {
'com.characterForm.label.1': 'Basis',
'com.characterForm.label.2': 'Details',
'com.characterForm.label.3': 'Others'
}
}
11 changes: 11 additions & 0 deletions packages/client/src/routes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ const routes: RouteConfig[] = [
component: lazyLoader(() => import('@/views/Character')),
title: '角色详情'
},
{
path: '/photos',
component: lazyLoader(() => import('@/views/Photos')),
title: '相册'
},
{
path: '/about',
component: lazyLoader(() => import('@/views/About')),
Expand Down Expand Up @@ -77,6 +82,12 @@ const routes: RouteConfig[] = [
title: '角色编辑',
isPrivate: true
},
{
path: '/admin/imgs',
component: lazyLoader(() => import('@/views/Admin/Imgs')),
title: '图片上传',
isPrivate: true
},
{
path: '*',
component: lazyLoader(() => import('@/views/404')),
Expand Down
5 changes: 4 additions & 1 deletion packages/client/src/styles/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ a::selection {
.cardSquare {
width: 550px;
max-width: 95vw;

}

.clean {
Expand All @@ -72,4 +71,8 @@ a::selection {
width: 500px;
max-width: 95%;
margin: 0 auto;
}

h1, h2, h3, h4, h5, h6 {
font-weight: bold;
}
65 changes: 65 additions & 0 deletions packages/client/src/views/Admin/Imgs/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { Card, Flex, Upload, type UploadFile, type UploadProps, notification } from 'antd'
import config from '@/http/config'
import Dragger from 'antd/es/upload/Dragger'
import { InboxOutlined } from '@ant-design/icons'
import { useSelector } from 'react-redux'
import { getToken } from '@/store/adminReducer'
import { useState } from 'react'

const ImgsView: React.FC = () => {
const token = useSelector(getToken)
const [fileList, setFileList] = useState<UploadFile[]>([])

const props: UploadProps = {
name: 'file',
multiple: true,
action: `${config.url}/settings/imgs`,
headers: {
Authorization: `Bearer ${token}`
},
fileList,
beforeUpload: (file) => {
const isPNG = file.type.startsWith('image/')
if (!isPNG) notification.error({ message: `${file.name} 不是一个图片文件` })
return isPNG || Upload.LIST_IGNORE
},
onChange(info) {
setFileList(
info.fileList.map((file) => {
const newName = file.response?.data?.[0]?.filename
const url = newName ? `${new URL(config.url).origin}/imgs/${newName}` : undefined
return { ...file, name: newName ?? file.name, url }
})
)
console.log(info)
const { status } = info.file
// if (status !== 'uploading') {
// console.log(info.file, info.fileList)
// }
if (status === 'done') {
notification.success({ message: `${info.file.name} 文件上传成功` })
} else if (status === 'error') {
notification.error({ message: `${info.file.name} 文件上传失败` })
}
}
}

return (
<div>
<h1>图片上传</h1>
<Flex justify="center" align="center" vertical wrap>
<Card hoverable className="card cardFixed">
<Dragger {...props}>
<p className="ant-upload-drag-icon">
<InboxOutlined />
</p>
<p className="ant-upload-text">点击或拖拽文件到该区域进行上传</p>
<p className="ant-upload-hint">一次性支持单个或多个图片上传</p>
</Dragger>
</Card>
</Flex>
</div>
)
}

export default ImgsView
Loading

0 comments on commit 6ea2083

Please sign in to comment.