mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-01 12:06:38 +08:00
Update MediaStationGo branding and deployment docs
This commit is contained in:
+1
-1
@@ -113,7 +113,7 @@ class AppErrorBoundary extends Component<{ children: ReactNode }, { hasError: bo
|
||||
}
|
||||
|
||||
componentDidCatch(error: Error, info: ErrorInfo) {
|
||||
console.error('MediaStation UI crashed', error, info)
|
||||
console.error('MediaStationGo UI crashed', error, info)
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { api } from './client'
|
||||
|
||||
// ── License Server types (generic, ready for MediaStationLicenseServer integration) ──
|
||||
// ── License Server types (generic, ready for MediaStationGo license integration) ──
|
||||
|
||||
/** Response after binding/activating a license. */
|
||||
export interface LicenseActivation {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Link, NavLink, Outlet, useLocation, useNavigate } from 'react-router-do
|
||||
import { AnimatePresence, motion } from 'framer-motion'
|
||||
import toast from 'react-hot-toast'
|
||||
import {
|
||||
Activity, Bell, Clock, CloudDownload, Compass, Film,
|
||||
Activity, Bell, Clock, CloudDownload, Compass,
|
||||
Cast, Globe, HardDrive, Heart, Home, Image, KeySquare,
|
||||
ListMusic, LogOut, Rss, Search, Trash2,
|
||||
Settings, Sliders, Sparkles, UserCog,
|
||||
@@ -139,16 +139,18 @@ export function Layout() {
|
||||
{/* Brand Logo & Brand Title */}
|
||||
<div className="flex h-20 items-center justify-between px-6 border-b border-gray-100">
|
||||
<Link to="/" className="flex items-center gap-3">
|
||||
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-gradient-to-br from-[#111827] to-[#1f2937] shadow-sm">
|
||||
<Film className="h-5 w-5 text-[#c9954a]" />
|
||||
</div>
|
||||
<img
|
||||
src="/brand/mgo-emby-icon.png"
|
||||
alt="MediaStationGo"
|
||||
className="h-10 w-10 shrink-0 rounded-xl object-contain shadow-sm"
|
||||
/>
|
||||
{(isSidebarOpen || isMobileDrawerOpen) && (
|
||||
<motion.span
|
||||
initial={{ opacity: 0, x: -10 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
className="font-display text-lg font-extrabold tracking-tight text-[#111827]"
|
||||
>
|
||||
MediaStation
|
||||
MediaStationGo
|
||||
</motion.span>
|
||||
)}
|
||||
</Link>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { motion } from 'framer-motion'
|
||||
import toast from 'react-hot-toast'
|
||||
import { Eye, EyeOff, Film, ArrowRight, ShieldCheck, Lock, User } from 'lucide-react'
|
||||
import { Eye, EyeOff, ArrowRight, ShieldCheck, Lock, User } from 'lucide-react'
|
||||
import { AppFooter } from '../components/AppFooter'
|
||||
import { authAPI } from '../api/auth'
|
||||
import { useAuthStore } from '../stores/auth'
|
||||
@@ -50,14 +50,14 @@ export function LoginPage() {
|
||||
|
||||
{/* Logo & Headline */}
|
||||
<div className="flex flex-col items-center text-center pb-8">
|
||||
<motion.div
|
||||
<motion.img
|
||||
initial={{ scale: 0.8, opacity: 0 }}
|
||||
animate={{ scale: 1, opacity: 1 }}
|
||||
transition={{ delay: 0.15, type: 'spring', stiffness: 200 }}
|
||||
className="mb-4 flex h-14 w-14 items-center justify-center rounded-2xl bg-[#111827] shadow-sm"
|
||||
>
|
||||
<Film className="h-7 w-7 text-[#c9954a]" />
|
||||
</motion.div>
|
||||
src="/brand/mgo-emby-icon.png"
|
||||
alt="MediaStationGo"
|
||||
className="mb-4 h-14 w-14 rounded-2xl object-contain shadow-sm"
|
||||
/>
|
||||
|
||||
<motion.h1
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
@@ -65,7 +65,7 @@ export function LoginPage() {
|
||||
transition={{ delay: 0.25 }}
|
||||
className="font-display text-2xl font-extrabold tracking-tight text-gray-900"
|
||||
>
|
||||
MediaStation
|
||||
MediaStationGo
|
||||
</motion.h1>
|
||||
|
||||
<motion.p
|
||||
@@ -195,4 +195,4 @@ export function LoginPage() {
|
||||
</motion.div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,6 +129,14 @@ const TYPE_LABELS: Record<NotifyChannel['type'], string> = {
|
||||
email: 'Email',
|
||||
}
|
||||
|
||||
const EVENT_OPTIONS = [
|
||||
{ value: 'subscription_hit', label: '订阅命中新资源' },
|
||||
{ value: 'download_complete', label: '下载任务完成' },
|
||||
{ value: 'library_ingest', label: '入库完成' },
|
||||
{ value: 'scrape_failed', label: '刮削失败告警' },
|
||||
{ value: 'system_alert', label: '系统异常通知' },
|
||||
]
|
||||
|
||||
function ChannelCard({
|
||||
channel,
|
||||
onTest,
|
||||
@@ -154,6 +162,7 @@ function ChannelCard({
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-1 truncate text-xs text-ink-50">{summary}</div>
|
||||
<div className="mt-1 truncate text-xs text-sand-500">{eventSummary(channel.events)}</div>
|
||||
</div>
|
||||
<div className="flex shrink-0 gap-2">
|
||||
<button
|
||||
@@ -179,6 +188,12 @@ function ChannelCard({
|
||||
)
|
||||
}
|
||||
|
||||
function eventSummary(events: string[] | undefined): string {
|
||||
if (!events || events.length === 0) return '事件:全部'
|
||||
const labels = events.map((event) => EVENT_OPTIONS.find((item) => item.value === event)?.label ?? event)
|
||||
return `事件:${labels.join('、')}`
|
||||
}
|
||||
|
||||
function channelSummary(ch: NotifyChannel): string {
|
||||
const cfg = ch.config ?? {}
|
||||
switch (ch.type) {
|
||||
@@ -245,6 +260,7 @@ function ChannelFormModal({
|
||||
const [config, setConfig] = useState<Record<string, string>>(
|
||||
normalizeInitialConfig(editing?.type ?? 'telegram', editing?.config ?? {}),
|
||||
)
|
||||
const [events, setEvents] = useState<string[]>(editing?.events ?? [])
|
||||
const [enabled, setEnabled] = useState(editing?.enabled ?? true)
|
||||
const [saving, setSaving] = useState(false)
|
||||
|
||||
@@ -275,6 +291,7 @@ function ChannelFormModal({
|
||||
name: name.trim(),
|
||||
type: type,
|
||||
config: cleanedConfig,
|
||||
events,
|
||||
enabled,
|
||||
}
|
||||
if (editing) {
|
||||
@@ -296,6 +313,12 @@ function ChannelFormModal({
|
||||
const updateConfig = (k: string, v: string) =>
|
||||
setConfig((c) => ({ ...c, [k]: v }))
|
||||
|
||||
const toggleEvent = (event: string) => {
|
||||
setEvents((current) =>
|
||||
current.includes(event) ? current.filter((item) => item !== event) : [...current, event],
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4 backdrop-blur-sm">
|
||||
<div className="glass-panel w-full max-w-lg max-h-[90vh] overflow-y-auto">
|
||||
@@ -532,6 +555,33 @@ function ChannelFormModal({
|
||||
</>
|
||||
)}
|
||||
|
||||
<Field label="推送事件">
|
||||
<div className="space-y-2 rounded-lg border border-gray-200 bg-gray-50/60 p-3">
|
||||
<label className="flex cursor-pointer items-center gap-2 text-sm text-ink-100">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="h-4 w-4 accent-primary-400"
|
||||
checked={events.length === 0}
|
||||
onChange={() => setEvents([])}
|
||||
/>
|
||||
全部事件
|
||||
</label>
|
||||
<div className="grid gap-2 sm:grid-cols-2">
|
||||
{EVENT_OPTIONS.map((event) => (
|
||||
<label key={event.value} className="flex cursor-pointer items-center gap-2 text-sm text-ink-100">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="h-4 w-4 accent-primary-400"
|
||||
checked={events.includes(event.value)}
|
||||
onChange={() => toggleEvent(event.value)}
|
||||
/>
|
||||
{event.label}
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</Field>
|
||||
|
||||
<label className="flex cursor-pointer items-center gap-2 text-sm text-ink-100">
|
||||
<input
|
||||
type="checkbox"
|
||||
|
||||
@@ -140,7 +140,7 @@ const GROUPS: SettingGroup[] = [
|
||||
{
|
||||
key: 'license',
|
||||
label: '授权服务',
|
||||
description: '连接私有 MediaStationLicenseServer;开源版默认最多 20 个用户,激活后按授权策略提升额度。',
|
||||
description: '连接私有 MediaStationGo 授权服务;开源版默认最多 20 个用户,激活后按授权策略提升额度。',
|
||||
items: [
|
||||
{
|
||||
key: 'license.server_url',
|
||||
|
||||
@@ -312,7 +312,7 @@ export interface NotifyChannel {
|
||||
name: string
|
||||
type: 'telegram' | 'wechat' | 'bark' | 'webhook' | 'email'
|
||||
enabled: boolean
|
||||
events: string
|
||||
events: string[]
|
||||
config: Record<string, string>
|
||||
created_at: string
|
||||
updated_at: string
|
||||
|
||||
Reference in New Issue
Block a user