夜莺活动

master
liu min 2023-08-04 15:47:42 +08:00
commit 5b0589005e
73 changed files with 10296 additions and 0 deletions

80
.drone.yml Normal file
View File

@ -0,0 +1,80 @@
kind: pipeline
name: linear-dream-hd-pipeline
platform:
os: linux
arch: amd64
workspace:
path: /drone/src
trigger:
branch:
- master
event:
- push
image_pull_secrets:
- docker_auth_config
steps:
- name: build(release
image: node:14.18.1
commands:
- CI=false
- echo 'build 打包部署'
- npm config set registry https://registry.npm.taobao.org
- npm config set disturl https://npm.taobao.org/dist
- npm config set electron_mirror https://npm.taobao.org/mirrors/electron/
- npm config set sass_binary_site https://npm.taobao.org/mirrors/node-sass/
- npm config set phantomjs_cdnurl https://npm.taobao.org/mirrors/phantomjs/
- npm install cnpm -g
- npm install -g create-react-app
- npm install --save-dev react-dev-utils
- npm install --save-dev patch-package
- npm install --save-dev jsondiffpatch-for-react
- npm install --save-dev dotenv-cli
- npm install
- npm run build:test
when:
branch:
- release/*
status: [ success ]
- name: push(release
image: plugins/docker
settings:
username: lunar@starlinear
password:
from_secret: CI_PWD
insecure: true
repo: linear-repo-registry.cn-shanghai.cr.aliyuncs.com/platform/dream-hd
dockerfile: Dockerfile
registry: linear-repo-registry.cn-shanghai.cr.aliyuncs.com
tags:
- 'release'
when:
branch:
- release/*
status: [ success ]
- name: deploy(release
image: appleboy/drone-ssh
settings:
host: 106.15.72.97
username: root
ssh_key:
from_secret: SSH_KEY
port: 22
insecure: false
command_timeout: 3m
script:
- docker pull linear-repo-registry-vpc.cn-shanghai.cr.aliyuncs.com/platform/dream-hd:release
- cd /wwwroot/dream-hd/
- docker-compose down
- docker-compose -f docker-compose.yml up -d
when:
branch:
- release/*
status: [ success ]

15
.editorconfig Normal file
View File

@ -0,0 +1,15 @@
# @see: http://editorconfig.org
root = true
[*] # 表示所有文件适用
charset = utf-8 # 设置文件字符集为 utf-8
end_of_line = lf # 控制换行类型(lf | cr | crlf)
insert_final_newline = true # 始终在文件末尾插入一个新行
indent_style = tab # 缩进风格tab | space
indent_size = 2 # 缩进大小
max_line_length = 130 # 最大行长度
[*.md] # 表示仅 md 文件适用以下规则
max_line_length = off # 关闭最大行长度限制
trim_trailing_whitespace = false # 关闭末尾空格修剪

16
.eslintignore Normal file
View File

@ -0,0 +1,16 @@
*.sh
node_modules
*.md
*.woff
*.ttf
.vscode
.idea
dist
/public
/docs
.husky
.local
/bin
.eslintrc.js
.prettierrc.js
/src/mock/*

79
.eslintrc.cjs Normal file
View File

@ -0,0 +1,79 @@
module.exports = {
settings: {
react: {
version: "detect"
}
},
root: true,
env: {
browser: true,
es2020: true,
es6: true,
node: true
},
/* 指定如何解析语法 */
parser: "@typescript-eslint/parser",
/* 优先级低于 parse 的语法解析配置 */
parserOptions: {
ecmaVersion: 2020,
sourceType: "module",
jsxPragma: "React",
ecmaFeatures: {
jsx: true
}
// project: "tsconfig.json",
},
plugins: ["react", "@typescript-eslint", "react-hooks", "prettier"],
/* 继承某些已有的规则 */
extends: [
"eslint:recommended",
"plugin:react/recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react-hooks/recommended",
"plugin:react/jsx-runtime",
"prettier",
"plugin:prettier/recommended"
],
/*
* "off" 0 ==> 关闭规则
* "warn" 1 ==> 打开的规则作为警告不影响代码执行
* "error" 2 ==> 规则作为一个错误代码不能执行界面报错
*/
rules: {
"no-var": "error", // 要求使用 let 或 const 而不是 var
"no-multiple-empty-lines": [
"error",
{
max: 1
}
], // 不允许多个空行
"no-use-before-define": "off", // 禁止在 函数/类/变量 定义之前使用它们
"prefer-const": "off", // 此规则旨在标记使用 let 关键字声明但在初始分配后从未重新分配的变量,要求使用 const
"no-irregular-whitespace": "off", // 禁止不规则的空白
// typeScript (https://typescript-eslint.io/rules)
"@typescript-eslint/no-unused-vars": "error", // 禁止定义未使用的变量
"@typescript-eslint/no-inferrable-types": "off", // 可以轻松推断的显式类型可能会增加不必要的冗长
"@typescript-eslint/no-namespace": "off", // 禁止使用自定义 TypeScript 模块和命名空间。
"@typescript-eslint/no-explicit-any": "off", // 禁止使用 any 类型
"@typescript-eslint/ban-ts-ignore": "off", // 禁止使用 @ts-ignore
"@typescript-eslint/ban-types": "off", // 禁止使用特定类型
"@typescript-eslint/explicit-function-return-type": "off", // 不允许对初始化为数字、字符串或布尔值的变量或参数进行显式类型声明
"@typescript-eslint/no-var-requires": "off", // 不允许在 import 语句中使用 require 语句
"@typescript-eslint/no-empty-function": "off", // 禁止空函数
"@typescript-eslint/no-use-before-define": "off", // 禁止在变量定义之前使用它们
"@typescript-eslint/ban-ts-comment": "off", // 禁止 @ts-<directive> 使用注释或要求在指令后进行描述
"@typescript-eslint/no-non-null-assertion": "off", // 不允许使用后缀运算符的非空断言(!)
"@typescript-eslint/explicit-module-boundary-types": "off", // 要求导出函数和类的公共类方法的显式返回和参数类型
// react (https://github.com/jsx-eslint/eslint-plugin-react)
"react-hooks/rules-of-hooks": "off",
"react-hooks/exhaustive-deps": "off",
"prettier/prettier": [
"error",
{
printWidth: 130
}
]
}
};

24
.gitignore vendored Normal file
View File

@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
# dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

8
.prettierignore Normal file
View File

@ -0,0 +1,8 @@
/dist/*
.local
/node_modules/**
**/*.svg
**/*.sh
/public/*

39
.prettierrc.cjs Normal file
View File

@ -0,0 +1,39 @@
// @see: https://www.prettier.cn
module.exports = {
// 超过最大值换行
printWidth: 130,
// 缩进字节数
tabWidth: 2,
// 使用制表符而不是空格缩进行
useTabs: true,
// 结尾不用分号(true有false没有)
semi: true,
// 使用单引号(true单双引号false双引号)
singleQuote: false,
// 更改引用对象属性的时间 可选值"<as-needed|consistent|preserve>"
quoteProps: "as-needed",
// 在对象,数组括号与文字之间加空格 "{ foo: bar }"
bracketSpacing: true,
// 多行时尽可能打印尾随逗号。(例如,单行数组永远不会出现逗号结尾。) 可选值"<none|es5|all>"默认none
trailingComma: "none",
// 在JSX中使用单引号而不是双引号
jsxSingleQuote: false,
// (x) => {} 箭头函数参数只有一个时是否要有小括号。avoid省略括号 ,always不省略括号
arrowParens: "avoid",
// 如果文件顶部已经有一个 doclock这个选项将新建一行注释并打上@format标记。
insertPragma: false,
// 指定要使用的解析器,不需要写文件开头的 @prettier
requirePragma: false,
// 默认值。因为使用了一些折行敏感型的渲染器如GitHub comment而按照markdown文本样式进行折行
proseWrap: "preserve",
// 在html中空格是否是敏感的 "css" - 遵守CSS显示属性的默认值 "strict" - 空格被认为是敏感的 "ignore" - 空格被认为是不敏感的
htmlWhitespaceSensitivity: "css",
// 换行符使用 lf 结尾是 可选值"<auto|lf|crlf|cr>"
endOfLine: "lf",
// 这两个选项可用于格式化以给定字符偏移量(分别包括和不包括)开始和结束的代码
rangeStart: 0,
rangeEnd: Infinity,
// Vue文件脚本和样式标签缩进
vueIndentScriptAndStyle: false,
};

7
Dockerfile Normal file
View File

@ -0,0 +1,7 @@
FROM nginx:latest
WORKDIR /usr/share/nginx/html/
COPY ./build /usr/share/nginx/html/
EXPOSE 80

18
docker-compose.yml Normal file
View File

@ -0,0 +1,18 @@
version: '3.7'
services:
gms-front:
image: linear-repo-registry-vpc.cn-shanghai.cr.aliyuncs.com/platform/dream-hd:release
privileged: true
cap_add:
- ALL
restart: always
container_name: dream-hd
resources:
limits:
cpus: "0.30"
expose:
- 80
ports:
- 3001:80
environment:
- TZ=Asia/Shanghai

16
index.html Normal file
View File

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/logo.png" />
<meta
name="viewport"
content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
<title>《欢迎来到梦乐园》夜莺专属定制</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

8679
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

41
package.json Normal file
View File

@ -0,0 +1,41 @@
{
"name": "hd.star.linear",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
"dependencies": {
"html2canvas": "^1.4.1",
"postcss-pxtorem": "^6.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.14.2"
},
"devDependencies": {
"@types/node": "^20.4.2",
"@types/postcss-pxtorem": "^6.0.0",
"@types/react": "^18.2.14",
"@types/react-dom": "^18.2.6",
"@types/react-router-dom": "^5.3.3",
"@typescript-eslint/eslint-plugin": "^5.61.0",
"@typescript-eslint/parser": "^5.61.0",
"@vitejs/plugin-react": "^4.0.1",
"eslint": "^8.44.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.32.2",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.1",
"less": "^4.1.3",
"less-loader": "^11.1.3",
"prettier": "^2.8.8",
"typescript": "^5.0.2",
"vite": "^4.4.0",
"vite-plugin-eslint": "^1.8.1"
}
}

BIN
public/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

1
public/vite.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

10
src/App.tsx Normal file
View File

@ -0,0 +1,10 @@
import { HashRouter } from "react-router-dom";
import Router from "@/routers/index";
function App() {
return (
<HashRouter>
<Router></Router>
</HashRouter>
);
}
export default App;

View File

@ -0,0 +1,40 @@
.mask {
position: fixed;
top: 0;
left: 50%;
transform: translateX(-50%);
background: rgba(0, 0, 0, 0.85);
width: 100%;
height: 100%;
z-index: 1000;
overflow: hidden;
max-width: 500px;
.rulesBox {
text-align: center;
position: relative;
max-width: 500px;
.rules {
width: 100%;
height: 100%;
}
.close {
text-align: center;
width: 126px;
height: 126px;
background-position: center;
background-repeat: no-repeat;
background-size: cover;
margin: -96px auto 0;
z-index: 10;
position: relative;
}
.link {
position: absolute;
bottom: 33.5%;
right: 16%;
width: 40%;
height: 4%;
// background-color: #fff;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 849 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 480 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 472 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 463 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 494 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 518 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 433 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 488 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 460 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 489 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 448 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 467 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 449 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 466 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 469 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 485 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 474 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 477 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 435 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 470 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

1
src/assets/react.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -0,0 +1,12 @@
import "@assets/components/outMask.less";
const outMask = (props: any) => {
const Child = props.child;
return (
<div className="mask">
<Child />
</div>
);
};
export default outMask;

4
src/main.tsx Normal file
View File

@ -0,0 +1,4 @@
import ReactDOM from "react-dom/client";
import App from "./App.tsx";
import "@/styles/reset.less";
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(<App />);

26
src/routers/index.tsx Normal file
View File

@ -0,0 +1,26 @@
import { Navigate, useRoutes } from "react-router-dom";
import { RouteObject } from "@/routers/interface";
import Nightingale from "@/views/nightingale/index";
// import {lazy} from 'react'
// * 处理路由
export const rootRouter: RouteObject[] = [
{
path: "/",
element: <Navigate to="/nightingale" />
},
{
path: "/nightingale",
element: <Nightingale />
},
{
path: "*",
element: <Navigate to="/404" />
}
];
const Router = () => {
const routes = useRoutes(rootRouter);
return routes;
};
export default Router;

View File

@ -0,0 +1,14 @@
export interface MetaProps {
keepAlive?: boolean;
requiresAuth?: boolean;
title: string;
key?: string;
}
export interface RouteObject {
caseSensitive?: boolean;
element?: React.ReactNode;
index?: boolean;
path?: string;
meta?: MetaProps;
}

89
src/styles/common.less Normal file
View File

@ -0,0 +1,89 @@
// 常用 flex
.flx-center {
display: flex;
align-items: center;
justify-content: center;
}
.flx-justify-bewteen {
display: flex;
align-items: center;
justify-content: space-between;
}
.flx-align-center {
display: flex;
align-items: center;
}
// 清除浮动
.clearfix::after {
display: block;
height: 0;
overflow: hidden;
clear: both;
content: '';
}
// 文字多了自动换行
.break-warp {
word-wrap: break-all;
word-wrap: break-word;
}
// 滚动条设置
::-webkit-scrollbar {
width: 8px;
height: 8px;
background-color: #fff;
}
::-webkit-scrollbar-thumb {
background-color: #fff;
border-radius: 20px;
box-shadow: inset 0 0 0 #fff;
}
// 动画效果
.fade-enter {
opacity: 0;
transform: translateX(-30px);
}
.fade-enter-active,
.fade-exit-active {
opacity: 1;
transition: all 0.2s ease-out;
transform: translateX(30px);
}
.fade-exit {
opacity: 0;
transform: translateX(30px);
}
// content-box样式
.content-box {
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
.text {
margin: 30px 0;
font-size: 23px;
font-weight: 700;
text-align: center;
a {
text-decoration: underline !important;
}
}
}
// 卡片样式
.card {
box-sizing: border-box;
padding: 20px;
overflow-x: hidden;
border: 1px solid #e4e7ed;
border-radius: 4px;
}

141
src/styles/reset.less Normal file
View File

@ -0,0 +1,141 @@
/* Reset style sheet */
body {
background: #000;
overflow-x: hidden;
scrollbar-width: none;
&::-webkit-scrollbar {
width: 0 !important;
}
}
html,
body,
div,
span,
applet,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
a,
abbr,
acronym,
address,
big,
cite,
code,
del,
dfn,
em,
img,
ins,
kbd,
q,
s,
samp,
small,
strike,
strong,
sub,
sup,
tt,
var,
b,
u,
i,
center,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
canvas,
details,
embed,
figure,
figcaption,
footer,
header,
hgroup,
menu,
nav,
output,
ruby,
section,
summary,
time,
mark,
audio,
video {
padding: 0;
margin: 0;
font: inherit;
font-size: 100%;
vertical-align: baseline;
border: 0;
}
/* HTML5 display-role reset for older browsers */
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
menu,
nav,
section {
display: block;
}
body {
padding: 0;
margin: 0;
}
ol,
ul {
list-style: none;
}
blockquote,
q {
quotes: none;
}
blockquote::before,
blockquote::after,
q::before,
q::after {
content: "";
content: none;
}
table {
border-spacing: 0;
border-collapse: collapse;
}
html,
body,
#root {
width: 100%;
height: 100%;
}

View File

@ -0,0 +1,394 @@
// @media all and (orientation: portrait) {
.home {
width: 100%;
height: 100%;
max-width: 500px;
overflow-y: hidden;
margin: 0 auto;
display: flex;
justify-content: flex-start;
-webkit-user-select: none; /* Chrome all / Safari all */
-moz-user-select: none; /* Firefox all */
-ms-user-select: none; /* IE 10+ */ /* No support for these yet,use at own risk */
-o-user-select: none;
user-select: none;
.playBtn {
position: absolute;
right: 27px;
top: 55px;
width: 42px;
height: 37px;
z-index: 10000;
}
.startBox {
width: 100vw;
max-width: 500px;
height: 100%;
align-items: center;
display: flex;
flex-direction: column;
text-align: center;
position: relative;
background-position: center;
background-repeat: no-repeat;
background-size: cover;
background-size: cover;
z-index: 100;
position: relative;
overflow-y: hidden;
&.fadeOut {
opacity: 0;
transition: all 1s;
z-index: -100;
}
.logo {
width: 250px;
margin: 16px auto 0;
}
.age {
position: absolute;
right: 27px;
top: 114px;
width: 35px;
}
.start {
position: absolute;
bottom: 118px;
left: 0;
width: 100%;
}
.tips {
position: absolute;
bottom: 100px;
left: 0;
color: #ffefd1;
width: 100%;
}
.starlinear {
width: 128px;
position: absolute;
bottom: 27px;
left: 50%;
transform: translateX(-50%);
}
}
.beginText {
max-width: 500px;
width: 100vw;
height: 100%;
align-items: center;
display: flex;
align-items: center;
flex-direction: column;
justify-content: center;
background-position: 0 0;
background-position: center;
background-repeat: no-repeat;
background-size: cover;
z-index: 50;
position: absolute;
opacity: 1;
&.fadeOut {
opacity: 0;
transition: all 1s;
z-index: -50;
}
.textList {
font-size: 14px;
width: 80%;
text-align: center;
color: #ffefd1;
font-weight: 200;
margin-bottom: 0px;
// margin-bottom: 140px;
opacity: 0;
&.fadein {
margin-bottom: 140px;
opacity: 1;
transition: all 2s;
}
.textItem {
line-height: 1.6;
}
.mt {
margin-top: 20px;
}
}
.step2 {
width: 351px;
height: 69px;
text-align: center;
background-position: center;
background-repeat: no-repeat;
background-size: cover;
line-height: 65px;
font-size: 12px;
color: #ffefd1;
font-weight: 400;
position: absolute;
bottom: 20%;
opacity: 0;
&.fadein {
opacity: 1;
transition: all 4s;
}
}
}
.startText {
width: 100%;
height: 100%;
max-width: 500px;
align-items: center;
display: flex;
align-items: center;
flex-direction: column;
justify-content: center;
background-position: 0 0;
background-position: center;
background-repeat: no-repeat;
background-size: cover;
z-index: 50;
opacity: 1;
position: absolute;
&.fadeOut {
opacity: 0;
transition: all 1s;
z-index: -50;
}
.textList {
font-size: 14px;
text-align: center;
color: #ffefd1;
font-weight: 200;
margin-bottom: 0px;
opacity: 0;
&.fadein {
margin-bottom: 140px;
opacity: 1;
transition: all 2s;
}
.textItem {
line-height: 1.6;
}
}
.step2 {
width: 351px;
height: 69px;
text-align: center;
background-position: center;
background-repeat: no-repeat;
background-size: cover;
margin: 180px auto 0;
line-height: 65px;
font-size: 12px;
color: #ffefd1;
font-weight: 400;
position: absolute;
bottom: 20%;
opacity: 0;
&.fadein {
opacity: 1;
transition: all 4s;
}
}
}
.qa {
width: 100%;
max-width: 500px;
height: 100%;
align-items: center;
display: flex;
flex-direction: column;
justify-content: center;
background-position: center;
background-repeat: no-repeat;
background-size: cover;
padding: 0 53px;
box-sizing: border-box;
position: absolute;
opacity: 1;
z-index: 10;
&.fadeOut {
opacity: 0;
transition: all 1s;
z-index: -1;
}
.req {
font-size: 15px;
text-align: center;
color: #ffefd1;
font-weight: 200;
margin-top: 46%;
padding: 5px 40px;
background-position: center;
background-repeat: no-repeat;
background-size: 100% 100%;
margin-bottom: 15px;
opacity: 1;
transition: all 1.5s;
&.active {
opacity: 0;
transition: all 1.5s;
}
}
.reqBtn {
width: 209px;
height: 69px;
text-align: center;
background-position: center;
background-repeat: no-repeat;
background-size: cover;
line-height: 65px;
font-size: 12px;
color: #ffefd1;
margin-bottom: -15px;
position: relative;
// transition: all 0.5s;
&::after {
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 69px;
display: block;
background: url("@night/btn_hignlight.png") center no-repeat;
background-size: auto 100%;
content: "";
}
&.active {
color: #494949;
transition: all 0.6s;
p {
z-index: 2;
position: relative;
}
&::after {
width: 209px;
}
}
}
}
.resultBox {
width: 100%;
max-width: 500px;
min-height: 100vh;
align-items: center;
display: flex;
flex-direction: column;
justify-content: flex-end;
position: absolute;
background-position: center;
background-repeat: no-repeat;
background-size: cover;
opacity: 0;
position: absolute;
z-index: -1;
&.active {
max-height: 250vw;
opacity: 1;
z-index: 1;
}
.figure {
width: 100%;
height: 100%;
}
.shareBtn {
width: 209px;
height: 70px;
background-position: center;
background-repeat: no-repeat;
background-size: cover;
position: relative;
z-index: 1001;
position: absolute;
left: 50%;
bottom: 13%;
transform: translateX(-50%);
}
.saveTips {
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: 12%;
color: #ffeed1;
font-size: 12px;
}
.pic_bottom {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 13.5%;
background-position: center;
background-repeat: no-repeat;
background-size: 100% 100%;
.toDream {
position: absolute;
bottom: 6.5vh;
right: 7%;
width: 41%;
z-index: 1001;
height: 2vh;
// background-color: #fff;
}
}
}
.canvasImg {
max-width: 500px;
width: 100%;
align-items: center;
display: flex;
flex-direction: column;
justify-content: flex-end;
background-position: center;
background-repeat: no-repeat;
background-size: cover;
position: absolute;
top: 0;
left: 0;
opacity: 0;
&.active {
// height: 100vh;
// height: 243vw;
z-index: 1000;
}
}
}
// }
// #root {
// position: relative;
// &::after {
// content: "请将页面调整至竖屏体验";
// font-size: 24px;
// display: block;
// position: fixed;
// top: 50%;
// left: 50%;
// transform: translate(-50%, -50%);
// color: #ffefd1;
// z-index: 10000;
// width: 100%;
// height: 100%;
// background: #000;
// text-align: center;
// line-height: 90vh;
// }
// }
// .home {
// width: 100%;
// height: 100%;
// background: rgba(0, 0, 0, 0.8);
// display: none;
// position: relative;
// }

View File

@ -0,0 +1,469 @@
import { useEffect, useState, useRef } from "react";
import pic_logo from "@night/pic_logo.png";
import music_off from "@night/btn_music_off.png";
import music_on from "@night/btn_music_on.png";
import age from "@night/age.png";
import start from "@night/btn_start.png";
import pic_linear from "@night/pic_linear.png";
import bg from "@night/bg.jpg";
import bg_qa from "@night/bg_qa.png";
import bg_2 from "@night/bg_2.png";
import btn_log from "@night/btn_log.png";
import qa_line from "@night/qa_line.png";
import shareBtn from "@night/btn_share.png";
import pic_bottom from "@night/pic_bottom.png";
import res_bg from "@night/res_bg.png";
import rules from "@night/rules.png";
import closeBtn from "@night/closeBtn.png";
import OutMask from "@/components/OutMask.tsx";
import "./index.less";
const Nightingale = () => {
// 默认格式
interface qaProps {
[propName: string]: any;
}
interface reqProps {
[propName: string]: any;
}
interface reqItemProps {
[propName: string]: any;
}
// state
const [step, setStep] = useState(-1);
// 选择的选项
const [req, setReq] = useState("first");
const [qa, setQa] = useState("first");
const [figure, setFigure] = useState("Flihine");
// 是否可点击
const [btnClick, setBtn] = useState(false);
// 当前点击按钮
const [btnValue, setBtnValue] = useState("");
const [showRules, setRules] = useState(false);
// 动画是否结束
const [isOver, setOver] = useState(false);
// 控制是否播放
const [isPlaying, setIsPlaying] = useState(false);
// 1.定义audioRef获取audio标签
const audioRef = useRef<HTMLAudioElement>(null);
useEffect(() => {
// DOM渲染完成后给audio赋值播放地址
audioRef.current!.src = "https://cdn.star-linear.com/voice/hd/nightingale_bgm.wav";
}, []);
const qaList: qaProps = {
first: ["当你步入夜莺", "您看到的身影是一位"],
man: ["您所期待的,", "是怎样年龄阶段的男性呢?"],
hair: ["您所期待的人,", "拥有怎样的发型呢?"],
color: ["在您的眼中,", "看到了怎样的色彩?"],
name: ["请确认您的指名对象。"],
character: ["您希望对方是什么性格?"]
};
//全部答案选项列表 设置下一个答案选项数组
const reqList: reqProps = {
first: [
{ title: "身份成谜的男性", value: "man", qa: "man" },
{ title: "身份成谜的女性", value: "woman", qa: "hair" }
],
// 男性
man: [
{ title: "看起来稚嫩的人", value: "immature", qa: "color" },
{ title: "看起来成熟的人", value: "mature", qa: "character" }
],
// 稚嫩
immature: [
{ title: "浅色", value: "light", qa: "name" },
{ title: "深色", value: "dark", qa: "name" }
],
light: [{ title: "目中无人的冰山恶龙", value: "Limmel", qa: "end" }],
dark: [
{ title: "古灵精怪的炼金术师", value: "Kikidi", qa: "end" },
{ title: "淘气好动的松鼠兽族", value: "Cocodi", qa: "end" },
{ title: "勤奋上进的魔法学徒", value: "ethan", qa: "end" }
],
// 成熟
mature: [
{ title: "温和的", value: "mild_mature", qa: "color" },
{ title: "活泼的", value: "lively_mature", qa: "hair" },
{ title: "神秘的", value: "cold_mature", qa: "hair" }
],
//成熟- 温和
mild_mature: [
{ title: "浅色", value: "mature_light", qa: "name" },
{ title: "深色", value: "mature_dark", qa: "name" }
],
// 成熟- 温和 - 浅色
mature_light: [
{ title: "温柔谦逊的第一王子", value: "Demian", qa: "end" },
{ title: "包容固执的远古精灵", value: "Selieu", qa: "end" }
],
// 成熟- 温和 - 浅色
mature_dark: [
{ title: "温文尔雅的商会当家", value: "Norden", qa: "end" },
{ title: "酔心拳法的习武之人", value: "Liyan", qa: "end" }
],
// 成熟-活泼
lively_mature: [
{ title: "长发", value: "mature_long", qa: "name" },
{ title: "短发", value: "mature_short", qa: "name" }
],
// 成熟-活泼-长发
mature_long: [
{ title: "口蜜腹剑的完美执事", value: "Luya", qa: "end" },
{ title: "天性自由洒脱的船长", value: "Alvaro", qa: "end" }
],
// 成熟-活泼-短发
mature_short: [
{ title: "热情风趣的吟游诗人", value: "Fermon", qa: "end" },
{ title: "讹言谎语的神秘妖怪", value: "Fumiya", qa: "end" }
],
// 成熟-冷淡
cold_mature: [
{ title: "中长发", value: "cold_long", qa: "color" },
{ title: "短发", value: "cold_short", qa: "color" }
],
// 成熟-冷淡-长发
cold_long: [
{ title: "冷色", value: "middle_light", qa: "name" },
{ title: "暖色", value: "middle_dark", qa: "name" }
],
middle_light: [
{ title: "善于交涉的年少骑士", value: "Shafie", qa: "end" },
{ title: "精明善辩的狡诈商人", value: "Flihine", qa: "end" }
],
middle_dark: [
{ title: "顾影自怜的独角兽", value: "Emic", qa: "end" },
{ title: "才思敏捷的自由骑士", value: "Bethina", qa: "end" }
],
// 成熟-冷淡-短发
cold_short: [
{ title: "浅色", value: "short_light", qa: "name" },
{ title: "深色", value: "short_dark", qa: "name" }
],
// 成熟-冷淡-短发-浅色
short_light: [
{ title: "成熟稳重的剑术教官", value: "Regis", qa: "end" },
{ title: "笑起来很诡异的忍者", value: "Hisoga", qa: "end" }
],
// 成熟-冷淡-短发- 深色
short_dark: [
{ title: "严厉果决的海军统领", value: "Isreall", qa: "end" },
{ title: "聪慧可靠的雇佣法师", value: "Gluna", qa: "end" }
],
// 女性
woman: [
{ title: "中短发", value: "short", qa: "character" },
{ title: "长发", value: "long", qa: "character" }
],
// 长发
short: [
{ title: "活泼的", value: "livel_long", qa: "name" },
{ title: "温和的", value: "mild_long", qa: "name" }
],
// 长发-活泼
livel_long: [{ title: "卖面包的人气小说家", value: "Mellie", qa: "end" }],
// 长发-温和
mild_long: [
{ title: "精明能干的优雅淑女", value: "Lillian", qa: "end" },
{ title: "清和平允的银白骑士", value: "Ophelia", qa: "end" }
],
// 短发
long: [
{ title: "神秘的", value: "woman_short", qa: "name" },
{ title: "活泼的", value: "lively_short", qa: "name" }
],
// 短发 -冷淡
woman_short: [
{ title: "神秘莫测的深红女巫", value: "Rosana", qa: "end" },
{ title: "优雅疏离的帽子女巫", value: "Filin", qa: "end" }
],
// 短发 - 活泼
lively_short: [
{ title: "活力四射的铃铛巫女", value: "Suzune", qa: "end" },
{ title: "狡黠可爱的狐狸小妖", value: "JinYingZi", qa: "end" }
]
};
// 结果列表
// const figureList: reqProps = {
// Kikidi: [
// "“乐园真是个好地方呀,总是会有络绎不绝的人走进来被我捉弄呢!”",
// "传说暗夜里不仅有危险,还有奇琪蒂——深红馆中唯一的男性巫师,外表看起来还算可爱,实际上是个对外隐藏自己真实身份,喜欢捉弄“猎物”,如同蝙蝠一般昼伏夜出的小恶魔。换句话说,如果不想被奇琪蒂抓住,那就不要熬夜,早些休息。"
// ],
// Limmel: [
// "“耀眼又美丽的宝石,我的名字是莱米尔。从今以后就是你的守护者了。别害怕,我会好好保护你的。”",
// "不知为何忽然出现在洛维斯的龙族少年,光凭外表就知道他肯定拥有尊贵的身份。莱米尔性格古怪,对待陌生人十分粗暴冷漠,对待亲近的人则时而霸道时而乖顺,让人难以捉摸。据说离开家乡是为了寻找只属于自己的,重要的“珍宝”。"
// ],
// Cocodi: [
// "“高大的兽族总是趾高气昂,他们不过是块头大了一点而已......”",
// "活泼可爱有点娇气的松鼠兽族。才来到人类社会,并不熟悉这里的规则,处于对一切都感到非常新鲜的时期。虽然模样可爱但有过大闹坚果店的恶劣记录!……所以,实际上是个名声在外的麻烦人物。对于柔软蓬松的尾巴非常自豪!关系好的话会让你摸一摸也说不定。"
// ],
// ethan: [
// "“老师说我在发传单方面有异常的才华,是不是放弃魔法成为推销员会比较好?”",
// "因为有一些魔术天赋,伊森走上了学习魔法的道路,虽然付出了许多努力,但收获颇少。时常因为成绩不理想而苦恼着。“比起魔法师,果然还是做一个街头魔术师更适合我……”伊森时常这样懊恼着。"
// ],
// Demian: [
// "“骑士,德米安。我以手中的剑起誓,绝不会让你受到任何伤害。”",
// "洛维斯的王子,同时也是拂晓骑士们的首领。他年轻有为,但从不骄傲,待人始终温和有礼。他虽然拥有强大的力量,但绝对不会滥用,是世人眼里完美的王子殿下——尽管他也有不擅长的事情。"
// ],
// Selieu: [
// "“比起提前知道答案,我更想和你一起慢慢前进……直到最后。”",
// "在精灵王的庇护与指引下,白雾之森的生灵与世隔绝、宁静悠闲。他喜爱和平,厌恶纷争,温和得如同春天吹过永盛花原的第一缕风。不过作为一个生命漫长无涯的远古精灵,瑟琉偶尔也会显露出偏执的一面,他有自己的坚持。"
// ],
// Norden: [
// "“同你合作非常顺心,以后也请多关照了。”",
// "温和有礼的成功商人,时常彬彬有礼地提出一些过分的要求……让人难以琢磨。如果他主动提出合作需求,请一定仔细考虑,并详读他撰写的合同。"
// ],
// Liyan: [
// "“又到修行的时间了。”",
// "出身陶缘的武道家,为挑战强者、精进武艺而不断游历中。沉稳、踏实,但是不太会说话,对于该如何与异性相处一窍不通,和女孩对视就会不由自主变口吃。总的来说是个认真且正直的人,承诺过的事无论多难都会做到,出了名的可靠。"
// ],
// Luya: [
// "“没有比我更完美的执事,请您记住这一点。”",
// "总在塔吉玛出没的神秘执事。只要是雇主的要求,无论多么奇怪,都能百分之百完美完成,以“为雇主提供优质生活”而努力。不过在执事这一身份的背后,路亚似乎有着不为人知的一面……"
// ],
// Alvaro: [
// "“要戴这顶帽子吗,以后你是船长,我是你的副手。”",
// "虽然阿尔瓦罗宣称自己“只是个不起眼的船长罢了”,但谁都知道塔吉玛的海面曾因他而掀起风浪。黑色的船在大海上肆意掠夺宝藏,尽管最终被塔吉玛的海军击败,但这未必意味着结束。"
// ],
// Fermon: [
// "“我可不想一直留在同一个地方,诗人注定漂泊。”",
// "来自洛维斯的吟游诗人,深受洛维斯乡村中的妇女和儿童们喜爱。经常在诗歌中描绘各地的风景,但实际上由于晕车严重,身为吟游诗人的他其实连洛维斯都没出过。费尔蒙偶尔会因此感到苦恼,不过只要唱一首歌就能回归无忧无虑的状态。"
// ],
// Fumiya: [
// "“我不想再变成其他人的样子顶替他们工作了!这不是人...不对,这不是妖怪该做的事情!”",
// "以他人记忆为食的妖怪,来自遥远的坊国。拥有随意改变自身外貌的能力,这为他四处行骗提供了非常大的帮助。虽然看着很好相处,但到了进食期就会不择手段去夺取或篡改他人的记忆,与他相处时千万不能掉以轻心。"
// ],
// Emic: [
// "“我知道我的美丽足以让阳光暗淡,但你无须为此感到畏惧。”",
// "用“自恋”也不足以形容的家伙。当人们对上他的眼睛时,一切似乎又变得理所当然。他伏在泉水边忧郁的身影,让人想起关于水仙花的传说故事。那种对美貌的极度自信和极致追求,在梦乐园里也许再找不到第二个这样的人了。"
// ],
// Flihine: [
// "“离我的收藏室远一点,别以为我不知道你在打什么主意。”",
// "在充满海洋与商业气息的塔吉玛,许多人拥有无与伦比的经商天赋。不过要论商务谈判能力,可能很少有人能胜过弗林海因。这个拥有一头柔软金发的男人,当他藏在镜片后狡黠的眼睛望向你时,请小心。"
// ],
// Shafie: [
// "“你问我会不会感到无聊?不,这样安安静静呆着挺好的。”",
// "拂晓骑士中最为年轻的一位,在学生时代是当之无愧的天才级学生,成绩、家世样样完美,是绝对令人羡慕的“别人家的孩子”。处世圆滑,讨人喜爱,因为太过优秀,未到规定年龄便破格成为了拂晓骑士。"
// ],
// Bethina: [
// "“只是站在这里看着你,就让人觉得神清气爽。你充满活力的目光就像是正午盛开的花朵,非常吸引我。”",
// "虽然在四骑士(德米安等人)中较为年长,不过据其他三人称,贝汀那大部分时候并没有起到年长者的作用……平日里总说自己有着更为远大的目标,但这“远大的目标”几乎每天都是不同的。在旁人看来是个极其难定义的自由之人。"
// ],
// Regis: [
// "“到我这个年纪,其实已经很难再有突破。但为了你,我愿意超越极限,成为你最坚固的盾牌。而且……不能总让年轻人出风头啊。”",
// "看似严肃的剑术教官,实际也有轻松活跃的一面。曾任拂晓骑士团高级指挥官,现在则更愿意退居二线担当教习,将机会让给年轻人。",
// "兴趣是棋牌类活动——某种意义上的老谋深算。很会做饭和照顾人,并且意外地很会说冷笑话。"
// ],
// Hisoga: [
// "“别担心,我身上没有藏蜘蛛。”",
// "喜爱制作标本,总是笑眯眯地说很恐怖的话。时密完全不喜欢忍者的工作,经常偷懒在自己房间里做标本。后来有一次利用标本技术成功从妖怪肚子里找出关键情报,自此组织便允许他在忍者城楼里拥有自己的标本制作室。"
// ],
// Isreall: [
// "“过多的介绍就不必了,之后会慢慢让你知道我的为人。”",
// "作为一名雷厉风行的执行者,伊斯雷尔其人不苟言笑,曾经是海上令人闻风丧胆的海军统领,但因为平日太过于严厉,性格也过于刻板强硬,所以没有朋友。不过据本人称,他并不在意。"
// ],
// Gluna: [
// "“那么,要开始讲课了,准备好记笔记了吗?”",
// "身份神秘的魔法师,游走在世界各地。因其性格原因,十分喜爱指导他人做事。有时甚至会亲自出马帮他人做事,直到做对为止。所以……如果有难以攻克的试题,可以试着拿给格伦亚看看。"
// ],
// Mellie: [
// "“这一期准备刊登的稿子写好了,给我提点建议吧。”",
// "在面包店工作的梅莉非常喜欢写作,做完面包后她会拿着本子和笔,坐在窗户边记下今天一天的写作想法。梅莉总是担心自己写出来的文字会不受人欢迎,但在发表了第一篇作品后,梅莉逐渐找回了自信。"
// ],
// Lillian: [
// "“嗯~努力的模样也必须比别人优雅十倍,这就是我的信条。”",
// "优雅有礼的大小姐,作为商人也能独当一面,如果因为外貌和年龄而看轻她,可是会吃大亏的。至于爱看浪漫小说?这是淑女的爱好,请不要大惊小怪。"
// ],
// Ophelia: [
// "“我是只属于你一人的骑士奥菲利亚。来,请放心将手交给我——无论何时,我都不会放开的。”",
// "作为洛维斯王国拂晓骑兵团成员之一,奥菲利亚的骑术、剑术等全都是顶尖水准。她为人坚强、正直,因其对待女性格外温柔,总是毫不吝啬对女性的夸赞,所以在女性中十分有人气。兴趣爱好广泛,似乎找不出她不擅长的事。"
// ],
// Rosana: [
// "“即便是我也有看不透你的时候,所以我才觉得你有趣。”",
// "一个不知从何处而来,也不知要去往何处的女巫。明明是温柔的絮语却让人不寒而栗,被她“喜欢”上的人会有怎样的结局……还是不要知道的太清楚比较好。"
// ],
// Filin: [
// "“帽子和人一样,需要精心维护才能保持美丽。”",
// "来自深红馆的女巫。模样看似是十几岁的女童,但实际年龄始终成谜,似乎连百年前的战争都亲眼见证过,总是以长辈的口吻说话。不喜欢外出,平日会安安静静地待在自己的房间里面,一边听着古典乐曲,一边制作各式各样的帽子。"
// ],
// Suzune: [
// "“有点无聊啊......要不要看我跳舞?我最近又新学了一支舞哦!”",
// "自称巫女的可疑家伙。真身是铃铛化出的妖怪,按照妖怪的年纪来算其实还很小。十分有元气,虽然缺乏人类社会的基本常识但自信满满!为了振兴祈愿寺在不断努力着,虽然方式或许并不可取,但这份积极进取的精神值得嘉许。"
// ],
// JinYingZi: [
// "“你身上的味道很好闻呢,是不是有用熏香之类的东西?”",
// "离开老家,云游在外的狐狸妖怪少女,总能分寸正好地拿捏着任性的程度。旅途中,金樱子经常被认作是兽族,有时候她会反驳,有时候她会默认,还有的时候她会主动声称自己是兽族——一切都要看她心情。"
// ]
// };
const rulesElement = () => {
return (
<div className="rulesBox">
<img className="rules" src={rules} alt="" />
<img className="close" src={closeBtn} alt="" onClick={closeRuleBtn} />
<a
className="link"
href="https://weibo.com/p/100808f765ceea1fb70a179203dc3232c71ab8/super_index"
target="_blank"
rel="noreferrer"
></a>
</div>
);
};
const closeRuleBtn = () => {
setRules(false);
};
const startBtn = () => {
setOver(true);
setStep(0);
setTimeout(() => {
setOver(false);
}, 1000);
};
const step1Btn = () => {
if (isOver) return;
setOver(true);
setStep(1);
setTimeout(() => {
setOver(false);
}, 1500);
};
const step2Btn = () => {
if (isOver) return;
setOver(true);
setStep(2);
setTimeout(() => {
setOver(false);
}, 1500);
};
// 选项按钮
const reqBtn = (element: any) => {
if (btnClick) return;
setBtn(true);
setBtnValue(element.value);
if (element.qa === "end") {
setStep(3);
setFigure(element.value);
return;
}
setTimeout(() => {
// 设置问题
setQa(element.qa);
// 设置对应答案选项
setReq(element.value);
setBtn(false);
setBtnValue("");
}, 1200);
};
const showRuleBtn = () => {
setRules(true);
};
const playAudio = (e: React.MouseEvent<HTMLDivElement>) => {
e.stopPropagation();
isPlaying ? audioRef.current?.pause() : audioRef.current?.play().catch(() => setIsPlaying(false));
// 改变isPlaying的状态
setIsPlaying(!isPlaying);
};
return (
<div className="home card">
{/* <img src={isPlaying ? music_on : music_off} alt="" className="playBtn" onClick={playAudio} /> */}
<div className={`startBox ${step !== -1 ? "fadeOut" : ""}`} style={{ backgroundImage: `url(${bg}` }} onClick={startBtn}>
<img src={isPlaying ? music_on : music_off} alt="" className="playBtn" onClick={playAudio} />
<img className="logo" src={pic_logo} alt="welcome" />
<img src={age} alt="" className="age" />
<img src={start} alt="" className="start" />
<p className="tips">使</p>
<img src={pic_linear} alt="" className="starlinear" />
</div>
{/* 开篇 */}
<div className={`beginText ${step !== 0 ? "fadeOut" : ""}`} style={{ backgroundImage: `url(${bg_2}` }}>
<img src={isPlaying ? music_on : music_off} alt="" className="playBtn" onClick={playAudio} />
<ul className={`textList ${step === 0 ? "fadein" : ""}`}>
<li className="textItem"></li>
<li className="textItem"></li>
<li className="textItem mt"></li>
<li className="textItem"></li>
</ul>
<div className={`step2 ${step === 0 ? "fadein" : ""}`} style={{ backgroundImage: `url(${btn_log}` }} onClick={step1Btn}>
</div>
</div>
{/* 开篇 */}
<div className={`startText ${step !== 1 ? "fadeOut" : ""}`} style={{ backgroundImage: `url(${bg_2}` }}>
<img src={isPlaying ? music_on : music_off} alt="" className="playBtn" onClick={playAudio} />
<ul className={`textList ${step === 1 ? "fadein" : ""}`}>
<li className="textItem">访</li>
<li className="textItem"></li>
<li className="textItem"></li>
<li className="textItem"></li>
<li className="textItem"></li>
</ul>
<div className={`step2 ${step === 1 ? "fadein" : ""}`} style={{ backgroundImage: `url(${btn_log}` }} onClick={step2Btn}>
</div>
</div>
{/* 问答 */}
<div className={`qa ${step !== 2 ? "fadeOut" : ""}`} style={{ backgroundImage: `url(${bg_qa}` }}>
<img src={isPlaying ? music_on : music_off} alt="" className="playBtn" onClick={playAudio} />
{/* 问题 */}
<div className={`req ${btnClick ? "active" : ""}`} style={{ backgroundImage: `url(${qa_line}` }}>
{qaList[qa]!.map((element: any) => {
return (
<p className={`${btnValue === element.value ? "fadein" : "fadeout"}`} key={element.value}>
{element}
</p>
);
})}
</div>
{/* 选项 */}
{reqList[req].map((element: reqItemProps) => {
return (
<div
className={`reqBtn ${btnClick && btnValue === element.value ? "active" : ""}`}
style={{ backgroundImage: `url(${res_bg}` }}
key={element.value}
onClick={() => reqBtn(element)}
>
<p> {element.title}</p>
</div>
);
})}
</div>
{/* 结果 */}
<div className={`resultBox ${step === 3 && !showRules ? "active" : null}`}>
<img src={isPlaying ? music_on : music_off} alt="" className="playBtn" onClick={playAudio} />
<img
className="figure"
src={step === 3 ? `https://cdn.star-linear.com/img/hd/nightingale/result/${figure}.png` : ""}
alt=""
/>
<div className="shareBtn" style={{ backgroundImage: `url(${shareBtn}` }} onClick={showRuleBtn}></div>
<div className="saveTips"></div>
<div className="pic_bottom" style={{ backgroundImage: `url(${pic_bottom}` }}>
<a className="toDream" href="http://dream.star-linear.com" target="_blank" rel="noopener noreferrer"></a>
</div>
{/* 这里是需要保存成图片的内容 */}
<img
className={`canvasImg ${step === 3 ? "active" : null}`}
src={step === 3 ? `https://cdn.star-linear.com/img/hd/nightingale/${figure}.png` : ""}
alt=""
/>
{/* 背景音乐 */}
</div>
<div id="audioBox">
<audio ref={audioRef} />
</div>
{showRules ? <OutMask child={rulesElement} /> : <></>}
</div>
);
};
export default Nightingale;

1
src/vite-env.d.ts vendored Normal file
View File

@ -0,0 +1 @@
/// <reference types="vite/client" />

32
tsconfig.json Normal file
View File

@ -0,0 +1,32 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"skipLibCheck": true,
"esModuleInterop": false,
"allowImportingTsExtensions": true,
"allowSyntheticDefaultImports": true,
/* Linting */
"strict": true,
/* Bundler mode */
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
"moduleResolution": "Node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
//
"baseUrl": "./",
// baseUrl
"paths": {
"@": ["src"],
"@/*": ["src/*"]
}
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "vite.config.ts"],
"exclude": ["node_modules", "dist", "**/*.js"]
}

40
vite.config.ts Normal file
View File

@ -0,0 +1,40 @@
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import eslintPlugin from "vite-plugin-eslint";
import { resolve } from "path";
import postCssPxToRem from "postcss-pxtorem";
// https://vitejs.dev/config/
export default defineConfig(() => {
return {
resolve: {
alias: {
"@": resolve(__dirname, "./src"),
"@assets": resolve(__dirname, "./src/assets"),
"@night": resolve(__dirname, "./src/assets/nightIngale")
}
},
plugins: [
react(), // * EsLint 报错信息显示在浏览器界面上
eslintPlugin()
],
css: {
postcss: {
plugins: [
postCssPxToRem({
rootValue: 16, // 1rem的大小
propList: ["*"] // 需要转换的属性,这里选择全部都进行转换
})
]
}
},
server: {
host: "0.0.0.0",
port: 5000
// cors: true, //默认启用并允许任何源
// https: false
// open: true, //在服务器启动时自动在浏览器中打开应用程序
// 反向代理配置注意rewrite写法
}
};
});