继续提交
24
mengyadriftbottle-frontend/.gitignore
vendored
Normal 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?
|
||||
29
mengyadriftbottle-frontend/README.md
Normal file
@@ -0,0 +1,29 @@
|
||||
## Mengya Drift Bottle – Frontend
|
||||
|
||||
React + Vite single-page application that consumes the Flask API exposed under `/api`.
|
||||
|
||||
### Available Scripts
|
||||
|
||||
```bash
|
||||
# start dev server with API proxy to http://localhost:5002
|
||||
npm run dev
|
||||
|
||||
# lint with ESLint
|
||||
npm run lint
|
||||
|
||||
# production build
|
||||
npm run build
|
||||
```
|
||||
|
||||
The dev server proxies every `/api/*` request to the backend, so start the Flask app before opening the React UI.
|
||||
|
||||
### Configuration
|
||||
|
||||
Set the following environment variables in a `.env` file if you need to override defaults:
|
||||
|
||||
```
|
||||
VITE_API_BASE_URL=http://localhost:5002/api
|
||||
VITE_ADMIN_URL=http://localhost:5002/admin/login
|
||||
```
|
||||
|
||||
In production you typically serve the static build (`dist/`) behind the same origin as the backend, allowing the default relative `/api` base to keep working.
|
||||
29
mengyadriftbottle-frontend/eslint.config.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import js from '@eslint/js'
|
||||
import globals from 'globals'
|
||||
import reactHooks from 'eslint-plugin-react-hooks'
|
||||
import reactRefresh from 'eslint-plugin-react-refresh'
|
||||
import { defineConfig, globalIgnores } from 'eslint/config'
|
||||
|
||||
export default defineConfig([
|
||||
globalIgnores(['dist']),
|
||||
{
|
||||
files: ['**/*.{js,jsx}'],
|
||||
extends: [
|
||||
js.configs.recommended,
|
||||
reactHooks.configs.flat.recommended,
|
||||
reactRefresh.configs.vite,
|
||||
],
|
||||
languageOptions: {
|
||||
ecmaVersion: 2020,
|
||||
globals: globals.browser,
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
ecmaFeatures: { jsx: true },
|
||||
sourceType: 'module',
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }],
|
||||
},
|
||||
},
|
||||
])
|
||||
17
mengyadriftbottle-frontend/index.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>萌芽漂流瓶(´,,•ω•,,)♡</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="让心意随海浪飘向远方,邂逅那个懂你的人——萌芽漂流瓶 React 前端"
|
||||
/>
|
||||
<link rel="icon" type="image/png" href="/logo.png" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.jsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
2891
mengyadriftbottle-frontend/package-lock.json
generated
Normal file
28
mengyadriftbottle-frontend/package.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "mengyadriftbottle-frontend",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"lint": "eslint .",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-free": "^6.7.2",
|
||||
"react": "^19.2.0",
|
||||
"react-dom": "^19.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.39.1",
|
||||
"@types/react": "^19.2.2",
|
||||
"@types/react-dom": "^19.2.2",
|
||||
"@vitejs/plugin-react": "^5.1.0",
|
||||
"eslint": "^9.39.1",
|
||||
"eslint-plugin-react-hooks": "^7.0.1",
|
||||
"eslint-plugin-react-refresh": "^0.4.24",
|
||||
"globals": "^16.5.0",
|
||||
"vite": "^7.2.2"
|
||||
}
|
||||
}
|
||||
BIN
mengyadriftbottle-frontend/public/background/image1.png
Normal file
|
After Width: | Height: | Size: 18 MiB |
BIN
mengyadriftbottle-frontend/public/background/image10.png
Normal file
|
After Width: | Height: | Size: 4.3 MiB |
BIN
mengyadriftbottle-frontend/public/background/image11.png
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
BIN
mengyadriftbottle-frontend/public/background/image12.png
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
mengyadriftbottle-frontend/public/background/image13.png
Normal file
|
After Width: | Height: | Size: 480 KiB |
BIN
mengyadriftbottle-frontend/public/background/image14.png
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
BIN
mengyadriftbottle-frontend/public/background/image15.png
Normal file
|
After Width: | Height: | Size: 920 KiB |
BIN
mengyadriftbottle-frontend/public/background/image16.png
Normal file
|
After Width: | Height: | Size: 3.1 MiB |
BIN
mengyadriftbottle-frontend/public/background/image17.png
Normal file
|
After Width: | Height: | Size: 3.6 MiB |
BIN
mengyadriftbottle-frontend/public/background/image18.png
Normal file
|
After Width: | Height: | Size: 2.4 MiB |
BIN
mengyadriftbottle-frontend/public/background/image19.png
Normal file
|
After Width: | Height: | Size: 265 KiB |
BIN
mengyadriftbottle-frontend/public/background/image2.png
Normal file
|
After Width: | Height: | Size: 9.0 MiB |
BIN
mengyadriftbottle-frontend/public/background/image20.png
Normal file
|
After Width: | Height: | Size: 4.2 MiB |
BIN
mengyadriftbottle-frontend/public/background/image21.png
Normal file
|
After Width: | Height: | Size: 8.4 MiB |
BIN
mengyadriftbottle-frontend/public/background/image22.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
mengyadriftbottle-frontend/public/background/image23.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
mengyadriftbottle-frontend/public/background/image24.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
BIN
mengyadriftbottle-frontend/public/background/image25.png
Normal file
|
After Width: | Height: | Size: 5.5 MiB |
BIN
mengyadriftbottle-frontend/public/background/image26.png
Normal file
|
After Width: | Height: | Size: 5.7 MiB |
BIN
mengyadriftbottle-frontend/public/background/image27.png
Normal file
|
After Width: | Height: | Size: 2.5 MiB |
BIN
mengyadriftbottle-frontend/public/background/image28.png
Normal file
|
After Width: | Height: | Size: 5.2 MiB |
BIN
mengyadriftbottle-frontend/public/background/image29.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
BIN
mengyadriftbottle-frontend/public/background/image3.png
Normal file
|
After Width: | Height: | Size: 2.4 MiB |
BIN
mengyadriftbottle-frontend/public/background/image4.png
Normal file
|
After Width: | Height: | Size: 5.1 MiB |
BIN
mengyadriftbottle-frontend/public/background/image5.png
Normal file
|
After Width: | Height: | Size: 4.8 MiB |
BIN
mengyadriftbottle-frontend/public/background/image6.png
Normal file
|
After Width: | Height: | Size: 9.6 MiB |
BIN
mengyadriftbottle-frontend/public/background/image7.png
Normal file
|
After Width: | Height: | Size: 2.9 MiB |
BIN
mengyadriftbottle-frontend/public/background/image8.png
Normal file
|
After Width: | Height: | Size: 3.4 MiB |
BIN
mengyadriftbottle-frontend/public/background/image9.png
Normal file
|
After Width: | Height: | Size: 3.0 MiB |
560
mengyadriftbottle-frontend/public/legacy-style.css
Normal file
@@ -0,0 +1,560 @@
|
||||
body {
|
||||
font-family: 'Segoe UI', Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||
background: linear-gradient(135deg, #f5e8f0 0%, #f3e5fc 100%);
|
||||
color: #5e5166;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
min-height: 100vh;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.container {
|
||||
background-color: rgba(255, 255, 255, 0.9);
|
||||
padding: 25px 30px;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 8px 32px rgba(155, 89, 182, 0.15);
|
||||
width: 90%;
|
||||
max-width: 600px;
|
||||
text-align: center;
|
||||
margin: 40px auto;
|
||||
backdrop-filter: blur(8px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: '楷体', 'STKaiti', '华文楷体', KaiTi, '宋体', SimSun, sans-serif;
|
||||
color: #d873a9;
|
||||
margin-bottom: 10px;
|
||||
font-size: 2.4em;
|
||||
text-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: #b07cc6;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
font-weight: 600;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
h2 i {
|
||||
margin-right: 8px;
|
||||
color: #c27ba0;
|
||||
}
|
||||
|
||||
.action-section {
|
||||
margin-bottom: 30px;
|
||||
padding: 25px 20px;
|
||||
background-color: #fff;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.throw-section {
|
||||
border-top: 4px solid #ffb6c1;
|
||||
}
|
||||
|
||||
.pickup-section {
|
||||
border-top: 4px solid #c5a3ff;
|
||||
}
|
||||
|
||||
.action-section::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='20' height='20' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23f9e0f0' fill-opacity='0.2' fill-rule='evenodd'%3E%3Ccircle cx='3' cy='3' r='3'/%3E%3Ccircle cx='13' cy='13' r='3'/%3E%3C/g%3E%3C/svg%3E");
|
||||
opacity: 0.5;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
color: #7d5ba6;
|
||||
font-weight: 600;
|
||||
text-align: left;
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
textarea,
|
||||
select {
|
||||
width: 100%;
|
||||
padding: 12px 15px;
|
||||
margin-bottom: 18px;
|
||||
border: 1px solid #e1d1f0;
|
||||
border-radius: 8px;
|
||||
background-color: #fdfaff;
|
||||
color: #5e4b6b;
|
||||
font-size: 0.95em;
|
||||
box-sizing: border-box;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
input[type="text"]:focus,
|
||||
textarea:focus,
|
||||
select:focus {
|
||||
outline: none;
|
||||
border-color: #d291bc;
|
||||
box-shadow: 0 0 0 3px rgba(219, 112, 194, 0.1);
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
min-height: 80px;
|
||||
}
|
||||
|
||||
::placeholder {
|
||||
color: #cbb8db;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: #aa67e5;
|
||||
color: white;
|
||||
padding: 12px 25px;
|
||||
border: none;
|
||||
border-radius: 30px;
|
||||
cursor: pointer;
|
||||
font-size: 1.05em;
|
||||
font-weight: 600;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 4px 8px rgba(170, 103, 229, 0.3);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.btn-throw {
|
||||
background: linear-gradient(135deg, #ff8fbc 0%, #eb6dab 100%);
|
||||
}
|
||||
|
||||
.btn-pickup {
|
||||
background: linear-gradient(135deg, #a47aed 0%, #876bd3 100%);
|
||||
}
|
||||
|
||||
button i {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 15px rgba(170, 103, 229, 0.4);
|
||||
}
|
||||
|
||||
button:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
#throw-status,
|
||||
#pickup-status {
|
||||
margin-top: 15px;
|
||||
font-style: italic;
|
||||
color: #b56ab0;
|
||||
min-height: 1.5em;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
#bottle-display {
|
||||
margin-top: 25px;
|
||||
padding: 0;
|
||||
background-color: #fff;
|
||||
border-radius: 12px;
|
||||
text-align: left;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 5px 15px rgba(138, 80, 201, 0.1);
|
||||
transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||
border: 1px solid #f1e1fb;
|
||||
}
|
||||
|
||||
.bottle-header {
|
||||
background: linear-gradient(135deg, #f9ddff 0%, #e9cdff 100%);
|
||||
padding: 15px 20px;
|
||||
position: relative;
|
||||
border-bottom: 1px solid #f1e1ff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#bottle-avatar {
|
||||
max-width: 60px;
|
||||
border-radius: 50%;
|
||||
border: 3px solid white;
|
||||
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.1);
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.gender-badge {
|
||||
display: inline-block;
|
||||
padding: 2px 8px;
|
||||
border-radius: 12px;
|
||||
font-size: 0.8em;
|
||||
margin-left: 8px;
|
||||
background-color: #f0e6ff;
|
||||
color: #7155a8;
|
||||
}
|
||||
|
||||
#bottle-display h3 {
|
||||
color: #8156c5;
|
||||
margin: 0;
|
||||
font-size: 1.2em;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.message-content {
|
||||
padding: 20px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
#bottle-display p {
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
margin: 0;
|
||||
color: #51456a;
|
||||
line-height: 1.6;
|
||||
font-size: 1.05em;
|
||||
}
|
||||
|
||||
.bottle-footer {
|
||||
padding: 12px 20px;
|
||||
background-color: #fbf8ff;
|
||||
border-top: 1px solid #f1e8ff;
|
||||
}
|
||||
|
||||
.bottle-info small {
|
||||
display: inline-block;
|
||||
margin-right: 15px;
|
||||
color: #9d8aaf;
|
||||
font-size: 0.85em;
|
||||
}
|
||||
|
||||
.bottle-info i {
|
||||
margin-right: 5px;
|
||||
color: #b67fdb;
|
||||
}
|
||||
|
||||
.bottle-reactions {
|
||||
margin-top: 15px;
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.reaction-btn {
|
||||
background: #ffffff;
|
||||
border: 1px solid #e9d8ff;
|
||||
border-radius: 20px;
|
||||
padding: 6px 15px;
|
||||
font-size: 0.9em;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.reaction-btn i {
|
||||
margin-right: 6px;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.like-btn {
|
||||
color: #5aaa9d;
|
||||
}
|
||||
|
||||
.like-btn:hover:not(:disabled) {
|
||||
background-color: #e5fff8;
|
||||
border-color: #93e7d7;
|
||||
}
|
||||
|
||||
.dislike-btn {
|
||||
color: #d76b8b;
|
||||
}
|
||||
|
||||
.dislike-btn:hover:not(:disabled) {
|
||||
background-color: #fff1f5;
|
||||
border-color: #ffb8c9;
|
||||
}
|
||||
|
||||
.reaction-btn:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.cooldown-timer {
|
||||
margin-top: 15px;
|
||||
background-color: #f8f0ff;
|
||||
padding: 10px 15px;
|
||||
border-radius: 25px;
|
||||
color: #aa67e5;
|
||||
font-size: 0.95em;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
border: 1px dashed #d7c3f0;
|
||||
animation: pulse-soft 1.5s infinite;
|
||||
}
|
||||
|
||||
.cooldown-timer i {
|
||||
margin-right: 8px;
|
||||
color: #d873a9;
|
||||
animation: spin 2s linear infinite;
|
||||
}
|
||||
|
||||
.char-count {
|
||||
font-size: 0.8em;
|
||||
color: #aa67e5;
|
||||
margin-left: 10px;
|
||||
background-color: #f8f4ff;
|
||||
padding: 3px 8px;
|
||||
border-radius: 10px;
|
||||
font-weight: normal;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.char-count-limit {
|
||||
background-color: #ffebf3;
|
||||
color: #e65c8f;
|
||||
animation: pulse 0.5s ease;
|
||||
}
|
||||
|
||||
@keyframes pulse-soft {
|
||||
0% {
|
||||
box-shadow: 0 0 0 0 rgba(170, 103, 229, 0.2);
|
||||
}
|
||||
70% {
|
||||
box-shadow: 0 0 0 8px rgba(170, 103, 229, 0);
|
||||
}
|
||||
100% {
|
||||
box-shadow: 0 0 0 0 rgba(170, 103, 229, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.appear {
|
||||
animation: appear 0.5s ease-out;
|
||||
}
|
||||
|
||||
@keyframes appear {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
footer {
|
||||
margin-top: 40px;
|
||||
color: #a07bb8;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
footer i {
|
||||
color: #ff85a2;
|
||||
}
|
||||
|
||||
.admin-link {
|
||||
margin-top: 10px;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
.admin-link a {
|
||||
color: #a07bb8;
|
||||
text-decoration: none;
|
||||
opacity: 0.7;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.admin-link a:hover {
|
||||
opacity: 1;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
body {
|
||||
padding: 10px;
|
||||
}
|
||||
.container {
|
||||
padding: 20px 15px;
|
||||
width: 95%;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
}
|
||||
.wave-container {
|
||||
height: 120px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
h1 {
|
||||
font-size: 1.7em;
|
||||
}
|
||||
h2 {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
.bottle-info small {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
button {
|
||||
padding: 10px 20px;
|
||||
font-size: 0.95em;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/* 波浪动画 */
|
||||
.wave-container {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
overflow: hidden;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.wave {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 200%;
|
||||
height: 100%;
|
||||
background-repeat: repeat-x;
|
||||
background-position: 0 bottom;
|
||||
transform-origin: center bottom;
|
||||
}
|
||||
|
||||
.wave1 {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 800 88.7'%3E%3Cpath d='M800 56.9c-155.5 0-204.9-50-405.5-49.9-200 0-250 49.9-394.5 49.9v31.8h800v-.2-31.6z' fill='%23f8d8eb' fill-opacity='0.4'/%3E%3C/svg%3E");
|
||||
background-size: 50% 100px;
|
||||
animation: wave 25s -3s linear infinite;
|
||||
opacity: 0.6;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.wave2 {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 800 88.7'%3E%3Cpath d='M800 56.9c-155.5 0-204.9-50-405.5-49.9-200 0-250 49.9-394.5 49.9v31.8h800v-.2-31.6z' fill='%23e6c0e9' fill-opacity='0.3'/%3E%3C/svg%3E");
|
||||
background-size: 50% 120px;
|
||||
animation: wave 20s linear reverse infinite;
|
||||
opacity: 0.4;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
@keyframes wave {
|
||||
0% {transform: translateX(0) translateZ(0) scaleY(1)}
|
||||
50% {transform: translateX(-25%) translateZ(0) scaleY(0.8)}
|
||||
100% {transform: translateX(-50%) translateZ(0) scaleY(1)}
|
||||
}
|
||||
|
||||
/* 标题和介绍文字 */
|
||||
.heart-icon {
|
||||
color: #ff6b9c;
|
||||
margin: 0 8px;
|
||||
animation: pulse 1.5s infinite;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% {transform: scale(1);}
|
||||
50% {transform: scale(1.2);}
|
||||
100% {transform: scale(1);}
|
||||
}
|
||||
|
||||
.tagline {
|
||||
color: #9d7bb0;
|
||||
margin-bottom: 25px;
|
||||
font-style: italic;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.motto-container {
|
||||
background-color: #fff;
|
||||
border-radius: 12px;
|
||||
padding: 18px 20px;
|
||||
margin-bottom: 25px;
|
||||
border-left: 5px solid #aa67e5;
|
||||
box-shadow: 0 3px 15px rgba(160, 120, 200, 0.12);
|
||||
text-align: center;
|
||||
position: relative;
|
||||
font-family: '楷体', 'STKaiti', '华文楷体', KaiTi, '宋体', SimSun, sans-serif;
|
||||
}
|
||||
|
||||
.motto-container i {
|
||||
color: #d291bc;
|
||||
font-size: 1rem;
|
||||
opacity: 0.7;
|
||||
margin: 0 8px;
|
||||
}
|
||||
|
||||
.motto-container i.fa-quote-left {
|
||||
position: relative;
|
||||
top: -5px;
|
||||
left: -3px;
|
||||
}
|
||||
|
||||
.motto-container i.fa-quote-right {
|
||||
position: relative;
|
||||
bottom: -5px;
|
||||
right: -3px;
|
||||
}
|
||||
|
||||
#random-motto {
|
||||
font-size: 1.3em;
|
||||
color: #7d5ba6;
|
||||
font-weight: bold;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.stats-container {
|
||||
background-color: #f8e4ff;
|
||||
border-radius: 12px;
|
||||
padding: 12px 15px;
|
||||
margin-bottom: 25px;
|
||||
border: 1px dashed #d7b5f3;
|
||||
box-shadow: 0 3px 10px rgba(160, 120, 200, 0.1);
|
||||
}
|
||||
|
||||
.stats-container p {
|
||||
margin: 0;
|
||||
color: #8a5fad;
|
||||
font-weight: 600;
|
||||
font-size: 1.05em;
|
||||
}
|
||||
|
||||
.stats-container i {
|
||||
margin-right: 8px;
|
||||
color: #d873a9;
|
||||
}
|
||||
|
||||
#total-bottles {
|
||||
display: inline-block;
|
||||
background-color: #fff;
|
||||
padding: 3px 10px;
|
||||
border-radius: 20px;
|
||||
margin: 0 5px;
|
||||
color: #aa67e5;
|
||||
font-weight: bold;
|
||||
min-width: 30px;
|
||||
}
|
||||
BIN
mengyadriftbottle-frontend/public/logo.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
BIN
mengyadriftbottle-frontend/public/logo2.png
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
BIN
mengyadriftbottle-frontend/public/logo3.png
Normal file
|
After Width: | Height: | Size: 2.2 MiB |
1
mengyadriftbottle-frontend/public/vite.svg
Normal 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 |
507
mengyadriftbottle-frontend/src/App.css
Normal file
@@ -0,0 +1,507 @@
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--app-background-image: url('/background/image1.png');
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
background-color: #f7eaf3;
|
||||
background-image: var(--app-background-image);
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-attachment: fixed;
|
||||
color: #5e5166;
|
||||
margin: 0;
|
||||
min-height: 100vh;
|
||||
position: relative;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.background-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(255, 214, 233, 0.35);
|
||||
backdrop-filter: blur(5px);
|
||||
-webkit-backdrop-filter: blur(5px);
|
||||
pointer-events: none;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.page-wrapper {
|
||||
min-height: 100vh;
|
||||
padding: 30px 10px 60px;
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.container {
|
||||
background-color: rgba(255, 255, 255, 0.7);
|
||||
padding: 25px 30px;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 8px 32px rgba(155, 89, 182, 0.15);
|
||||
width: 90%;
|
||||
max-width: 650px;
|
||||
text-align: center;
|
||||
margin: 0 auto;
|
||||
backdrop-filter: blur(8px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: '楷体', 'STKaiti', '华文楷体', KaiTi, '宋体', SimSun, sans-serif;
|
||||
color: #d873a9;
|
||||
margin-bottom: 10px;
|
||||
font-size: 2.4em;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: #b07cc6;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
font-weight: 600;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
h2 i {
|
||||
margin-right: 8px;
|
||||
color: #c27ba0;
|
||||
}
|
||||
|
||||
.tagline {
|
||||
color: #9d7bb0;
|
||||
margin-bottom: 25px;
|
||||
font-style: italic;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.motto-container {
|
||||
background-color: #fff;
|
||||
border-radius: 12px;
|
||||
padding: 18px 20px;
|
||||
margin-bottom: 25px;
|
||||
border-left: 5px solid #aa67e5;
|
||||
box-shadow: 0 3px 15px rgba(160, 120, 200, 0.12);
|
||||
text-align: center;
|
||||
position: relative;
|
||||
font-family: '楷体', 'STKaiti', '华文楷体', KaiTi, '宋体', SimSun, sans-serif;
|
||||
}
|
||||
|
||||
.motto-container i {
|
||||
color: #d291bc;
|
||||
font-size: 1rem;
|
||||
opacity: 0.7;
|
||||
margin: 0 8px;
|
||||
}
|
||||
|
||||
#random-motto {
|
||||
font-size: 1.3em;
|
||||
color: #7d5ba6;
|
||||
font-weight: bold;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.refresh-motto {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
right: 12px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: #aa67e5;
|
||||
cursor: pointer;
|
||||
font-size: 0.85em;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.refresh-motto:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.stats-container {
|
||||
background-color: #f8e4ff;
|
||||
border-radius: 12px;
|
||||
padding: 12px 15px;
|
||||
margin-bottom: 25px;
|
||||
border: 1px dashed #d7b5f3;
|
||||
box-shadow: 0 3px 10px rgba(160, 120, 200, 0.1);
|
||||
}
|
||||
|
||||
.stats-container p {
|
||||
margin: 0;
|
||||
color: #8a5fad;
|
||||
font-weight: 600;
|
||||
font-size: 1.05em;
|
||||
}
|
||||
|
||||
.stats-container i {
|
||||
margin-right: 8px;
|
||||
color: #d873a9;
|
||||
}
|
||||
|
||||
#total-bottles {
|
||||
display: inline-block;
|
||||
background-color: #fff;
|
||||
padding: 3px 10px;
|
||||
border-radius: 20px;
|
||||
margin: 0 5px;
|
||||
color: #aa67e5;
|
||||
font-weight: bold;
|
||||
min-width: 30px;
|
||||
}
|
||||
|
||||
.action-section {
|
||||
margin-bottom: 30px;
|
||||
padding: 25px 20px;
|
||||
background-color: #fff;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.throw-section {
|
||||
border-top: 4px solid #ffb6c1;
|
||||
}
|
||||
|
||||
.pickup-section {
|
||||
border-top: 4px solid #c5a3ff;
|
||||
}
|
||||
|
||||
.action-section::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='20' height='20' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23f9e0f0' fill-opacity='0.2' fill-rule='evenodd'%3E%3Ccircle cx='3' cy='3' r='3'/%3E%3Ccircle cx='13' cy='13' r='3'/%3E%3C/g%3E%3C/svg%3E");
|
||||
opacity: 0.5;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
color: #7d5ba6;
|
||||
font-weight: 600;
|
||||
text-align: left;
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
input[type='text'],
|
||||
textarea,
|
||||
select {
|
||||
width: 100%;
|
||||
padding: 12px 15px;
|
||||
margin-bottom: 18px;
|
||||
border: 1px solid #e1d1f0;
|
||||
border-radius: 8px;
|
||||
background-color: #fdfaff;
|
||||
color: #5e4b6b;
|
||||
font-size: 0.95em;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
input[type='text']:focus,
|
||||
textarea:focus,
|
||||
select:focus {
|
||||
outline: none;
|
||||
border-color: #d291bc;
|
||||
box-shadow: 0 0 0 3px rgba(219, 112, 194, 0.1);
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
min-height: 90px;
|
||||
}
|
||||
|
||||
::placeholder {
|
||||
color: #cbb8db;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: #aa67e5;
|
||||
color: #fff;
|
||||
padding: 12px 25px;
|
||||
border: none;
|
||||
border-radius: 30px;
|
||||
cursor: pointer;
|
||||
font-size: 1.05em;
|
||||
font-weight: 600;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 4px 8px rgba(170, 103, 229, 0.3);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.btn-throw {
|
||||
background: linear-gradient(135deg, #ff8fbc 0%, #eb6dab 100%);
|
||||
}
|
||||
|
||||
.btn-pickup {
|
||||
background: linear-gradient(135deg, #a47aed 0%, #876bd3 100%);
|
||||
}
|
||||
|
||||
button:hover:not(:disabled) {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 15px rgba(170, 103, 229, 0.4);
|
||||
}
|
||||
|
||||
button:disabled {
|
||||
opacity: 0.7;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
#throw-status,
|
||||
#pickup-status {
|
||||
margin-top: 15px;
|
||||
font-style: italic;
|
||||
color: #b56ab0;
|
||||
min-height: 1.5em;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
#bottle-display {
|
||||
margin-top: 25px;
|
||||
background-color: #fff;
|
||||
border-radius: 12px;
|
||||
text-align: left;
|
||||
box-shadow: 0 5px 15px rgba(138, 80, 201, 0.1);
|
||||
border: 1px solid #f1e1fb;
|
||||
}
|
||||
|
||||
.bottle-header {
|
||||
background: linear-gradient(135deg, #f9ddff 0%, #e9cdff 100%);
|
||||
padding: 15px 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
#bottle-avatar {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 50%;
|
||||
border: 3px solid #fff;
|
||||
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.gender-badge {
|
||||
display: inline-block;
|
||||
padding: 2px 8px;
|
||||
border-radius: 12px;
|
||||
font-size: 0.8em;
|
||||
margin-left: 8px;
|
||||
background-color: #f0e6ff;
|
||||
color: #7155a8;
|
||||
}
|
||||
|
||||
.message-content {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
#bottle-message {
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
margin: 0;
|
||||
color: #51456a;
|
||||
line-height: 1.6;
|
||||
font-size: 1.05em;
|
||||
}
|
||||
|
||||
.bottle-footer {
|
||||
padding: 12px 20px;
|
||||
background-color: #fbf8ff;
|
||||
border-top: 1px solid #f1e8ff;
|
||||
}
|
||||
|
||||
.bottle-info small {
|
||||
display: inline-block;
|
||||
margin-right: 15px;
|
||||
color: #9d8aaf;
|
||||
font-size: 0.85em;
|
||||
}
|
||||
|
||||
.bottle-reactions {
|
||||
margin-top: 15px;
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.reaction-btn {
|
||||
background: #ffffff;
|
||||
border: 1px solid #e9d8ff;
|
||||
border-radius: 20px;
|
||||
padding: 6px 15px;
|
||||
font-size: 0.9em;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.like-btn {
|
||||
color: #5aaa9d;
|
||||
}
|
||||
|
||||
.dislike-btn {
|
||||
color: #d76b8b;
|
||||
}
|
||||
|
||||
.reaction-btn:hover:not(:disabled) {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.cooldown-timer {
|
||||
margin-top: 15px;
|
||||
background-color: #f8f0ff;
|
||||
padding: 10px 15px;
|
||||
border-radius: 25px;
|
||||
color: #aa67e5;
|
||||
font-size: 0.95em;
|
||||
display: inline-flex;
|
||||
gap: 6px;
|
||||
align-items: center;
|
||||
border: 1px dashed #d7c3f0;
|
||||
animation: pulse-soft 1.5s infinite;
|
||||
}
|
||||
|
||||
.char-count {
|
||||
font-size: 0.8em;
|
||||
color: #aa67e5;
|
||||
margin-left: 10px;
|
||||
background-color: #f8f4ff;
|
||||
padding: 3px 8px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.char-count-limit {
|
||||
background-color: #ffebf3;
|
||||
color: #e65c8f;
|
||||
animation: pulse 0.5s ease;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse-soft {
|
||||
0% {
|
||||
box-shadow: 0 0 0 0 rgba(170, 103, 229, 0.2);
|
||||
}
|
||||
70% {
|
||||
box-shadow: 0 0 0 8px rgba(170, 103, 229, 0);
|
||||
}
|
||||
100% {
|
||||
box-shadow: 0 0 0 0 rgba(170, 103, 229, 0);
|
||||
}
|
||||
}
|
||||
|
||||
.appear {
|
||||
animation: appear 0.5s ease-out;
|
||||
}
|
||||
|
||||
@keyframes appear {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.heart-icon {
|
||||
color: #ff6b9c;
|
||||
margin: 0 8px;
|
||||
animation: heart 1.5s infinite;
|
||||
}
|
||||
|
||||
@keyframes heart {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.2);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
footer {
|
||||
margin-top: 40px;
|
||||
color: #a07bb8;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
footer i {
|
||||
color: #ff85a2;
|
||||
}
|
||||
|
||||
.admin-link {
|
||||
margin-top: 10px;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
.admin-link a {
|
||||
color: #a07bb8;
|
||||
text-decoration: none;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.admin-link a:hover {
|
||||
opacity: 1;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.container {
|
||||
width: 95%;
|
||||
padding: 20px 18px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
body {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 98%;
|
||||
padding: 18px 14px;
|
||||
}
|
||||
|
||||
button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.bottle-info small {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
}
|
||||
446
mengyadriftbottle-frontend/src/App.jsx
Normal file
@@ -0,0 +1,446 @@
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import '@fortawesome/fontawesome-free/css/all.min.css'
|
||||
import './App.css'
|
||||
|
||||
const API_BASE_URL = (import.meta.env.VITE_API_BASE_URL || '/api').replace(/\/$/, '')
|
||||
const ADMIN_URL = import.meta.env.VITE_ADMIN_URL || 'http://localhost:5002/admin/login'
|
||||
const DEFAULT_FORM = Object.freeze({
|
||||
name: '',
|
||||
message: '',
|
||||
gender: '保密',
|
||||
qq: '',
|
||||
})
|
||||
|
||||
const BACKGROUND_IMAGES = Array.from({ length: 29 }, (_, index) => `/background/image${index + 1}.png`)
|
||||
|
||||
const formatCount = (value) => {
|
||||
const num = typeof value === 'number' ? value : Number(value || 0)
|
||||
return Number.isNaN(num) ? 0 : num
|
||||
}
|
||||
|
||||
function App() {
|
||||
const [formData, setFormData] = useState({ ...DEFAULT_FORM })
|
||||
const [limits, setLimits] = useState({ name: 7, message: 100 })
|
||||
const [stats, setStats] = useState({ total_bottles: 0 })
|
||||
const [motto, setMotto] = useState('载入中...')
|
||||
const [throwStatus, setThrowStatus] = useState('')
|
||||
const [pickupStatus, setPickupStatus] = useState('')
|
||||
const [currentBottle, setCurrentBottle] = useState(null)
|
||||
const [cooldowns, setCooldowns] = useState({ throw: 0, pickup: 0 })
|
||||
const [loadingAction, setLoadingAction] = useState({ throw: false, pickup: false })
|
||||
const [reactionDisabled, setReactionDisabled] = useState(false)
|
||||
const isThrowing = loadingAction.throw
|
||||
const isPicking = loadingAction.pickup
|
||||
|
||||
const randomBackground = useMemo(() => {
|
||||
if (!BACKGROUND_IMAGES.length) {
|
||||
return ''
|
||||
}
|
||||
const index = Math.floor(Math.random() * BACKGROUND_IMAGES.length)
|
||||
return BACKGROUND_IMAGES[index]
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (randomBackground) {
|
||||
document.documentElement.style.setProperty('--app-background-image', `url(${randomBackground})`)
|
||||
}
|
||||
}, [randomBackground])
|
||||
|
||||
const startCooldown = useCallback((type, seconds = 5) => {
|
||||
const duration = Math.max(1, Math.ceil(seconds))
|
||||
setCooldowns((prev) => ({ ...prev, [type]: duration }))
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setInterval(() => {
|
||||
setCooldowns((prev) => {
|
||||
const next = {
|
||||
throw: prev.throw > 0 ? prev.throw - 1 : 0,
|
||||
pickup: prev.pickup > 0 ? prev.pickup - 1 : 0,
|
||||
}
|
||||
if (next.throw === prev.throw && next.pickup === prev.pickup) {
|
||||
return prev
|
||||
}
|
||||
return next
|
||||
})
|
||||
}, 1000)
|
||||
return () => clearInterval(timer)
|
||||
}, [])
|
||||
|
||||
const fetchConfig = useCallback(async () => {
|
||||
try {
|
||||
const response = await fetch(`${API_BASE_URL}/config`)
|
||||
const data = await response.json()
|
||||
if (data.success && data.config) {
|
||||
setLimits({
|
||||
name: data.config.name_limit ?? 7,
|
||||
message: data.config.message_limit ?? 100,
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch config', error)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const fetchStats = useCallback(async () => {
|
||||
try {
|
||||
const response = await fetch(`${API_BASE_URL}/stats`)
|
||||
const data = await response.json()
|
||||
if (data.success && data.stats) {
|
||||
setStats(data.stats)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch stats', error)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const fetchMotto = useCallback(async () => {
|
||||
try {
|
||||
const response = await fetch(`${API_BASE_URL}/motto`)
|
||||
const data = await response.json()
|
||||
if (data.success) {
|
||||
setMotto(data.motto)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch motto', error)
|
||||
setMotto('良言一句三冬暖,恶语伤人六月寒')
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
fetchConfig()
|
||||
fetchStats()
|
||||
fetchMotto()
|
||||
}, [fetchConfig, fetchStats, fetchMotto])
|
||||
|
||||
const handleInputChange = useCallback((event) => {
|
||||
const { name, value } = event.target
|
||||
if (name === 'qq' && value && /[^0-9]/.test(value)) {
|
||||
return
|
||||
}
|
||||
setFormData((prev) => ({ ...prev, [name]: value }))
|
||||
}, [])
|
||||
|
||||
const resetForm = useCallback(() => {
|
||||
setFormData({ ...DEFAULT_FORM })
|
||||
}, [])
|
||||
|
||||
const handleThrowSubmit = useCallback(
|
||||
async (event) => {
|
||||
event.preventDefault()
|
||||
if (cooldowns.throw > 0 || isThrowing) {
|
||||
return
|
||||
}
|
||||
|
||||
setLoadingAction((prev) => ({ ...prev, throw: true }))
|
||||
setThrowStatus('正在扔瓶子...')
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_BASE_URL}/throw`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
name: formData.name,
|
||||
message: formData.message,
|
||||
gender: formData.gender,
|
||||
qq: formData.qq,
|
||||
}),
|
||||
})
|
||||
|
||||
const data = await response.json()
|
||||
if (response.ok && data.success) {
|
||||
setThrowStatus('瓶子已成功扔出!祝你好运~')
|
||||
resetForm()
|
||||
fetchStats()
|
||||
startCooldown('throw', 5)
|
||||
} else {
|
||||
const waitTime = data.wait_time ?? 0
|
||||
setThrowStatus(`出错了: ${data.error || data.message || '未知错误'}`)
|
||||
if (waitTime) {
|
||||
startCooldown('throw', waitTime)
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Throw request failed', error)
|
||||
setThrowStatus('请求失败,请检查网络连接。')
|
||||
} finally {
|
||||
setLoadingAction((prev) => ({ ...prev, throw: false }))
|
||||
}
|
||||
},
|
||||
[cooldowns.throw, isThrowing, formData, fetchStats, resetForm, startCooldown],
|
||||
)
|
||||
|
||||
const handlePickup = useCallback(async () => {
|
||||
if (cooldowns.pickup > 0 || isPicking) {
|
||||
return
|
||||
}
|
||||
setLoadingAction((prev) => ({ ...prev, pickup: true }))
|
||||
setPickupStatus('正在打捞瓶子...')
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_BASE_URL}/pickup`)
|
||||
const data = await response.json()
|
||||
if (response.ok && data.success && data.bottle) {
|
||||
setCurrentBottle(data.bottle)
|
||||
setReactionDisabled(false)
|
||||
setPickupStatus('捡到了一个瓶子!缘分来了~')
|
||||
startCooldown('pickup', 5)
|
||||
} else {
|
||||
setCurrentBottle(null)
|
||||
const waitTime = data.wait_time ?? 0
|
||||
setPickupStatus(data.message || data.error || '海里没有瓶子了,或者出错了。')
|
||||
if (waitTime) {
|
||||
startCooldown('pickup', waitTime)
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Pickup request failed', error)
|
||||
setPickupStatus('请求失败,请检查网络连接。')
|
||||
setCurrentBottle(null)
|
||||
} finally {
|
||||
setLoadingAction((prev) => ({ ...prev, pickup: false }))
|
||||
}
|
||||
}, [cooldowns.pickup, isPicking, startCooldown])
|
||||
|
||||
const handleReaction = useCallback(
|
||||
async (reaction) => {
|
||||
if (!currentBottle) {
|
||||
return
|
||||
}
|
||||
setReactionDisabled(true)
|
||||
try {
|
||||
const response = await fetch(`${API_BASE_URL}/react`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ bottle_id: currentBottle.id, reaction }),
|
||||
})
|
||||
const data = await response.json()
|
||||
if (response.ok && data.success) {
|
||||
setCurrentBottle((prev) =>
|
||||
prev
|
||||
? {
|
||||
...prev,
|
||||
likes: reaction === 'like' ? formatCount(prev.likes) + 1 : prev.likes,
|
||||
dislikes: reaction === 'dislike' ? formatCount(prev.dislikes) + 1 : prev.dislikes,
|
||||
}
|
||||
: prev,
|
||||
)
|
||||
setPickupStatus(
|
||||
reaction === 'like' ? '感谢您的点赞!' : '已记录您的反馈,该瓶子被捡起的概率将会降低。',
|
||||
)
|
||||
} else {
|
||||
setPickupStatus(data.error || '记录反馈时出错。')
|
||||
setReactionDisabled(false)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Reaction request failed', error)
|
||||
setPickupStatus('请求失败,请稍后再试。')
|
||||
setReactionDisabled(false)
|
||||
}
|
||||
},
|
||||
[currentBottle],
|
||||
)
|
||||
|
||||
const nameCharCount = useMemo(() => formData.name.length, [formData.name])
|
||||
const messageCharCount = useMemo(() => formData.message.length, [formData.message])
|
||||
|
||||
return (
|
||||
<div className="page-wrapper">
|
||||
<div className="background-overlay" aria-hidden="true" />
|
||||
|
||||
<div className="container">
|
||||
<h1>
|
||||
<i className="fas fa-heart heart-icon" /> 萌芽漂流瓶{' '}
|
||||
<i className="fas fa-heart heart-icon" />
|
||||
</h1>
|
||||
<p className="tagline">让心意随海浪飘向远方,邂逅那个懂你的人(´,,•ω•,,)♡...</p>
|
||||
|
||||
|
||||
<div className="stats-container">
|
||||
<p>
|
||||
<i className="fas fa-wine-bottle" /> 海洋中共有{' '}
|
||||
<span id="total-bottles">{formatCount(stats.total_bottles)}</span> 个漂流瓶在寻找有缘人
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="action-section throw-section">
|
||||
<h2>
|
||||
<i className="fas fa-paper-plane" /> 扔一个漂流瓶(,,・ω・,,)
|
||||
</h2>
|
||||
<form id="throw-bottle-form" onSubmit={handleThrowSubmit}>
|
||||
<div>
|
||||
<label htmlFor="name">
|
||||
你的昵称:{' '}
|
||||
<span className={`char-count ${nameCharCount >= limits.name ? 'char-count-limit' : ''}`}>
|
||||
<span id="name-char-count">{nameCharCount}</span>/{' '}
|
||||
<span id="name-limit">{limits.name}</span>
|
||||
</span>
|
||||
</label>
|
||||
<input
|
||||
id="name"
|
||||
name="name"
|
||||
type="text"
|
||||
value={formData.name}
|
||||
onChange={handleInputChange}
|
||||
maxLength={limits.name}
|
||||
placeholder="告诉对方你是谁..."
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label htmlFor="message">
|
||||
漂流瓶内容:{' '}
|
||||
<span
|
||||
className={`char-count ${
|
||||
messageCharCount >= limits.message ? 'char-count-limit' : ''
|
||||
}`}
|
||||
>
|
||||
<span id="message-char-count">{messageCharCount}</span>/{' '}
|
||||
<span id="message-limit">{limits.message}</span>
|
||||
</span>
|
||||
</label>
|
||||
<textarea
|
||||
id="message"
|
||||
name="message"
|
||||
rows="4"
|
||||
value={formData.message}
|
||||
onChange={handleInputChange}
|
||||
maxLength={limits.message}
|
||||
placeholder="写下你想说的话,也许会有人懂..."
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label htmlFor="gender">性别:</label>
|
||||
<select id="gender" name="gender" value={formData.gender} onChange={handleInputChange}>
|
||||
<option value="保密">保密</option>
|
||||
<option value="男">男</option>
|
||||
<option value="女">女</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label htmlFor="qq">QQ号 (选填):</label>
|
||||
<input
|
||||
id="qq"
|
||||
name="qq"
|
||||
type="text"
|
||||
value={formData.qq}
|
||||
inputMode="numeric"
|
||||
pattern="[0-9]*"
|
||||
onChange={handleInputChange}
|
||||
placeholder="填写QQ号展示头像..."
|
||||
/>
|
||||
</div>
|
||||
|
||||
{cooldowns.throw > 0 ? (
|
||||
<div id="throw-cooldown" className="cooldown-timer">
|
||||
<i className="fas fa-hourglass-half" /> 冷却中: <span id="throw-countdown">{cooldowns.throw}</span> 秒
|
||||
</div>
|
||||
) : (
|
||||
<button type="submit" id="throw-button" className="btn-throw" disabled={isThrowing}>
|
||||
<i className="fas fa-paper-plane" /> {isThrowing ? '正在扔瓶子...' : '扔出去'}
|
||||
</button>
|
||||
)}
|
||||
</form>
|
||||
<p id="throw-status">{throwStatus}</p>
|
||||
</div>
|
||||
|
||||
<div className="action-section pickup-section">
|
||||
<h2>
|
||||
<i className="fas fa-search-location" /> 捡一个漂流瓶(,,・ω・,,)
|
||||
</h2>
|
||||
|
||||
{cooldowns.pickup > 0 ? (
|
||||
<div id="pickup-cooldown" className="cooldown-timer">
|
||||
<i className="fas fa-hourglass-half" /> 冷却中: <span id="pickup-countdown">{cooldowns.pickup}</span> 秒
|
||||
</div>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
id="pickup-bottle-button"
|
||||
className="btn-pickup"
|
||||
onClick={handlePickup}
|
||||
disabled={isPicking}
|
||||
>
|
||||
<i className="fas fa-hand-paper" /> {isPicking ? '正在打捞...' : '捡瓶子'}
|
||||
</button>
|
||||
)}
|
||||
|
||||
{currentBottle && (
|
||||
<div id="bottle-display" className="appear">
|
||||
<div className="bottle-header">
|
||||
{currentBottle.qq_avatar_url ? (
|
||||
<img id="bottle-avatar" src={currentBottle.qq_avatar_url} alt="QQ Avatar" />
|
||||
) : null}
|
||||
<h3>
|
||||
来自 <span id="bottle-name">{currentBottle.name}</span>{' '}
|
||||
<span className="gender-badge" id="bottle-gender">
|
||||
{currentBottle.gender || '保密'}
|
||||
</span>{' '}
|
||||
的漂流瓶
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div className="message-content">
|
||||
<p id="bottle-message">{currentBottle.message}</p>
|
||||
</div>
|
||||
|
||||
<div className="bottle-footer">
|
||||
<div className="bottle-info">
|
||||
<small>
|
||||
<i className="far fa-clock" /> 时间: <span id="bottle-timestamp">{currentBottle.timestamp}</span>
|
||||
</small>
|
||||
<small>
|
||||
<i className="fas fa-map-marker-alt" /> IP:{' '}
|
||||
<span id="bottle-ip">{currentBottle.ip_address || '未知'}</span>
|
||||
</small>
|
||||
{currentBottle.qq_number ? (
|
||||
<small id="bottle-qq-number">
|
||||
<i className="fab fa-qq" /> QQ: <span id="qq-number-val">{currentBottle.qq_number}</span>
|
||||
</small>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
<div className="bottle-reactions">
|
||||
<button
|
||||
type="button"
|
||||
id="like-button"
|
||||
className="reaction-btn like-btn"
|
||||
onClick={() => handleReaction('like')}
|
||||
disabled={reactionDisabled}
|
||||
>
|
||||
<i className="far fa-thumbs-up" /> <span id="like-count">{formatCount(currentBottle.likes)}</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
id="dislike-button"
|
||||
className="reaction-btn dislike-btn"
|
||||
onClick={() => handleReaction('dislike')}
|
||||
disabled={reactionDisabled}
|
||||
>
|
||||
<i className="far fa-thumbs-down" />{' '}
|
||||
<span id="dislike-count">{formatCount(currentBottle.dislikes)}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<p id="pickup-status">{pickupStatus}</p>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<p>
|
||||
© 2025 萌芽漂流瓶-蜀ICP备2025151694号 <i className="fas fa-heart" />
|
||||
</p>
|
||||
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default App
|
||||
1
mengyadriftbottle-frontend/src/assets/react.svg
Normal 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 |
12
mengyadriftbottle-frontend/src/index.css
Normal file
@@ -0,0 +1,12 @@
|
||||
:root {
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
min-width: 320px;
|
||||
min-height: 100vh;
|
||||
}
|
||||
10
mengyadriftbottle-frontend/src/main.jsx
Normal file
@@ -0,0 +1,10 @@
|
||||
import { StrictMode } from 'react'
|
||||
import { createRoot } from 'react-dom/client'
|
||||
import './index.css'
|
||||
import App from './App.jsx'
|
||||
|
||||
createRoot(document.getElementById('root')).render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
</StrictMode>,
|
||||
)
|
||||
453
mengyadriftbottle-frontend/static/admin.css
Normal file
@@ -0,0 +1,453 @@
|
||||
/* 管理后台样式 */
|
||||
:root {
|
||||
--admin-primary: #8a5fad;
|
||||
--admin-secondary: #d291bc;
|
||||
--admin-dark: #5e4b6b;
|
||||
--admin-light: #f8f4ff;
|
||||
--admin-gray: #e9e3f5;
|
||||
--admin-success: #6bbd85;
|
||||
--admin-error: #e65c8f;
|
||||
--admin-warning: #f3a754;
|
||||
}
|
||||
|
||||
.admin-body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: #f3f0f8;
|
||||
color: #333;
|
||||
font-family: 'Segoe UI', Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
/* 登录页面样式 */
|
||||
.admin-container {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: linear-gradient(135deg, #f5e8f0 0%, #f3e5fc 100%);
|
||||
}
|
||||
|
||||
.admin-card {
|
||||
width: 400px;
|
||||
background-color: white;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 5px 20px rgba(138, 95, 173, 0.1);
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.admin-header {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.admin-header h1 {
|
||||
color: var(--admin-primary);
|
||||
margin-bottom: 10px;
|
||||
font-size: 1.8em;
|
||||
}
|
||||
|
||||
.admin-header p {
|
||||
color: var(--admin-secondary);
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.alert {
|
||||
padding: 12px 15px;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 20px;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.alert-error {
|
||||
background-color: #ffecf1;
|
||||
color: var(--admin-error);
|
||||
border-left: 4px solid var(--admin-error);
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
background-color: #ecf9f2;
|
||||
color: var(--admin-success);
|
||||
border-left: 4px solid var(--admin-success);
|
||||
}
|
||||
|
||||
.admin-form .form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.admin-form label {
|
||||
display: block;
|
||||
color: var(--admin-dark);
|
||||
margin-bottom: 8px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.admin-form input {
|
||||
width: 100%;
|
||||
padding: 12px 15px;
|
||||
border: 1px solid var(--admin-gray);
|
||||
border-radius: 5px;
|
||||
font-size: 1em;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.admin-form input:focus {
|
||||
outline: none;
|
||||
border-color: var(--admin-primary);
|
||||
box-shadow: 0 0 0 3px rgba(138, 95, 173, 0.1);
|
||||
}
|
||||
|
||||
.admin-btn {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
background-color: var(--admin-primary);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
font-size: 1em;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.admin-btn:hover {
|
||||
background-color: #7b4f9d;
|
||||
}
|
||||
|
||||
.admin-footer {
|
||||
margin-top: 25px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.back-link {
|
||||
color: var(--admin-primary);
|
||||
text-decoration: none;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.back-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* 仪表盘布局 */
|
||||
.admin-sidebar {
|
||||
width: 250px;
|
||||
background-color: var(--admin-dark);
|
||||
color: white;
|
||||
height: 100vh;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.admin-sidebar-header {
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.admin-sidebar-header h2 {
|
||||
margin: 0 0 5px;
|
||||
font-size: 1.4em;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.admin-sidebar-header p {
|
||||
margin: 0;
|
||||
font-size: 0.9em;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.admin-menu {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.admin-menu li {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.admin-menu li a {
|
||||
display: block;
|
||||
padding: 12px 20px;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.admin-menu li a i {
|
||||
margin-right: 10px;
|
||||
width: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.admin-menu li a:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.admin-menu li.active a {
|
||||
background-color: rgba(255, 255, 255, 0.15);
|
||||
font-weight: 600;
|
||||
border-left: 4px solid var(--admin-secondary);
|
||||
}
|
||||
|
||||
.admin-main {
|
||||
flex-grow: 1;
|
||||
margin-left: 250px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.admin-header-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 30px;
|
||||
background-color: white;
|
||||
padding: 15px 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.admin-header-bar h1 {
|
||||
margin: 0;
|
||||
font-size: 1.5em;
|
||||
color: var(--admin-dark);
|
||||
}
|
||||
|
||||
.admin-user {
|
||||
font-size: 0.9em;
|
||||
color: var(--admin-primary);
|
||||
}
|
||||
|
||||
.admin-content {
|
||||
background-color: white;
|
||||
padding: 25px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
/* 统计卡片 */
|
||||
.admin-stats {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
background-color: var(--admin-light);
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.03);
|
||||
}
|
||||
|
||||
.stat-icon {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
background-color: var(--admin-primary);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.stat-icon i {
|
||||
color: white;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.stat-info h3 {
|
||||
margin: 0;
|
||||
font-size: 1.8em;
|
||||
color: var(--admin-primary);
|
||||
}
|
||||
|
||||
.stat-info p {
|
||||
margin: 5px 0 0;
|
||||
font-size: 0.9em;
|
||||
color: var(--admin-dark);
|
||||
}
|
||||
|
||||
/* 表格样式 */
|
||||
.admin-table-container {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.admin-table-container h2 {
|
||||
margin-top: 0;
|
||||
color: var(--admin-dark);
|
||||
margin-bottom: 15px;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.admin-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.admin-table th,
|
||||
.admin-table td {
|
||||
text-align: left;
|
||||
padding: 12px 15px;
|
||||
border-bottom: 1px solid var(--admin-gray);
|
||||
}
|
||||
|
||||
.admin-table th {
|
||||
background-color: var(--admin-light);
|
||||
color: var(--admin-dark);
|
||||
font-weight: 600;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.admin-table tr:hover {
|
||||
background-color: #fdfbff;
|
||||
}
|
||||
|
||||
.bottle-id {
|
||||
font-family: monospace;
|
||||
font-size: 0.8em;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.bottle-message {
|
||||
max-width: 300px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.delete-btn {
|
||||
background-color: #ffeaef;
|
||||
color: var(--admin-error);
|
||||
border: none;
|
||||
padding: 6px 10px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 0.85em;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.delete-btn:hover {
|
||||
background-color: var(--admin-error);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.no-data {
|
||||
text-align: center;
|
||||
padding: 30px;
|
||||
color: #888;
|
||||
background-color: #f9f9f9;
|
||||
border-radius: 5px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
/* 设置页面 */
|
||||
.settings-card {
|
||||
background-color: white;
|
||||
border-radius: 8px;
|
||||
padding: 25px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.settings-card h2 {
|
||||
margin-top: 0;
|
||||
color: var(--admin-dark);
|
||||
margin-bottom: 10px;
|
||||
font-size: 1.3em;
|
||||
}
|
||||
|
||||
.settings-description {
|
||||
color: #777;
|
||||
margin-bottom: 30px;
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
.settings-form .form-group {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.settings-form label {
|
||||
display: block;
|
||||
margin-bottom: 10px;
|
||||
color: var(--admin-dark);
|
||||
}
|
||||
|
||||
.setting-hint {
|
||||
font-size: 0.85em;
|
||||
color: var(--admin-secondary);
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.settings-form input[type="number"] {
|
||||
width: 120px;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid var(--admin-gray);
|
||||
border-radius: 4px;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.settings-form input[type="number"]:focus {
|
||||
outline: none;
|
||||
border-color: var(--admin-primary);
|
||||
box-shadow: 0 0 0 3px rgba(138, 95, 173, 0.1);
|
||||
}
|
||||
|
||||
.save-btn {
|
||||
background-color: var(--admin-success);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 10px 20px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 1em;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.save-btn:hover {
|
||||
background-color: #5aa975;
|
||||
}
|
||||
|
||||
.settings-note {
|
||||
background-color: #fffbeb;
|
||||
padding: 15px;
|
||||
border-radius: 5px;
|
||||
margin-top: 30px;
|
||||
border-left: 4px solid var(--admin-warning);
|
||||
}
|
||||
|
||||
.settings-note p {
|
||||
margin: 0;
|
||||
color: #997328;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 768px) {
|
||||
.admin-body {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.admin-sidebar {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.admin-main {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.admin-stats {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.admin-card {
|
||||
width: 90%;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
Fonticons, Inc. (https://fontawesome.com)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Font Awesome Free License
|
||||
|
||||
Font Awesome Free is free, open source, and GPL friendly. You can use it for
|
||||
commercial projects, open source projects, or really almost whatever you want.
|
||||
Full Font Awesome Free license: https://fontawesome.com/license/free.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
# Icons: CC BY 4.0 License (https://creativecommons.org/licenses/by/4.0/)
|
||||
|
||||
The Font Awesome Free download is licensed under a Creative Commons
|
||||
Attribution 4.0 International License and applies to all icons packaged
|
||||
as SVG and JS file types.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
# Fonts: SIL OFL 1.1 License
|
||||
|
||||
In the Font Awesome Free download, the SIL OFL license applies to all icons
|
||||
packaged as web and desktop font files.
|
||||
|
||||
Copyright (c) 2024 Fonticons, Inc. (https://fontawesome.com)
|
||||
with Reserved Font Name: "Font Awesome".
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
SIL OPEN FONT LICENSE
|
||||
Version 1.1 - 26 February 2007
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting — in part or in whole — any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
# Code: MIT License (https://opensource.org/licenses/MIT)
|
||||
|
||||
In the Font Awesome Free download, the MIT license applies to all non-font and
|
||||
non-icon files.
|
||||
|
||||
Copyright 2024 Fonticons, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without limitation the rights to use, copy,
|
||||
modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so, subject to the
|
||||
following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
# Attribution
|
||||
|
||||
Attribution is required by MIT, SIL OFL, and CC BY licenses. Downloaded Font
|
||||
Awesome Free files already contain embedded comments with sufficient
|
||||
attribution, so you shouldn't need to do anything additional when using these
|
||||
files normally.
|
||||
|
||||
We've kept attribution comments terse, so we ask that you do not actively work
|
||||
to remove them from files, especially code. They're a great way for folks to
|
||||
learn about Font Awesome.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
# Brand Icons
|
||||
|
||||
All brand icons are trademarks of their respective owners. The use of these
|
||||
trademarks does not indicate endorsement of the trademark holder by Font
|
||||
Awesome, nor vice versa. **Please do not use brand logos for any purpose except
|
||||
to represent the company, product, or service to which they refer.**
|
||||
9
mengyadriftbottle-frontend/static/fontawesome-free-6.7.2-web/css/all.min.css
vendored
Normal file
6
mengyadriftbottle-frontend/static/fontawesome-free-6.7.2-web/css/brands.min.css
vendored
Normal file
6243
mengyadriftbottle-frontend/static/fontawesome-free-6.7.2-web/css/fontawesome.css
vendored
Normal file
9
mengyadriftbottle-frontend/static/fontawesome-free-6.7.2-web/css/fontawesome.min.css
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
/*!
|
||||
* Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2024 Fonticons, Inc.
|
||||
*/
|
||||
:root, :host {
|
||||
--fa-style-family-classic: 'Font Awesome 6 Free';
|
||||
--fa-font-regular: normal 400 1em/1 'Font Awesome 6 Free'; }
|
||||
|
||||
@font-face {
|
||||
font-family: 'Font Awesome 6 Free';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: block;
|
||||
src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype"); }
|
||||
|
||||
.far,
|
||||
.fa-regular {
|
||||
font-weight: 400; }
|
||||
6
mengyadriftbottle-frontend/static/fontawesome-free-6.7.2-web/css/regular.min.css
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
/*!
|
||||
* Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2024 Fonticons, Inc.
|
||||
*/
|
||||
:host,:root{--fa-style-family-classic:"Font Awesome 6 Free";--fa-font-regular:normal 400 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype")}.fa-regular,.far{font-weight:400}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*!
|
||||
* Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2024 Fonticons, Inc.
|
||||
*/
|
||||
:root, :host {
|
||||
--fa-style-family-classic: 'Font Awesome 6 Free';
|
||||
--fa-font-solid: normal 900 1em/1 'Font Awesome 6 Free'; }
|
||||
|
||||
@font-face {
|
||||
font-family: 'Font Awesome 6 Free';
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
font-display: block;
|
||||
src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); }
|
||||
|
||||
.fas,
|
||||
.fa-solid {
|
||||
font-weight: 900; }
|
||||
6
mengyadriftbottle-frontend/static/fontawesome-free-6.7.2-web/css/solid.min.css
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
/*!
|
||||
* Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2024 Fonticons, Inc.
|
||||
*/
|
||||
:host,:root{--fa-style-family-classic:"Font Awesome 6 Free";--fa-font-solid:normal 900 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}.fa-solid,.fas{font-weight:900}
|
||||
@@ -0,0 +1,461 @@
|
||||
/*!
|
||||
* Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2024 Fonticons, Inc.
|
||||
*/
|
||||
:root, :host {
|
||||
--fa-font-solid: normal 900 1em/1 'Font Awesome 6 Free';
|
||||
--fa-font-regular: normal 400 1em/1 'Font Awesome 6 Free';
|
||||
--fa-font-light: normal 300 1em/1 'Font Awesome 6 Pro';
|
||||
--fa-font-thin: normal 100 1em/1 'Font Awesome 6 Pro';
|
||||
--fa-font-duotone: normal 900 1em/1 'Font Awesome 6 Duotone';
|
||||
--fa-font-duotone-regular: normal 400 1em/1 'Font Awesome 6 Duotone';
|
||||
--fa-font-duotone-light: normal 300 1em/1 'Font Awesome 6 Duotone';
|
||||
--fa-font-duotone-thin: normal 100 1em/1 'Font Awesome 6 Duotone';
|
||||
--fa-font-brands: normal 400 1em/1 'Font Awesome 6 Brands';
|
||||
--fa-font-sharp-solid: normal 900 1em/1 'Font Awesome 6 Sharp';
|
||||
--fa-font-sharp-regular: normal 400 1em/1 'Font Awesome 6 Sharp';
|
||||
--fa-font-sharp-light: normal 300 1em/1 'Font Awesome 6 Sharp';
|
||||
--fa-font-sharp-thin: normal 100 1em/1 'Font Awesome 6 Sharp';
|
||||
--fa-font-sharp-duotone-solid: normal 900 1em/1 'Font Awesome 6 Sharp Duotone';
|
||||
--fa-font-sharp-duotone-regular: normal 400 1em/1 'Font Awesome 6 Sharp Duotone';
|
||||
--fa-font-sharp-duotone-light: normal 300 1em/1 'Font Awesome 6 Sharp Duotone';
|
||||
--fa-font-sharp-duotone-thin: normal 100 1em/1 'Font Awesome 6 Sharp Duotone'; }
|
||||
|
||||
svg.svg-inline--fa:not(:root), svg.svg-inline--fa:not(:host) {
|
||||
overflow: visible;
|
||||
box-sizing: content-box; }
|
||||
|
||||
.svg-inline--fa {
|
||||
display: var(--fa-display, inline-block);
|
||||
height: 1em;
|
||||
overflow: visible;
|
||||
vertical-align: -.125em; }
|
||||
.svg-inline--fa.fa-2xs {
|
||||
vertical-align: 0.1em; }
|
||||
.svg-inline--fa.fa-xs {
|
||||
vertical-align: 0em; }
|
||||
.svg-inline--fa.fa-sm {
|
||||
vertical-align: -0.07143em; }
|
||||
.svg-inline--fa.fa-lg {
|
||||
vertical-align: -0.2em; }
|
||||
.svg-inline--fa.fa-xl {
|
||||
vertical-align: -0.25em; }
|
||||
.svg-inline--fa.fa-2xl {
|
||||
vertical-align: -0.3125em; }
|
||||
.svg-inline--fa.fa-pull-left {
|
||||
margin-right: var(--fa-pull-margin, 0.3em);
|
||||
width: auto; }
|
||||
.svg-inline--fa.fa-pull-right {
|
||||
margin-left: var(--fa-pull-margin, 0.3em);
|
||||
width: auto; }
|
||||
.svg-inline--fa.fa-li {
|
||||
width: var(--fa-li-width, 2em);
|
||||
top: 0.25em; }
|
||||
.svg-inline--fa.fa-fw {
|
||||
width: var(--fa-fw-width, 1.25em); }
|
||||
|
||||
.fa-layers svg.svg-inline--fa {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
margin: auto;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0; }
|
||||
|
||||
.fa-layers-counter, .fa-layers-text {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
text-align: center; }
|
||||
|
||||
.fa-layers {
|
||||
display: inline-block;
|
||||
height: 1em;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
vertical-align: -.125em;
|
||||
width: 1em; }
|
||||
.fa-layers svg.svg-inline--fa {
|
||||
transform-origin: center center; }
|
||||
|
||||
.fa-layers-text {
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
transform-origin: center center; }
|
||||
|
||||
.fa-layers-counter {
|
||||
background-color: var(--fa-counter-background-color, #ff253a);
|
||||
border-radius: var(--fa-counter-border-radius, 1em);
|
||||
box-sizing: border-box;
|
||||
color: var(--fa-inverse, #fff);
|
||||
line-height: var(--fa-counter-line-height, 1);
|
||||
max-width: var(--fa-counter-max-width, 5em);
|
||||
min-width: var(--fa-counter-min-width, 1.5em);
|
||||
overflow: hidden;
|
||||
padding: var(--fa-counter-padding, 0.25em 0.5em);
|
||||
right: var(--fa-right, 0);
|
||||
text-overflow: ellipsis;
|
||||
top: var(--fa-top, 0);
|
||||
transform: scale(var(--fa-counter-scale, 0.25));
|
||||
transform-origin: top right; }
|
||||
|
||||
.fa-layers-bottom-right {
|
||||
bottom: var(--fa-bottom, 0);
|
||||
right: var(--fa-right, 0);
|
||||
top: auto;
|
||||
transform: scale(var(--fa-layers-scale, 0.25));
|
||||
transform-origin: bottom right; }
|
||||
|
||||
.fa-layers-bottom-left {
|
||||
bottom: var(--fa-bottom, 0);
|
||||
left: var(--fa-left, 0);
|
||||
right: auto;
|
||||
top: auto;
|
||||
transform: scale(var(--fa-layers-scale, 0.25));
|
||||
transform-origin: bottom left; }
|
||||
|
||||
.fa-layers-top-right {
|
||||
top: var(--fa-top, 0);
|
||||
right: var(--fa-right, 0);
|
||||
transform: scale(var(--fa-layers-scale, 0.25));
|
||||
transform-origin: top right; }
|
||||
|
||||
.fa-layers-top-left {
|
||||
left: var(--fa-left, 0);
|
||||
right: auto;
|
||||
top: var(--fa-top, 0);
|
||||
transform: scale(var(--fa-layers-scale, 0.25));
|
||||
transform-origin: top left; }
|
||||
|
||||
.fa-1x {
|
||||
font-size: 1em; }
|
||||
|
||||
.fa-2x {
|
||||
font-size: 2em; }
|
||||
|
||||
.fa-3x {
|
||||
font-size: 3em; }
|
||||
|
||||
.fa-4x {
|
||||
font-size: 4em; }
|
||||
|
||||
.fa-5x {
|
||||
font-size: 5em; }
|
||||
|
||||
.fa-6x {
|
||||
font-size: 6em; }
|
||||
|
||||
.fa-7x {
|
||||
font-size: 7em; }
|
||||
|
||||
.fa-8x {
|
||||
font-size: 8em; }
|
||||
|
||||
.fa-9x {
|
||||
font-size: 9em; }
|
||||
|
||||
.fa-10x {
|
||||
font-size: 10em; }
|
||||
|
||||
.fa-2xs {
|
||||
font-size: 0.625em;
|
||||
line-height: 0.1em;
|
||||
vertical-align: 0.225em; }
|
||||
|
||||
.fa-xs {
|
||||
font-size: 0.75em;
|
||||
line-height: 0.08333em;
|
||||
vertical-align: 0.125em; }
|
||||
|
||||
.fa-sm {
|
||||
font-size: 0.875em;
|
||||
line-height: 0.07143em;
|
||||
vertical-align: 0.05357em; }
|
||||
|
||||
.fa-lg {
|
||||
font-size: 1.25em;
|
||||
line-height: 0.05em;
|
||||
vertical-align: -0.075em; }
|
||||
|
||||
.fa-xl {
|
||||
font-size: 1.5em;
|
||||
line-height: 0.04167em;
|
||||
vertical-align: -0.125em; }
|
||||
|
||||
.fa-2xl {
|
||||
font-size: 2em;
|
||||
line-height: 0.03125em;
|
||||
vertical-align: -0.1875em; }
|
||||
|
||||
.fa-fw {
|
||||
text-align: center;
|
||||
width: 1.25em; }
|
||||
|
||||
.fa-ul {
|
||||
list-style-type: none;
|
||||
margin-left: var(--fa-li-margin, 2.5em);
|
||||
padding-left: 0; }
|
||||
.fa-ul > li {
|
||||
position: relative; }
|
||||
|
||||
.fa-li {
|
||||
left: calc(-1 * var(--fa-li-width, 2em));
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
width: var(--fa-li-width, 2em);
|
||||
line-height: inherit; }
|
||||
|
||||
.fa-border {
|
||||
border-color: var(--fa-border-color, #eee);
|
||||
border-radius: var(--fa-border-radius, 0.1em);
|
||||
border-style: var(--fa-border-style, solid);
|
||||
border-width: var(--fa-border-width, 0.08em);
|
||||
padding: var(--fa-border-padding, 0.2em 0.25em 0.15em); }
|
||||
|
||||
.fa-pull-left {
|
||||
float: left;
|
||||
margin-right: var(--fa-pull-margin, 0.3em); }
|
||||
|
||||
.fa-pull-right {
|
||||
float: right;
|
||||
margin-left: var(--fa-pull-margin, 0.3em); }
|
||||
|
||||
.fa-beat {
|
||||
animation-name: fa-beat;
|
||||
animation-delay: var(--fa-animation-delay, 0s);
|
||||
animation-direction: var(--fa-animation-direction, normal);
|
||||
animation-duration: var(--fa-animation-duration, 1s);
|
||||
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||
animation-timing-function: var(--fa-animation-timing, ease-in-out); }
|
||||
|
||||
.fa-bounce {
|
||||
animation-name: fa-bounce;
|
||||
animation-delay: var(--fa-animation-delay, 0s);
|
||||
animation-direction: var(--fa-animation-direction, normal);
|
||||
animation-duration: var(--fa-animation-duration, 1s);
|
||||
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||
animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1)); }
|
||||
|
||||
.fa-fade {
|
||||
animation-name: fa-fade;
|
||||
animation-delay: var(--fa-animation-delay, 0s);
|
||||
animation-direction: var(--fa-animation-direction, normal);
|
||||
animation-duration: var(--fa-animation-duration, 1s);
|
||||
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||
animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); }
|
||||
|
||||
.fa-beat-fade {
|
||||
animation-name: fa-beat-fade;
|
||||
animation-delay: var(--fa-animation-delay, 0s);
|
||||
animation-direction: var(--fa-animation-direction, normal);
|
||||
animation-duration: var(--fa-animation-duration, 1s);
|
||||
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||
animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); }
|
||||
|
||||
.fa-flip {
|
||||
animation-name: fa-flip;
|
||||
animation-delay: var(--fa-animation-delay, 0s);
|
||||
animation-direction: var(--fa-animation-direction, normal);
|
||||
animation-duration: var(--fa-animation-duration, 1s);
|
||||
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||
animation-timing-function: var(--fa-animation-timing, ease-in-out); }
|
||||
|
||||
.fa-shake {
|
||||
animation-name: fa-shake;
|
||||
animation-delay: var(--fa-animation-delay, 0s);
|
||||
animation-direction: var(--fa-animation-direction, normal);
|
||||
animation-duration: var(--fa-animation-duration, 1s);
|
||||
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||
animation-timing-function: var(--fa-animation-timing, linear); }
|
||||
|
||||
.fa-spin {
|
||||
animation-name: fa-spin;
|
||||
animation-delay: var(--fa-animation-delay, 0s);
|
||||
animation-direction: var(--fa-animation-direction, normal);
|
||||
animation-duration: var(--fa-animation-duration, 2s);
|
||||
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||
animation-timing-function: var(--fa-animation-timing, linear); }
|
||||
|
||||
.fa-spin-reverse {
|
||||
--fa-animation-direction: reverse; }
|
||||
|
||||
.fa-pulse,
|
||||
.fa-spin-pulse {
|
||||
animation-name: fa-spin;
|
||||
animation-direction: var(--fa-animation-direction, normal);
|
||||
animation-duration: var(--fa-animation-duration, 1s);
|
||||
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||
animation-timing-function: var(--fa-animation-timing, steps(8)); }
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.fa-beat,
|
||||
.fa-bounce,
|
||||
.fa-fade,
|
||||
.fa-beat-fade,
|
||||
.fa-flip,
|
||||
.fa-pulse,
|
||||
.fa-shake,
|
||||
.fa-spin,
|
||||
.fa-spin-pulse {
|
||||
animation-delay: -1ms;
|
||||
animation-duration: 1ms;
|
||||
animation-iteration-count: 1;
|
||||
transition-delay: 0s;
|
||||
transition-duration: 0s; } }
|
||||
|
||||
@keyframes fa-beat {
|
||||
0%, 90% {
|
||||
transform: scale(1); }
|
||||
45% {
|
||||
transform: scale(var(--fa-beat-scale, 1.25)); } }
|
||||
|
||||
@keyframes fa-bounce {
|
||||
0% {
|
||||
transform: scale(1, 1) translateY(0); }
|
||||
10% {
|
||||
transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); }
|
||||
30% {
|
||||
transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); }
|
||||
50% {
|
||||
transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); }
|
||||
57% {
|
||||
transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); }
|
||||
64% {
|
||||
transform: scale(1, 1) translateY(0); }
|
||||
100% {
|
||||
transform: scale(1, 1) translateY(0); } }
|
||||
|
||||
@keyframes fa-fade {
|
||||
50% {
|
||||
opacity: var(--fa-fade-opacity, 0.4); } }
|
||||
|
||||
@keyframes fa-beat-fade {
|
||||
0%, 100% {
|
||||
opacity: var(--fa-beat-fade-opacity, 0.4);
|
||||
transform: scale(1); }
|
||||
50% {
|
||||
opacity: 1;
|
||||
transform: scale(var(--fa-beat-fade-scale, 1.125)); } }
|
||||
|
||||
@keyframes fa-flip {
|
||||
50% {
|
||||
transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); } }
|
||||
|
||||
@keyframes fa-shake {
|
||||
0% {
|
||||
transform: rotate(-15deg); }
|
||||
4% {
|
||||
transform: rotate(15deg); }
|
||||
8%, 24% {
|
||||
transform: rotate(-18deg); }
|
||||
12%, 28% {
|
||||
transform: rotate(18deg); }
|
||||
16% {
|
||||
transform: rotate(-22deg); }
|
||||
20% {
|
||||
transform: rotate(22deg); }
|
||||
32% {
|
||||
transform: rotate(-12deg); }
|
||||
36% {
|
||||
transform: rotate(12deg); }
|
||||
40%, 100% {
|
||||
transform: rotate(0deg); } }
|
||||
|
||||
@keyframes fa-spin {
|
||||
0% {
|
||||
transform: rotate(0deg); }
|
||||
100% {
|
||||
transform: rotate(360deg); } }
|
||||
|
||||
.fa-rotate-90 {
|
||||
transform: rotate(90deg); }
|
||||
|
||||
.fa-rotate-180 {
|
||||
transform: rotate(180deg); }
|
||||
|
||||
.fa-rotate-270 {
|
||||
transform: rotate(270deg); }
|
||||
|
||||
.fa-flip-horizontal {
|
||||
transform: scale(-1, 1); }
|
||||
|
||||
.fa-flip-vertical {
|
||||
transform: scale(1, -1); }
|
||||
|
||||
.fa-flip-both,
|
||||
.fa-flip-horizontal.fa-flip-vertical {
|
||||
transform: scale(-1, -1); }
|
||||
|
||||
.fa-rotate-by {
|
||||
transform: rotate(var(--fa-rotate-angle, 0)); }
|
||||
|
||||
.fa-stack {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
height: 2em;
|
||||
position: relative;
|
||||
width: 2.5em; }
|
||||
|
||||
.fa-stack-1x,
|
||||
.fa-stack-2x {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
margin: auto;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
z-index: var(--fa-stack-z-index, auto); }
|
||||
|
||||
.svg-inline--fa.fa-stack-1x {
|
||||
height: 1em;
|
||||
width: 1.25em; }
|
||||
|
||||
.svg-inline--fa.fa-stack-2x {
|
||||
height: 2em;
|
||||
width: 2.5em; }
|
||||
|
||||
.fa-inverse {
|
||||
color: var(--fa-inverse, #fff); }
|
||||
|
||||
.sr-only,
|
||||
.fa-sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border-width: 0; }
|
||||
|
||||
.sr-only-focusable:not(:focus),
|
||||
.fa-sr-only-focusable:not(:focus) {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border-width: 0; }
|
||||
|
||||
.svg-inline--fa .fa-primary {
|
||||
fill: var(--fa-primary-color, currentColor);
|
||||
opacity: var(--fa-primary-opacity, 1); }
|
||||
|
||||
.svg-inline--fa .fa-secondary {
|
||||
fill: var(--fa-secondary-color, currentColor);
|
||||
opacity: var(--fa-secondary-opacity, 0.4); }
|
||||
|
||||
.svg-inline--fa.fa-swap-opacity .fa-primary {
|
||||
opacity: var(--fa-secondary-opacity, 0.4); }
|
||||
|
||||
.svg-inline--fa.fa-swap-opacity .fa-secondary {
|
||||
opacity: var(--fa-primary-opacity, 1); }
|
||||
|
||||
.svg-inline--fa mask .fa-primary,
|
||||
.svg-inline--fa mask .fa-secondary {
|
||||
fill: black; }
|
||||
6
mengyadriftbottle-frontend/static/fontawesome-free-6.7.2-web/css/svg-with-js.min.css
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
/*!
|
||||
* Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2024 Fonticons, Inc.
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'FontAwesome';
|
||||
font-display: block;
|
||||
src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); }
|
||||
|
||||
@font-face {
|
||||
font-family: 'FontAwesome';
|
||||
font-display: block;
|
||||
src: url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.ttf") format("truetype"); }
|
||||
|
||||
@font-face {
|
||||
font-family: 'FontAwesome';
|
||||
font-display: block;
|
||||
src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype");
|
||||
unicode-range: U+F003,U+F006,U+F014,U+F016-F017,U+F01A-F01B,U+F01D,U+F022,U+F03E,U+F044,U+F046,U+F05C-F05D,U+F06E,U+F070,U+F087-F088,U+F08A,U+F094,U+F096-F097,U+F09D,U+F0A0,U+F0A2,U+F0A4-F0A7,U+F0C5,U+F0C7,U+F0E5-F0E6,U+F0EB,U+F0F6-F0F8,U+F10C,U+F114-F115,U+F118-F11A,U+F11C-F11D,U+F133,U+F147,U+F14E,U+F150-F152,U+F185-F186,U+F18E,U+F190-F192,U+F196,U+F1C1-F1C9,U+F1D9,U+F1DB,U+F1E3,U+F1EA,U+F1F7,U+F1F9,U+F20A,U+F247-F248,U+F24A,U+F24D,U+F255-F25B,U+F25D,U+F271-F274,U+F278,U+F27B,U+F28C,U+F28E,U+F29C,U+F2B5,U+F2B7,U+F2BA,U+F2BC,U+F2BE,U+F2C0-F2C1,U+F2C3,U+F2D0,U+F2D2,U+F2D4,U+F2DC; }
|
||||
|
||||
@font-face {
|
||||
font-family: 'FontAwesome';
|
||||
font-display: block;
|
||||
src: url("../webfonts/fa-v4compatibility.woff2") format("woff2"), url("../webfonts/fa-v4compatibility.ttf") format("truetype");
|
||||
unicode-range: U+F041,U+F047,U+F065-F066,U+F07D-F07E,U+F080,U+F08B,U+F08E,U+F090,U+F09A,U+F0AC,U+F0AE,U+F0B2,U+F0D0,U+F0D6,U+F0E4,U+F0EC,U+F10A-F10B,U+F123,U+F13E,U+F148-F149,U+F14C,U+F156,U+F15E,U+F160-F161,U+F163,U+F175-F178,U+F195,U+F1F8,U+F219,U+F27A; }
|
||||
6
mengyadriftbottle-frontend/static/fontawesome-free-6.7.2-web/css/v4-font-face.min.css
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
/*!
|
||||
* Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2024 Fonticons, Inc.
|
||||
*/
|
||||
@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype");unicode-range:u+f003,u+f006,u+f014,u+f016-f017,u+f01a-f01b,u+f01d,u+f022,u+f03e,u+f044,u+f046,u+f05c-f05d,u+f06e,u+f070,u+f087-f088,u+f08a,u+f094,u+f096-f097,u+f09d,u+f0a0,u+f0a2,u+f0a4-f0a7,u+f0c5,u+f0c7,u+f0e5-f0e6,u+f0eb,u+f0f6-f0f8,u+f10c,u+f114-f115,u+f118-f11a,u+f11c-f11d,u+f133,u+f147,u+f14e,u+f150-f152,u+f185-f186,u+f18e,u+f190-f192,u+f196,u+f1c1-f1c9,u+f1d9,u+f1db,u+f1e3,u+f1ea,u+f1f7,u+f1f9,u+f20a,u+f247-f248,u+f24a,u+f24d,u+f255-f25b,u+f25d,u+f271-f274,u+f278,u+f27b,u+f28c,u+f28e,u+f29c,u+f2b5,u+f2b7,u+f2ba,u+f2bc,u+f2be,u+f2c0-f2c1,u+f2c3,u+f2d0,u+f2d2,u+f2d4,u+f2dc}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-v4compatibility.woff2) format("woff2"),url(../webfonts/fa-v4compatibility.ttf) format("truetype");unicode-range:u+f041,u+f047,u+f065-f066,u+f07d-f07e,u+f080,u+f08b,u+f08e,u+f090,u+f09a,u+f0ac,u+f0ae,u+f0b2,u+f0d0,u+f0d6,u+f0e4,u+f0ec,u+f10a-f10b,u+f123,u+f13e,u+f148-f149,u+f14c,u+f156,u+f15e,u+f160-f161,u+f163,u+f175-f178,u+f195,u+f1f8,u+f219,u+f27a}
|
||||
6
mengyadriftbottle-frontend/static/fontawesome-free-6.7.2-web/css/v4-shims.min.css
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
/*!
|
||||
* Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2024 Fonticons, Inc.
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'Font Awesome 5 Brands';
|
||||
font-display: block;
|
||||
font-weight: 400;
|
||||
src: url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.ttf") format("truetype"); }
|
||||
|
||||
@font-face {
|
||||
font-family: 'Font Awesome 5 Free';
|
||||
font-display: block;
|
||||
font-weight: 900;
|
||||
src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); }
|
||||
|
||||
@font-face {
|
||||
font-family: 'Font Awesome 5 Free';
|
||||
font-display: block;
|
||||
font-weight: 400;
|
||||
src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype"); }
|
||||
6
mengyadriftbottle-frontend/static/fontawesome-free-6.7.2-web/css/v5-font-face.min.css
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
/*!
|
||||
* Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2024 Fonticons, Inc.
|
||||
*/
|
||||
@font-face{font-family:"Font Awesome 5 Brands";font-display:block;font-weight:400;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}@font-face{font-family:"Font Awesome 5 Free";font-display:block;font-weight:900;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}@font-face{font-family:"Font Awesome 5 Free";font-display:block;font-weight:400;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype")}
|
||||
6
mengyadriftbottle-frontend/static/fontawesome-free-6.7.2-web/js/all.min.js
vendored
Normal file
6
mengyadriftbottle-frontend/static/fontawesome-free-6.7.2-web/js/brands.min.js
vendored
Normal file
6
mengyadriftbottle-frontend/static/fontawesome-free-6.7.2-web/js/conflict-detection.min.js
vendored
Normal file
6
mengyadriftbottle-frontend/static/fontawesome-free-6.7.2-web/js/fontawesome.min.js
vendored
Normal file
6
mengyadriftbottle-frontend/static/fontawesome-free-6.7.2-web/js/regular.min.js
vendored
Normal file
6
mengyadriftbottle-frontend/static/fontawesome-free-6.7.2-web/js/solid.min.js
vendored
Normal file
6
mengyadriftbottle-frontend/static/fontawesome-free-6.7.2-web/js/v4-shims.min.js
vendored
Normal file
@@ -0,0 +1,152 @@
|
||||
// animating icons
|
||||
// --------------------------
|
||||
|
||||
.@{fa-css-prefix}-beat {
|
||||
animation-name: ~'@{fa-css-prefix}-beat';
|
||||
animation-delay: ~'var(--@{fa-css-prefix}-animation-delay, 0s)';
|
||||
animation-direction: ~'var(--@{fa-css-prefix}-animation-direction, normal)';
|
||||
animation-duration: ~'var(--@{fa-css-prefix}-animation-duration, 1s)';
|
||||
animation-iteration-count: ~'var(--@{fa-css-prefix}-animation-iteration-count, infinite)';
|
||||
animation-timing-function: ~'var(--@{fa-css-prefix}-animation-timing, ease-in-out)';
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-bounce {
|
||||
animation-name: ~'@{fa-css-prefix}-bounce';
|
||||
animation-delay: ~'var(--@{fa-css-prefix}-animation-delay, 0s)';
|
||||
animation-direction: ~'var(--@{fa-css-prefix}-animation-direction, normal)';
|
||||
animation-duration: ~'var(--@{fa-css-prefix}-animation-duration, 1s)';
|
||||
animation-iteration-count: ~'var(--@{fa-css-prefix}-animation-iteration-count, infinite)';
|
||||
animation-timing-function: ~'var(--@{fa-css-prefix}-animation-timing, cubic-bezier(0.280, 0.840, 0.420, 1))';
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-fade {
|
||||
animation-name: ~'@{fa-css-prefix}-fade';
|
||||
animation-delay: ~'var(--@{fa-css-prefix}-animation-delay, 0s)';
|
||||
animation-direction: ~'var(--@{fa-css-prefix}-animation-direction, normal)';
|
||||
animation-duration: ~'var(--@{fa-css-prefix}-animation-duration, 1s)';
|
||||
animation-iteration-count: ~'var(--@{fa-css-prefix}-animation-iteration-count, infinite)';
|
||||
animation-timing-function: ~'var(--@{fa-css-prefix}-animation-timing, cubic-bezier(.4,0,.6,1))';
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-beat-fade {
|
||||
animation-name: ~'@{fa-css-prefix}-beat-fade';
|
||||
animation-delay: ~'var(--@{fa-css-prefix}-animation-delay, 0s)';
|
||||
animation-direction: ~'var(--@{fa-css-prefix}-animation-direction, normal)';
|
||||
animation-duration: ~'var(--@{fa-css-prefix}-animation-duration, 1s)';
|
||||
animation-iteration-count: ~'var(--@{fa-css-prefix}-animation-iteration-count, infinite)';
|
||||
animation-timing-function: ~'var(--@{fa-css-prefix}-animation-timing, cubic-bezier(.4,0,.6,1))';
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-flip {
|
||||
animation-name: ~'@{fa-css-prefix}-flip';
|
||||
animation-delay: ~'var(--@{fa-css-prefix}-animation-delay, 0s)';
|
||||
animation-direction: ~'var(--@{fa-css-prefix}-animation-direction, normal)';
|
||||
animation-duration: ~'var(--@{fa-css-prefix}-animation-duration, 1s)';
|
||||
animation-iteration-count: ~'var(--@{fa-css-prefix}-animation-iteration-count, infinite)';
|
||||
animation-timing-function: ~'var(--@{fa-css-prefix}-animation-timing, ease-in-out)';
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-shake {
|
||||
animation-name: ~'@{fa-css-prefix}-shake';
|
||||
animation-delay: ~'var(--@{fa-css-prefix}-animation-delay, 0s)';
|
||||
animation-direction: ~'var(--@{fa-css-prefix}-animation-direction, normal)';
|
||||
animation-duration: ~'var(--@{fa-css-prefix}-animation-duration, 1s)';
|
||||
animation-iteration-count: ~'var(--@{fa-css-prefix}-animation-iteration-count, infinite)';
|
||||
animation-timing-function: ~'var(--@{fa-css-prefix}-animation-timing, linear)';
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-spin {
|
||||
animation-name: ~'@{fa-css-prefix}-spin';
|
||||
animation-delay: ~'var(--@{fa-css-prefix}-animation-delay, 0s)';
|
||||
animation-direction: ~'var(--@{fa-css-prefix}-animation-direction, normal)';
|
||||
animation-duration: ~'var(--@{fa-css-prefix}-animation-duration, 2s)';
|
||||
animation-iteration-count: ~'var(--@{fa-css-prefix}-animation-iteration-count, infinite)';
|
||||
animation-timing-function: ~'var(--@{fa-css-prefix}-animation-timing, linear)';
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-spin-reverse {
|
||||
--@{fa-css-prefix}-animation-direction: reverse;
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-pulse,
|
||||
.@{fa-css-prefix}-spin-pulse {
|
||||
animation-name: ~'@{fa-css-prefix}-spin';
|
||||
animation-direction: ~'var(--@{fa-css-prefix}-animation-direction, normal)';
|
||||
animation-duration: ~'var(--@{fa-css-prefix}-animation-duration, 1s)';
|
||||
animation-iteration-count: ~'var(--@{fa-css-prefix}-animation-iteration-count, infinite)';
|
||||
animation-timing-function: ~'var(--@{fa-css-prefix}-animation-timing, steps(8));';
|
||||
}
|
||||
|
||||
// if agent or operating system prefers reduced motion, disable animations
|
||||
// see: https://www.smashingmagazine.com/2020/09/design-reduced-motion-sensitivities/
|
||||
// see: https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.@{fa-css-prefix}-beat,
|
||||
.@{fa-css-prefix}-bounce,
|
||||
.@{fa-css-prefix}-fade,
|
||||
.@{fa-css-prefix}-beat-fade,
|
||||
.@{fa-css-prefix}-flip,
|
||||
.@{fa-css-prefix}-pulse,
|
||||
.@{fa-css-prefix}-shake,
|
||||
.@{fa-css-prefix}-spin,
|
||||
.@{fa-css-prefix}-spin-pulse {
|
||||
animation-delay: -1ms;
|
||||
animation-duration: 1ms;
|
||||
animation-iteration-count: 1;
|
||||
transition-delay: 0s;
|
||||
transition-duration: 0s;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes ~'@{fa-css-prefix}-beat' {
|
||||
0%, 90% { transform: scale(1); }
|
||||
45% { transform: ~'scale(var(--@{fa-css-prefix}-beat-scale, 1.25))'; }
|
||||
}
|
||||
|
||||
@keyframes ~'@{fa-css-prefix}-bounce' {
|
||||
0% { transform: scale(1,1) translateY(0); }
|
||||
10% { transform: ~'scale(var(--@{fa-css-prefix}-bounce-start-scale-x, 1.1),var(--@{fa-css-prefix}-bounce-start-scale-y, 0.9))' translateY(0); }
|
||||
30% { transform: ~'scale(var(--@{fa-css-prefix}-bounce-jump-scale-x, 0.9),var(--@{fa-css-prefix}-bounce-jump-scale-y, 1.1))' ~'translateY(var(--@{fa-css-prefix}-bounce-height, -0.5em))'; }
|
||||
50% { transform: ~'scale(var(--@{fa-css-prefix}-bounce-land-scale-x, 1.05),var(--@{fa-css-prefix}-bounce-land-scale-y, 0.95))' translateY(0); }
|
||||
57% { transform: ~'scale(1,1) translateY(var(--@{fa-css-prefix}-bounce-rebound, -0.125em))'; }
|
||||
64% { transform: scale(1,1) translateY(0); }
|
||||
100% { transform: scale(1,1) translateY(0); }
|
||||
}
|
||||
|
||||
@keyframes ~'@{fa-css-prefix}-fade' {
|
||||
50% { opacity: ~'var(--@{fa-css-prefix}-fade-opacity, 0.4)'; }
|
||||
}
|
||||
|
||||
@keyframes ~'@{fa-css-prefix}-beat-fade' {
|
||||
0%, 100% {
|
||||
opacity: ~'var(--@{fa-css-prefix}-beat-fade-opacity, 0.4)';
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
opacity: 1;
|
||||
transform: ~'scale(var(--@{fa-css-prefix}-beat-fade-scale, 1.125))';
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes ~'@{fa-css-prefix}-flip' {
|
||||
50% {
|
||||
transform: ~'rotate3d(var(--@{fa-css-prefix}-flip-x, 0), var(--@{fa-css-prefix}-flip-y, 1), var(--@{fa-css-prefix}-flip-z, 0), var(--@{fa-css-prefix}-flip-angle, -180deg))';
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes ~'@{fa-css-prefix}-shake' {
|
||||
0% { transform: rotate(-15deg); }
|
||||
4% { transform: rotate(15deg); }
|
||||
8%, 24% { transform: rotate(-18deg); }
|
||||
12%, 28% { transform: rotate(18deg); }
|
||||
16% { transform: rotate(-22deg); }
|
||||
20% { transform: rotate(22deg); }
|
||||
32% { transform: rotate(-12deg); }
|
||||
36% { transform: rotate(12deg); }
|
||||
40%, 100% { transform: rotate(0deg); }
|
||||
}
|
||||
|
||||
@keyframes ~'@{fa-css-prefix}-spin' {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// bordered + pulled icons
|
||||
// -------------------------
|
||||
|
||||
.@{fa-css-prefix}-border {
|
||||
border-color: ~'var(--@{fa-css-prefix}-border-color, @{fa-border-color})';
|
||||
border-radius: ~'var(--@{fa-css-prefix}-border-radius, @{fa-border-radius})';
|
||||
border-style: ~'var(--@{fa-css-prefix}-border-style, @{fa-border-style})';
|
||||
border-width: ~'var(--@{fa-css-prefix}-border-width, @{fa-border-width})';
|
||||
padding: ~'var(--@{fa-css-prefix}-border-padding, @{fa-border-padding})';
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-pull-left {
|
||||
float: left;
|
||||
margin-right: ~'var(--@{fa-css-prefix}-pull-margin, @{fa-pull-margin})';
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-pull-right {
|
||||
float: right;
|
||||
margin-left: ~'var(--@{fa-css-prefix}-pull-margin, @{fa-pull-margin})';
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// base icon class definition
|
||||
// -------------------------
|
||||
|
||||
.@{fa-css-prefix} {
|
||||
font-family: ~"var(--@{fa-css-prefix}-style-family, '@{fa-style-family}')";
|
||||
font-weight: ~'var(--@{fa-css-prefix}-style, @{fa-style})';
|
||||
}
|
||||
|
||||
.fas,
|
||||
.far,
|
||||
.fab,
|
||||
.@{fa-css-prefix}-solid,
|
||||
.@{fa-css-prefix}-regular,
|
||||
.@{fa-css-prefix}-brands,
|
||||
|
||||
.@{fa-css-prefix}-sharp-solid,
|
||||
.@{fa-css-prefix}-classic,
|
||||
.@{fa-css-prefix} {
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
display: ~'var(--@{fa-css-prefix}-display, @{fa-display})';
|
||||
font-style: normal;
|
||||
font-variant: normal;
|
||||
line-height: 1;
|
||||
text-rendering: auto;
|
||||
}
|
||||
|
||||
.fas::before,
|
||||
.far::before,
|
||||
.fab::before,
|
||||
.@{fa-css-prefix}-solid::before,
|
||||
.@{fa-css-prefix}-regular::before,
|
||||
.@{fa-css-prefix}-brands::before,
|
||||
.@{fa-css-prefix}::before {
|
||||
content: ~'var(@{fa-icon-property})';
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-classic,
|
||||
.fas,
|
||||
.@{fa-css-prefix}-solid,
|
||||
.far,
|
||||
.@{fa-css-prefix}-regular {
|
||||
font-family: 'Font Awesome 6 Free';
|
||||
}
|
||||
.@{fa-css-prefix}-brands,
|
||||
.fab {
|
||||
font-family: 'Font Awesome 6 Brands';
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// fixed-width icons
|
||||
// -------------------------
|
||||
|
||||
.@{fa-css-prefix}-fw {
|
||||
text-align: center;
|
||||
width: @fa-fw-width;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// specific icon class definition
|
||||
// -------------------------
|
||||
|
||||
/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen
|
||||
readers do not read off random characters that represent icons */
|
||||
|
||||
each(.fa-icons(), {
|
||||
.@{fa-css-prefix}-@{key} {
|
||||
@{fa-icon-property}: @value;
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
// icons in a list
|
||||
// -------------------------
|
||||
|
||||
.@{fa-css-prefix}-ul {
|
||||
list-style-type: none;
|
||||
margin-left: ~'var(--@{fa-css-prefix}-li-margin, @{fa-li-margin})';
|
||||
padding-left: 0;
|
||||
|
||||
> li { position: relative; }
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-li {
|
||||
left: calc(~'var(--@{fa-css-prefix}-li-width, @{fa-li-width})' * -1);
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
width: ~'var(--@{fa-css-prefix}-li-width, @{fa-li-width})';
|
||||
line-height: inherit;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
// mixins
|
||||
// --------------------------
|
||||
|
||||
// base rendering for an icon
|
||||
.fa-icon() {
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
display: inline-block;
|
||||
font-style: normal;
|
||||
font-variant: normal;
|
||||
font-weight: normal;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
// sets relative font-sizing and alignment (in _sizing)
|
||||
.fa-size(@font-size) {
|
||||
font-size: (@font-size / @fa-size-scale-base) * 1em; // converts step in sizing scale into an em-based value that's relative to the scale's base
|
||||
line-height: (1 / @font-size) * 1em; // sets the line-height of the icon back to that of it's parent
|
||||
vertical-align: ((6 / @font-size) - (3 / 8)) * 1em; // vertically centers the icon taking into account the surrounding text's descender
|
||||
}
|
||||
|
||||
// only display content to screen readers
|
||||
// see: https://www.a11yproject.com/posts/2013-01-11-how-to-hide-content/
|
||||
// see: https://hugogiraudel.com/2016/10/13/css-hide-and-seek/
|
||||
.fa-sr-only() {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
// use in conjunction with .sr-only to only display content when it's focused
|
||||
.fa-sr-only-focusable() {
|
||||
&:not(:focus) {
|
||||
.fa-sr-only();
|
||||
}
|
||||
}
|
||||
|
||||
// sets a specific icon family to use alongside style + icon mixins
|
||||
.fa-family-classic() {
|
||||
&:extend(.fa-classic all);
|
||||
}
|
||||
|
||||
// convenience mixins for declaring pseudo-elements by CSS variable,
|
||||
// including all style-specific font properties
|
||||
.fa-icon-solid(@fa-var) {
|
||||
&:extend(.fa-solid all);
|
||||
|
||||
& { @{fa-icon-property}: @fa-var; @{fa-duotone-icon-property}: %("%s%s", @fa-var, @fa-var); }
|
||||
}
|
||||
|
||||
.fa-icon-regular(@fa-var) {
|
||||
&:extend(.fa-regular all);
|
||||
|
||||
& { @{fa-icon-property}: @fa-var; @{fa-duotone-icon-property}: %("%s%s", @fa-var, @fa-var); }
|
||||
}
|
||||
|
||||
.fa-icon-brands(@fa-var) {
|
||||
&:extend(.fa-brands all);
|
||||
|
||||
& { @{fa-icon-property}: @fa-var; @{fa-duotone-icon-property}: %("%s%s", @fa-var, @fa-var); }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
// rotating + flipping icons
|
||||
// -------------------------
|
||||
|
||||
.@{fa-css-prefix}-rotate-90 {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-rotate-180 {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-rotate-270 {
|
||||
transform: rotate(270deg);
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-flip-horizontal {
|
||||
transform: scale(-1, 1);
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-flip-vertical {
|
||||
transform: scale(1, -1);
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-flip-both,
|
||||
.@{fa-css-prefix}-flip-horizontal.@{fa-css-prefix}-flip-vertical {
|
||||
transform: scale(-1, -1);
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-rotate-by {
|
||||
transform: rotate(~'var(--@{fa-css-prefix}-rotate-angle, 0)');
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// screen-reader utilities
|
||||
// -------------------------
|
||||
|
||||
// only display content to screen readers
|
||||
.sr-only,
|
||||
.@{fa-css-prefix}-sr-only {
|
||||
.fa-sr-only();
|
||||
}
|
||||
|
||||
// use in conjunction with .sr-only to only display content when it's focused
|
||||
.sr-only-focusable,
|
||||
.@{fa-css-prefix}-sr-only-focusable {
|
||||
.fa-sr-only-focusable();
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// sizing icons
|
||||
// -------------------------
|
||||
|
||||
// literal magnification scale
|
||||
.sizes-literal(@factor) when (@factor > 0) {
|
||||
.sizes-literal((@factor - 1));
|
||||
|
||||
.@{fa-css-prefix}-@{factor}x {
|
||||
font-size: (@factor * 1em);
|
||||
}
|
||||
}
|
||||
.sizes-literal(10);
|
||||
|
||||
// step-based scale (with alignment)
|
||||
each(.fa-sizes(), {
|
||||
.@{fa-css-prefix}-@{key} {
|
||||
.fa-size(@value);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,31 @@
|
||||
// stacking icons
|
||||
// -------------------------
|
||||
|
||||
.@{fa-css-prefix}-stack {
|
||||
display: inline-block;
|
||||
height: 2em;
|
||||
line-height: 2em;
|
||||
position: relative;
|
||||
vertical-align: @fa-stack-vertical-align;
|
||||
width: @fa-stack-width;
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x {
|
||||
left: 0;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
z-index: ~'var(--@{fa-css-prefix}-stack-z-index, @{fa-stack-z-index})';
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-stack-1x {
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-stack-2x {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
.@{fa-css-prefix}-inverse {
|
||||
color: ~'var(--@{fa-css-prefix}-inverse, @{fa-inverse})';
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*!
|
||||
* Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2024 Fonticons, Inc.
|
||||
*/
|
||||
@import "_variables.less";
|
||||
|
||||
:root, :host {
|
||||
--@{fa-css-prefix}-style-family-brands: 'Font Awesome 6 Brands';
|
||||
--@{fa-css-prefix}-font-brands: normal 400 1em/1 'Font Awesome 6 Brands';
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Font Awesome 6 Brands';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: @fa-font-display;
|
||||
src: url('@{fa-font-path}/fa-brands-400.woff2') format('woff2'),
|
||||
url('@{fa-font-path}/fa-brands-400.ttf') format('truetype');
|
||||
}
|
||||
|
||||
.fab,
|
||||
.@{fa-css-prefix}-brands {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
each(.fa-brand-icons(), {
|
||||
.@{fa-css-prefix}-@{key} { @{fa-icon-property}: @value; }
|
||||
});
|
||||
20
mengyadriftbottle-frontend/static/fontawesome-free-6.7.2-web/less/fontawesome.less
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
/*!
|
||||
* Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2024 Fonticons, Inc.
|
||||
*/
|
||||
// Font Awesome core compile (Web Fonts-based)
|
||||
// -------------------------
|
||||
|
||||
@import "_variables.less";
|
||||
@import "_mixins.less";
|
||||
@import "_core.less";
|
||||
@import "_sizing.less";
|
||||
@import "_fixed-width.less";
|
||||
@import "_list.less";
|
||||
@import "_bordered-pulled.less";
|
||||
@import "_animated.less";
|
||||
@import "_rotated-flipped.less";
|
||||
@import "_stacked.less";
|
||||
@import "_icons.less";
|
||||
@import "_screen-reader.less";
|
||||
@@ -0,0 +1,25 @@
|
||||
/*!
|
||||
* Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2024 Fonticons, Inc.
|
||||
*/
|
||||
@import "_variables.less";
|
||||
|
||||
:root, :host {
|
||||
--@{fa-css-prefix}-style-family-classic: '@{fa-style-family}';
|
||||
--@{fa-css-prefix}-font-regular: normal 400 1em/1 '@{fa-style-family}';
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Font Awesome 6 Free';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: @fa-font-display;
|
||||
src: url('@{fa-font-path}/fa-regular-400.woff2') format('woff2'),
|
||||
url('@{fa-font-path}/fa-regular-400.ttf') format('truetype');
|
||||
}
|
||||
|
||||
.far,
|
||||
.@{fa-css-prefix}-regular {
|
||||
font-weight: 400;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*!
|
||||
* Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2024 Fonticons, Inc.
|
||||
*/
|
||||
@import "_variables.less";
|
||||
|
||||
:root, :host {
|
||||
--@{fa-css-prefix}-style-family-classic: '@{fa-style-family}';
|
||||
--@{fa-css-prefix}-font-solid: normal 900 1em/1 '@{fa-style-family}';
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Font Awesome 6 Free';
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
font-display: @fa-font-display;
|
||||
src: url('@{fa-font-path}/fa-solid-900.woff2') format('woff2'),
|
||||
url('@{fa-font-path}/fa-solid-900.ttf') format('truetype');
|
||||
}
|
||||
|
||||
.fas,
|
||||
.@{fa-css-prefix}-solid {
|
||||
font-weight: 900;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
/*!
|
||||
* Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2024 Fonticons, Inc.
|
||||
*/
|
||||
// V4 shims compile (Web Fonts-based)
|
||||
// -------------------------
|
||||
|
||||
@import '_variables.less';
|
||||
@import '_shims.less';
|
||||