7.21 big change
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M12 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-4.5 4c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm9 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-9.5 3.5c-1.38 0-2.5 1.12-2.5 2.5s1.12 2.5 2.5 2.5 2.5-1.12 2.5-2.5-1.12-2.5-2.5-2.5zm11 0c-1.38 0-2.5 1.12-2.5 2.5s1.12 2.5 2.5 2.5 2.5-1.12 2.5-2.5-1.12-2.5-2.5-2.5zM12 18c-2.21 0-4 1.79-4 4h8c0-2.21-1.79-4-4-4z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 466 B |
@@ -1,18 +0,0 @@
|
||||
import { route } from "preact-router"
|
||||
|
||||
const Dashboard = () => {
|
||||
return (
|
||||
<div class="app-dashboard">
|
||||
<div class="dashboard-sidebar">
|
||||
<a href="/dashboard/datasets" onClick={(e) => { e.preventDefault(); route("/dashboard/datasets") }}>训练集管理</a>
|
||||
<a href="/dashboard/testsets" onClick={(e) => { e.preventDefault(); route("/dashboard/testsets") }}>测试集管理</a>
|
||||
<a href="/dashboard/logs" onClick={(e) => { e.preventDefault(); route("/dashboard/logs") }}>训练日志</a>
|
||||
</div>
|
||||
<div class="dashboard-content">
|
||||
{/* 子页面内容通过 Router 渲染到这里 */}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Dashboard
|
||||
@@ -1,11 +1,9 @@
|
||||
export const Footer = () => {
|
||||
return (
|
||||
<footer class="app-footer">
|
||||
<span>https://pytorch.org/</span>
|
||||
<span>|</span>
|
||||
<span>https://wails.io/</span>
|
||||
<span>|</span>
|
||||
<span>https://preactjs.com/</span>
|
||||
</footer>
|
||||
)
|
||||
}
|
||||
export const Footer = () => (
|
||||
<footer class="app-footer">
|
||||
<span>📩 xiadongliang88@163.com</span>
|
||||
<span>|</span>
|
||||
<span>📦 https://git.leonstack.com/owner</span>
|
||||
<span>|</span>
|
||||
<span>🌏 https://www.leonstack.com/</span>
|
||||
</footer>
|
||||
)
|
||||
|
||||
@@ -1,82 +1,95 @@
|
||||
import { useState, useEffect } from 'preact/hooks'
|
||||
import { message } from '../utils/toast'
|
||||
import Pagination from './Pagination'
|
||||
|
||||
const formatDate = (timestamp: number) => {
|
||||
const date = new Date(timestamp * 1000)
|
||||
return date.toLocaleString('zh-CN', {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit',
|
||||
})
|
||||
}
|
||||
|
||||
const historyList = [
|
||||
{
|
||||
id: 1,
|
||||
breeds: '英短&1212',
|
||||
desc: 'The Maine Coon is a large, friendly cat breed known for its tufted ears.',
|
||||
img: '../../',
|
||||
date: 'Jan 15, 2024',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
breeds: '英短&fdfd',
|
||||
desc: 'The Maine Coon is a large, friendly cat breed known for its tufted ears.',
|
||||
img: '../../',
|
||||
date: 'Jan 15, 2024',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
breeds: '英短&11111',
|
||||
desc: 'The Maine Coon is a large, friendly cat breed known for its tufted ears.',
|
||||
img: '../../',
|
||||
date: 'Jan 15, 2024',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
breeds: '英短&4545',
|
||||
desc: 'The Maine Coon is a large, friendly cat breed known for its tufted ears.',
|
||||
img: '../../',
|
||||
date: 'Jan 15, 2024',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
breeds: '英短&fff',
|
||||
desc: 'The Maine Coon is a large, friendly cat breed known for its tufted ears.',
|
||||
img: '../../',
|
||||
date: 'Jan 15, 2024',
|
||||
},
|
||||
]
|
||||
interface IHistoryItem {
|
||||
id: number
|
||||
img: string
|
||||
breed: number
|
||||
date: number
|
||||
name: string
|
||||
brief: string
|
||||
}
|
||||
|
||||
const History = () => {
|
||||
const [page, setPage] = useState<number>(1)
|
||||
const pageSize = 5
|
||||
const [total, setTotal] = useState<number>(50)
|
||||
const [historyList, setHistoryList] = useState<IHistoryItem[]>([])
|
||||
|
||||
useEffect(() => {
|
||||
if (!(window as any).go?.main?.App?.GetHistory) {
|
||||
message.error('Wails runtime not ready')
|
||||
return
|
||||
}
|
||||
fetchData(page)
|
||||
}, [])
|
||||
|
||||
const handlePageChange = (page: number) => {
|
||||
// setPage(page)
|
||||
// loadTranscript(currentNav, currentOpt, page).then(res => {
|
||||
// if (res && res.code === 0) {
|
||||
// setData(res.data.data)
|
||||
// setTotal(res.data.total)
|
||||
// }
|
||||
// }).catch(e => message.error(e.toString()))
|
||||
const fetchData = async(page: number) => {
|
||||
const result = await (window as any).go.main.App.GetHistory(page, pageSize)
|
||||
if (result.code === 0) {
|
||||
setHistoryList(result.data.list)
|
||||
setTotal(result.data.total)
|
||||
} else if (result.code === 1) {
|
||||
message.error(result.message)
|
||||
}
|
||||
}
|
||||
|
||||
const handlePageChange = (page: number) => {
|
||||
setPage(page)
|
||||
fetchData(page)
|
||||
}
|
||||
|
||||
const handleDelete = async(id: number) => {
|
||||
const result = await (window as any).go.main.App.DeleteOneHistory(id)
|
||||
if (result.code === 0) {
|
||||
message.success('删除成功')
|
||||
fetchData(page)
|
||||
} else if (result.code === 1) {
|
||||
message.error(result.message)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div class="app-history">
|
||||
{historyList.map((item) =>
|
||||
<div class="history-clear">
|
||||
<a>清除全部</a>
|
||||
</div>
|
||||
{historyList.map((item: IHistoryItem) =>
|
||||
<div key={item.id} class="history-card">
|
||||
<div class="card-left">
|
||||
<img src="../assets/images/0012.jpg" />
|
||||
</div>
|
||||
<div class="card-right">
|
||||
<div class="right-top">
|
||||
<h3>{item.breeds}</h3>
|
||||
<span>{item.date}</span>
|
||||
<h3>{item.name}</h3>
|
||||
<div class="card-actions">
|
||||
<span>{formatDate(item.date)}</span>
|
||||
<button onClick={() => handleDelete(item.id)} title="删除">
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right-overview">
|
||||
{item.desc}
|
||||
{item.brief}
|
||||
</div>
|
||||
</div>
|
||||
</div>)
|
||||
}
|
||||
|
||||
<div class="history-pagination">
|
||||
<Pagination page={page} pagesize={5} total={total} onChange={handlePageChange} />
|
||||
<Pagination page={page} pagesize={pageSize} total={total} onChange={handlePageChange} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -1,16 +1,22 @@
|
||||
import { useState, useEffect, useRef } from 'preact/hooks'
|
||||
import { useState, useRef } from 'preact/hooks'
|
||||
import { message } from '../utils/toast'
|
||||
|
||||
interface IDetectResult {
|
||||
id: number
|
||||
code: string
|
||||
name: number
|
||||
brief: string
|
||||
confidence_level: number
|
||||
}
|
||||
|
||||
const Main = () => {
|
||||
const fileInputRef = useRef<HTMLInputElement>(null)
|
||||
const [fileName, setFileName] = useState<string>('')
|
||||
const [fileSrc, setFileSrc] = useState<string>('')
|
||||
const [step, setStep] = useState<number>(0)
|
||||
const [detectResult, setDetectResult] = useState<IDetectResult | null>(null)
|
||||
|
||||
const [step, setStep] = useState(0)
|
||||
|
||||
const handleUploadClick = () => {
|
||||
fileInputRef.current?.click()
|
||||
}
|
||||
const handleUploadClick = () => fileInputRef.current?.click()
|
||||
|
||||
const handleFileChange = (e: Event) => {
|
||||
const target = e.target as HTMLInputElement
|
||||
@@ -56,13 +62,20 @@ const Main = () => {
|
||||
const handleDetect = () => {
|
||||
setStep(2)
|
||||
|
||||
setTimeout(() => {
|
||||
setStep(3)
|
||||
setTimeout(async() => {
|
||||
const result = await (window as any).go.main.App.Detect(fileName)
|
||||
if (result.code === 0) {
|
||||
setDetectResult(result.data)
|
||||
setStep(3)
|
||||
} else if (result.code === 1) {
|
||||
message.error(result.message)
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
const handleTryOther = () => {
|
||||
setStep(0)
|
||||
setDetectResult(null)
|
||||
resetUpload()
|
||||
}
|
||||
|
||||
@@ -74,9 +87,14 @@ const Main = () => {
|
||||
发现<span>它</span>的<span>分类</span>
|
||||
</h1>
|
||||
<p>
|
||||
上传一张猫咪照片,让AI不仅认出它<span>是什么</span>
|
||||
上传一张猫咪照片,让AI认出它<span>是什么</span>
|
||||
</p>
|
||||
<i>基于深度残差网络</i>
|
||||
<i>
|
||||
<svg viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/>
|
||||
</svg>
|
||||
<span>基于深度残差网络</span>
|
||||
</i>
|
||||
</div>
|
||||
<div class={`upload${!(step == 0 || step == 1 || step == 2) ? ' hidden' : ''}`}>
|
||||
<div
|
||||
@@ -125,7 +143,7 @@ const Main = () => {
|
||||
}
|
||||
</div>
|
||||
{fileSrc.length > 0 && step == 1 ?
|
||||
<button id="detectBtn" onClick={handleDetect}>
|
||||
<button onClick={handleDetect}>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
@@ -142,60 +160,30 @@ const Main = () => {
|
||||
<svg viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" />
|
||||
</svg>
|
||||
<h2>检测完成!</h2>
|
||||
<h2>完成!</h2>
|
||||
</div>
|
||||
<div class="result-main">
|
||||
<img />
|
||||
<div class="result-word">
|
||||
<div>
|
||||
<h3>异国短毛猫</h3>
|
||||
<h3>{detectResult?.name}</h3>
|
||||
<div>
|
||||
<div class="probability-bar">
|
||||
<div />
|
||||
</div>
|
||||
<span>可信度 78%</span>
|
||||
<span>置信度 {detectResult ? detectResult.confidence_level * 100 + '%' : ''}</span>
|
||||
</div>
|
||||
</div>
|
||||
<h4>关于英短</h4>
|
||||
<p>尽量快点附近的路口附近的联发科九点零分肌肤的路口附近登陆反对浪费空间 尽量快点附近的路口附近的联发科九点零分肌肤的路口附近登陆反对浪费空间</p>
|
||||
<p>{detectResult?.brief}</p>
|
||||
</div>
|
||||
</div>
|
||||
<button onClick={handleTryOther}>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99" />
|
||||
</svg>
|
||||
再试一张
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* <div id="featuresSection" class="grid grid-cols-1 md:grid-cols-3 gap-6 mt-16">
|
||||
<div class="bg-white rounded-2xl border border-border p-6 text-center cursor-pointer hover:shadow-lg transition-shadow duration-200">
|
||||
<div class="w-14 h-14 mx-auto mb-4 bg-primary/10 rounded-2xl flex items-center justify-center">
|
||||
<svg class="w-7 h-7 text-primary" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 13.5l10.5-11.25L12 10.5h8.25L9.75 21.75 12 13.5H3.75z" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="font-heading font-semibold text-lg text-text mb-2">Lightning Fast</h3>
|
||||
<p class="text-text/60 text-sm">Get results in under 3 seconds with our optimized AI model</p>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-2xl border border-border p-6 text-center cursor-pointer hover:shadow-lg transition-shadow duration-200">
|
||||
<div class="w-14 h-14 mx-auto mb-4 bg-cta/10 rounded-2xl flex items-center justify-center">
|
||||
<svg class="w-7 h-7 text-cta" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9 6.75V15m6-6v8.25m.503 3.498l4.875-2.437c.381-.19.622-.58.622-1.006V4.82c0-.836-.88-1.38-1.628-1.006l-3.869 1.934c-.317.159-.69.159-1.006 0L9.503 3.252a1.125 1.125 0 00-1.006 0L3.622 5.689C3.24 5.88 3 6.27 3 6.695V19.18c0 .836.88 1.38 1.628 1.006l3.869-1.934c.317-.159.69-.159 1.006 0l4.994 2.497c.317.158.69.158 1.006 0z" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="font-heading font-semibold text-lg text-text mb-2">98% Accuracy</h3>
|
||||
<p class="text-text/60 text-sm">Trained on 50,000+ cat images across 60+ breeds</p>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-2xl border border-border p-6 text-center cursor-pointer hover:shadow-lg transition-shadow duration-200">
|
||||
<div class="w-14 h-14 mx-auto mb-4 bg-green-100 rounded-2xl flex items-center justify-center">
|
||||
<svg class="w-7 h-7 text-green-600" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 21a9.004 9.004 0 008.716-6.747M12 21a9.004 9.004 0 01-8.716-6.747M12 21c2.485 0 4.5-4.03 4.5-9S14.485 3 12 3m0 18c-2.485 0-4.5-4.03-4.5-9S9.515 3 12 3m0 0a8.997 8.997 0 017.843 4.582M12 3a8.997 8.997 0 00-7.843 4.582m15.686 0A11.953 11.953 0 0112 10.5c-2.998 0-5.74-1.1-7.843-2.918m15.686 0A8.959 8.959 0 0121 12c0 .778-.099 1.533-.284 2.253m0 0A17.919 17.919 0 0112 16.5c-3.162 0-6.133-.815-8.716-2.247m0 0A9.015 9.015 0 013 12c0-1.605.42-3.113 1.157-4.418" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="font-heading font-semibold text-lg text-text mb-2">Always Free</h3>
|
||||
<p class="text-text/60 text-sm">No hidden fees, no subscriptions. Detect away!</p>
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
</main>
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export const Navbar = () => {
|
||||
const svgPath = "M12 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-4.5 4c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm9 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-9.5 3.5c-1.38 0-2.5 1.12-2.5 2.5s1.12 2.5 2.5 2.5 2.5-1.12 2.5-2.5-1.12-2.5-2.5-2.5zm11 0c-1.38 0-2.5 1.12-2.5 2.5s1.12 2.5 2.5 2.5 2.5-1.12 2.5-2.5-1.12-2.5-2.5-2.5zM12 18c-2.21 0-4 1.79-4 4h8c0-2.21-1.79-4-4-4z"
|
||||
|
||||
const handleClick = () => window.open('https://git.leonstack.com/Leon/Collage-Images', '_blank')
|
||||
const handleClick = () => window.open('https://git.leonstack.com/owner/Collage-Images', '_blank')
|
||||
|
||||
return (
|
||||
<nav class="app-navbar animate-fade-in">
|
||||
@@ -10,13 +10,12 @@ export const Navbar = () => {
|
||||
<svg class="icon" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d={svgPath} />
|
||||
</svg>
|
||||
<span class="font-heading font-semibold text-xl text-text">分类miao</span>
|
||||
<span class="font-heading font-semibold text-xl text-text">分类喵</span>
|
||||
</div>
|
||||
<div class="container-right">
|
||||
<a href="/">主页</a>
|
||||
<a href="/history">历史记录</a>
|
||||
<a href="/dashboard">后台管理</a>
|
||||
<button onClick={handleClick}>代码仓库</button>
|
||||
<button onClick={handleClick}>查看代码</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@@ -45,14 +45,17 @@ const Pagination = ({
|
||||
|
||||
const handleEnterPress = (e: KeyboardEvent) => {
|
||||
if (e.key === 'Enter') {
|
||||
if (parseInt(value) <= seqNums.length && parseInt(value) > 0) {
|
||||
handleChangeNum(parseInt(value))
|
||||
} else if (parseInt(value) >= seqNums.length) {
|
||||
const target = e.target as HTMLInputElement
|
||||
const page = parseInt(target.value)
|
||||
if (page >= 1 && page <= seqNums.length) {
|
||||
handleChangeNum(page)
|
||||
onChange(page)
|
||||
} else if (page > seqNums.length) {
|
||||
handleChangeNum(seqNums.length)
|
||||
} else if (parseInt(value) < seqNums.length) {
|
||||
handleChangeNum(1)
|
||||
onChange(seqNums.length)
|
||||
} else {
|
||||
handleChangeNum(1)
|
||||
onChange(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
const TestsetManagement = () => {
|
||||
return (
|
||||
<div></div>
|
||||
)
|
||||
}
|
||||
|
||||
export default TestsetManagement
|
||||
@@ -1,7 +0,0 @@
|
||||
const TrainsetManagement = () => {
|
||||
return (
|
||||
<div></div>
|
||||
)
|
||||
}
|
||||
|
||||
export default TrainsetManagement
|
||||
@@ -2,26 +2,18 @@ import { Router, Route } from "preact-router"
|
||||
import { Navbar } from "../components/Navbar"
|
||||
import Main from "../components/Main"
|
||||
import History from "../components/History"
|
||||
import Dashboard from "../components/Dashboard"
|
||||
import TrainsetManagement from "../components/TrainsetManagement"
|
||||
import TestsetManagement from "../components/TestsetManagement"
|
||||
import { Footer } from "../components/Footer"
|
||||
import '../styles/base.sass'
|
||||
import '../styles/history.sass'
|
||||
import '../styles/pagination.sass'
|
||||
import '../styles/dashboard.sass'
|
||||
|
||||
|
||||
export function App(props: any) {
|
||||
export function App() {
|
||||
return (
|
||||
<div id="App">
|
||||
<Navbar />
|
||||
<Router>
|
||||
<Route path="/" component={Main} />
|
||||
<Route path="/dashboard" component={Dashboard} />
|
||||
<Route path="/history" component={History} />
|
||||
<Route path="/dashboard/datasets" component={TrainsetManagement} />
|
||||
<Route path="/dashboard/testsets" component={TestsetManagement} />
|
||||
</Router>
|
||||
<Footer />
|
||||
</div>
|
||||
|
||||
@@ -6,6 +6,7 @@ body
|
||||
margin: 0
|
||||
color: white
|
||||
font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI"
|
||||
overflow: hidden
|
||||
|
||||
@font-face
|
||||
font-family: "Nunito"
|
||||
@@ -17,11 +18,16 @@ body
|
||||
font-family: "ZcoolHappy"
|
||||
src: url("../assets/fonts/站酷快乐体.ttf") format("truetype")
|
||||
|
||||
@font-face
|
||||
font-family: "SANS_SC_BOLD"
|
||||
src: url("../assets/fonts/HARMONYOS_SANS_SC_BOLD.TTF") format("truetype")
|
||||
|
||||
:root
|
||||
--primary: #3B82F6
|
||||
--title: #1e293b
|
||||
--text:#5f6874
|
||||
--textsub: #878d95
|
||||
--sub-title: #5f6874
|
||||
--text:#5D5D5D
|
||||
--textsub: #979797
|
||||
|
||||
#app
|
||||
height: 100vh
|
||||
@@ -41,7 +47,7 @@ body
|
||||
width: 100%
|
||||
margin: 0 auto
|
||||
padding: 0.6rem 1.2rem
|
||||
background-color: #FFFFFF
|
||||
background-color: white
|
||||
backdrop-filter: blur(8px)
|
||||
border-radius: 0.6rem
|
||||
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)
|
||||
@@ -77,7 +83,7 @@ body
|
||||
width: 7rem
|
||||
height: 2.6rem
|
||||
margin-left: 1.5rem
|
||||
color: #FFFFFF
|
||||
color: white
|
||||
font-size: 0.9375rem
|
||||
background-color: var(--primary)
|
||||
border-radius: 0.5rem
|
||||
@@ -113,7 +119,7 @@ body
|
||||
|
||||
> p
|
||||
text-align: center
|
||||
color: var(--text)
|
||||
color: var(--sub-title)
|
||||
font-size: 1.0625rem
|
||||
margin-bottom: 1rem
|
||||
max-width: 42rem
|
||||
@@ -123,6 +129,8 @@ body
|
||||
color: var(--primary)
|
||||
|
||||
> i
|
||||
display: flex
|
||||
align-items: center
|
||||
font-style: normal
|
||||
text-align: center
|
||||
color: #FFD572
|
||||
@@ -130,7 +138,12 @@ body
|
||||
margin: 0 auto
|
||||
padding: 0.25rem 0.75rem
|
||||
background-color: #38383D
|
||||
border-radius: 0.2rem
|
||||
border-radius: 0.25rem
|
||||
gap: 0.25rem
|
||||
|
||||
> svg
|
||||
width: 0.625rem
|
||||
height: 0.625rem
|
||||
|
||||
.upload
|
||||
width: 32rem
|
||||
@@ -147,7 +160,6 @@ body
|
||||
border-width: 2px
|
||||
border-style: dashed
|
||||
border-color: #e2e8f0
|
||||
border-style: dashed
|
||||
text-align: center
|
||||
cursor: pointer
|
||||
|
||||
@@ -175,8 +187,7 @@ body
|
||||
|
||||
> img
|
||||
max-height: 10.5rem
|
||||
margin-left: auto
|
||||
margin-right: auto
|
||||
margin: 0 auto
|
||||
margin-bottom: 0.25rem
|
||||
border-radius: 1rem
|
||||
object-fit: cover
|
||||
@@ -195,7 +206,7 @@ body
|
||||
.zone-loading
|
||||
padding: 2rem
|
||||
text-align: center
|
||||
background-color: #FFFFFF
|
||||
background-color: white
|
||||
border-radius: 1.5rem
|
||||
|
||||
.loading-spinner
|
||||
@@ -223,25 +234,26 @@ body
|
||||
font-size: 1rem
|
||||
color: var(--textsub)
|
||||
|
||||
>button#detectBtn
|
||||
width: 12rem
|
||||
height: 3.5rem
|
||||
> button
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
width: 9rem
|
||||
height: 3rem
|
||||
margin: 1rem auto 0 auto
|
||||
background-color: var(--primary)
|
||||
color: white
|
||||
font-weight: 600
|
||||
font-size: 1.125rem
|
||||
border-radius: 0.75rem
|
||||
border-radius: 0.5rem
|
||||
transition: background-color 200ms, color 200ms
|
||||
cursor: pointer
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
gap: 0.5rem
|
||||
|
||||
gap: 0.25rem
|
||||
|
||||
> svg
|
||||
width: 1.5rem
|
||||
height: 1.5rem
|
||||
width: 1.25rem
|
||||
height: 1.25rem
|
||||
|
||||
.result
|
||||
width: 35rem
|
||||
@@ -251,6 +263,7 @@ body
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
height: 2.25rem
|
||||
gap: 0.75rem
|
||||
margin-bottom: 1.5rem
|
||||
|
||||
@@ -260,8 +273,8 @@ body
|
||||
color: var(--primary)
|
||||
|
||||
> h2
|
||||
font-family: "ZcoolHappy"
|
||||
font-weight: 700
|
||||
font-family: "SANS_SC_BOLD"
|
||||
font-weight: bold
|
||||
font-size: 1.5rem
|
||||
color: var(--title)
|
||||
|
||||
@@ -270,7 +283,7 @@ body
|
||||
min-height: 10rem
|
||||
padding: 1rem 1rem
|
||||
margin-bottom: 1.5rem
|
||||
background-color: #ffffff
|
||||
background-color: white
|
||||
border-radius: 1rem
|
||||
border: 1px solid var(--color-border)
|
||||
gap: 2rem
|
||||
@@ -293,7 +306,7 @@ body
|
||||
justify-content: space-between
|
||||
align-items: center
|
||||
width: 100%
|
||||
padding-bottom: 1rem
|
||||
padding-bottom: 0.75rem
|
||||
margin-bottom: 1rem
|
||||
border-bottom: 1px solid #c6c6c6
|
||||
|
||||
@@ -333,14 +346,6 @@ body
|
||||
|
||||
> span
|
||||
color: var(--title)
|
||||
// font-size: 0.725rem
|
||||
|
||||
> h4
|
||||
color: var(--title)
|
||||
text-align: left
|
||||
font-size: 1rem
|
||||
font-weight: bold
|
||||
margin-bottom: 0.5rem
|
||||
|
||||
> p
|
||||
color: var(--text)
|
||||
@@ -348,17 +353,24 @@ body
|
||||
font-size: 0.875rem
|
||||
|
||||
> button
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
width: 9rem
|
||||
height: 3rem
|
||||
background-color: var(--primary)
|
||||
margin: 0 auto
|
||||
color: white
|
||||
font-weight: 600
|
||||
font-size: 1.125rem
|
||||
background-color: var(--primary)
|
||||
border-radius: 0.5rem
|
||||
transition: background-color 200ms, color 200ms
|
||||
cursor: pointer
|
||||
gap: 0.25rem
|
||||
|
||||
|
||||
> svg
|
||||
width: 1.25rem
|
||||
height: 1.25rem
|
||||
|
||||
.app-footer
|
||||
display: flex
|
||||
@@ -375,56 +387,44 @@ body
|
||||
font-size: 0.8rem
|
||||
margin: 0 0.5rem
|
||||
|
||||
@media (prefers-reduced-motion: reduce)
|
||||
.animate-fade-in,
|
||||
.animate-slide-up,
|
||||
.animate-pulse-slow
|
||||
animation: none !important
|
||||
transition: none !important
|
||||
.message
|
||||
width: 100%
|
||||
height: 2rem
|
||||
position: fixed
|
||||
top: 6.25rem
|
||||
z-index: 1000
|
||||
background: none
|
||||
-moz-transition: all 0.5s ease-in
|
||||
-webkit-transition: all 0.5s ease-in
|
||||
-o-transition: all 0.5s ease-in
|
||||
transition: all 0.5s ease-in
|
||||
|
||||
@keyframes fadeIn
|
||||
from
|
||||
opacity: 0
|
||||
to
|
||||
opacity: 1
|
||||
.success, .error
|
||||
display: inline-flex
|
||||
justify-content: center
|
||||
align-items: center
|
||||
height: 2rem
|
||||
margin: 0 auto
|
||||
padding: 0 1.125rem
|
||||
font-size: 0.875rem
|
||||
background: white
|
||||
border: 1px solid var(--border)
|
||||
border-radius: 0.375rem
|
||||
box-shadow: 0rem 0.25rem 0.25rem rgb(0 0 0 / 0.1)
|
||||
gap: 0.25rem
|
||||
|
||||
@keyframes slideUp
|
||||
from
|
||||
opacity: 0
|
||||
transform: translateY(20px)
|
||||
to
|
||||
opacity: 1
|
||||
transform: translateY(0)
|
||||
> span
|
||||
width: 1rem
|
||||
height: 1rem
|
||||
|
||||
@keyframes pulseSlow
|
||||
0%, 100%
|
||||
opacity: 1
|
||||
50%
|
||||
opacity: 0.7
|
||||
> svg
|
||||
width: 1rem
|
||||
height: 1rem
|
||||
line-height: 2rem
|
||||
|
||||
.animate-fade-in
|
||||
animation: fadeIn 0.3s ease-out forwards
|
||||
|
||||
.animate-slide-up
|
||||
animation: slideUp 0.4s ease-out forwards
|
||||
|
||||
.animate-pulse-slow
|
||||
animation: pulseSlow 2s ease-in-out infinite
|
||||
|
||||
.drop-zone
|
||||
transition: all 0.2s ease-out
|
||||
|
||||
.drop-zone.dragover
|
||||
border-color: #3B82F6
|
||||
background-color: #EFF6FF
|
||||
transform: scale(1.01)
|
||||
|
||||
.breed-card
|
||||
transition: all 0.2s ease-out
|
||||
|
||||
&:hover
|
||||
transform: translateY(-4px)
|
||||
box-shadow: 0 12px 24px -8px rgba(59, 130, 246, 0.25)
|
||||
|
||||
.confidence-bar
|
||||
transition: width 0.8s ease-out
|
||||
> p
|
||||
max-width: 24rem
|
||||
color: var(--text)
|
||||
overflow: hidden
|
||||
white-space: nowrap
|
||||
text-overflow: ellipsis
|
||||
@@ -1,26 +0,0 @@
|
||||
.app-dashboard
|
||||
display: flex
|
||||
height: 648px
|
||||
padding: 7rem 1.5rem 4rem 1.5rem
|
||||
|
||||
.dashboard-sidebar
|
||||
display: flex
|
||||
flex-direction: column
|
||||
align-items: center
|
||||
width: 18%
|
||||
height: 100%
|
||||
border-right: 1px solid #9AAAC6
|
||||
|
||||
> a
|
||||
display: inline-flex
|
||||
height: 2.5rem
|
||||
line-height: 2.5rem
|
||||
font-size: 0.9375rem
|
||||
color: #8E8E8E
|
||||
border-bottom: 1px solid #9AAAC6
|
||||
cursor: pointer
|
||||
|
||||
.dashboard-content
|
||||
width: 82%
|
||||
height: 100%
|
||||
// background-color: #555
|
||||
@@ -3,7 +3,18 @@
|
||||
flex-direction: column
|
||||
align-items: center
|
||||
height: 651px
|
||||
padding: 7rem 1rem 4rem 1rem
|
||||
padding: 6.5rem 1rem 4rem 1rem
|
||||
|
||||
.history-clear
|
||||
width: calc(100% - 20rem)
|
||||
text-align: right
|
||||
margin-bottom: 0.5rem
|
||||
|
||||
> a
|
||||
font-size: 0.875rem
|
||||
color: var(--primary)
|
||||
cursor: pointer
|
||||
// text-decoration: underline
|
||||
|
||||
.history-card
|
||||
display: flex
|
||||
@@ -33,15 +44,39 @@
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: space-between
|
||||
gap: 1rem
|
||||
|
||||
> h3
|
||||
width: 6rem
|
||||
color: #333333
|
||||
font-size: 1rem
|
||||
font-weight: bold
|
||||
text-align: left
|
||||
|
||||
> span
|
||||
color: #cccccc
|
||||
font-size: 0.8rem
|
||||
.card-actions
|
||||
display: flex
|
||||
flex: 1
|
||||
justify-content: space-between
|
||||
align-items: flex-start
|
||||
gap: 0.75rem
|
||||
|
||||
> span
|
||||
color: #cccccc
|
||||
font-size: 0.8rem
|
||||
|
||||
> button
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
width: 1rem
|
||||
height: 1rem
|
||||
font-size: 1rem
|
||||
padding: 0
|
||||
background: none
|
||||
border: none
|
||||
border-radius: 0.35rem
|
||||
color: #9ca3af
|
||||
cursor: pointer
|
||||
|
||||
.right-overview
|
||||
width: 100%
|
||||
@@ -49,9 +84,12 @@
|
||||
color: #cccccc
|
||||
font-size: 0.9rem
|
||||
text-align: left
|
||||
overflow: hidden
|
||||
text-overflow: ellipsis
|
||||
white-space: nowrap
|
||||
|
||||
.history-pagination
|
||||
width: calc(100% - 20rem)
|
||||
margin-top: 1rem
|
||||
margin-top: 0.5rem
|
||||
|
||||
|
||||
|
||||
@@ -59,7 +59,6 @@
|
||||
|
||||
.pagination-word
|
||||
font-size: 0.75rem
|
||||
font-weight: bold
|
||||
margin: 0 0.3125rem 0 0.3125rem
|
||||
color: #333333
|
||||
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
interface MessageAPI {
|
||||
success: (text: string) => void
|
||||
error: (text: string) => void
|
||||
}
|
||||
|
||||
export const message: MessageAPI = {
|
||||
success: (text: string) => {
|
||||
const div = document.createElement('div')
|
||||
div.className = 'message'
|
||||
|
||||
const subDiv = document.createElement('div')
|
||||
subDiv.className = 'success'
|
||||
|
||||
const subSpan = document.createElement('span')
|
||||
subSpan.innerHTML = `<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="10" cy="10" r="9" fill="#22c55e"/><path d="M6 10L9 13L14 7" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>`
|
||||
|
||||
const subP = document.createElement('p')
|
||||
subP.innerText = text
|
||||
|
||||
subDiv.appendChild(subSpan)
|
||||
subDiv.appendChild(subP)
|
||||
|
||||
div.appendChild(subDiv)
|
||||
document.body.appendChild(div)
|
||||
|
||||
setTimeout(() => {
|
||||
div.remove()
|
||||
}, 3000)
|
||||
},
|
||||
error: (text: string) => {
|
||||
const div = document.createElement('div')
|
||||
div.className = 'message'
|
||||
|
||||
const subDiv = document.createElement('div')
|
||||
subDiv.className = 'error'
|
||||
|
||||
const subSpan = document.createElement('span')
|
||||
subSpan.innerHTML = `<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="10" cy="10" r="9" fill="#ef4444"/><path d="M7 7L13 13M13 7L7 13" stroke="white" stroke-width="2" stroke-linecap="round"/></svg>`
|
||||
|
||||
const subP = document.createElement('p')
|
||||
subP.innerText = text
|
||||
|
||||
subDiv.appendChild(subSpan)
|
||||
subDiv.appendChild(subP)
|
||||
|
||||
div.appendChild(subDiv)
|
||||
document.body.appendChild(div)
|
||||
|
||||
setTimeout(() => {
|
||||
div.remove()
|
||||
}, 3000)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user