diff --git a/app/Http/Controllers/Admin/AuthController.php b/app/Http/Controllers/Admin/AuthController.php index b4e4c23..38e2b12 100644 --- a/app/Http/Controllers/Admin/AuthController.php +++ b/app/Http/Controllers/Admin/AuthController.php @@ -156,6 +156,6 @@ class AuthController extends Controller private function loginRateLimiterKey(Request $request, string $username): string { - return Str::lower($username).'|'.$request->ip(); + return Str::lower($username) . '|' . $request->ip(); } } diff --git a/app/Http/Controllers/Admin/UploadController.php b/app/Http/Controllers/Admin/UploadController.php index 81ddfa4..0bf3049 100644 --- a/app/Http/Controllers/Admin/UploadController.php +++ b/app/Http/Controllers/Admin/UploadController.php @@ -42,7 +42,7 @@ class UploadController extends Controller public function markdownImage(Request $request): JsonResponse { $validated = $request->validate([ - 'image' => ['required', 'file', 'image', 'mimes:jpg,jpeg,png,webp,gif', 'max:'.self::MAX_FILE_KB], + 'image' => ['required', 'file', 'image', 'mimes:jpg,jpeg,png,webp,gif', 'max:' . self::MAX_FILE_KB], ], [ 'image.required' => '请选择要上传的图片。', 'image.image' => '仅支持图片文件上传。', @@ -77,22 +77,22 @@ class UploadController extends Controller $thumbBinary = $this->encodeWebp($thumbImage, self::THUMB_WEBP_QUALITY); $subDir = now()->format('Y/m/d'); - $baseName = now()->format('YmdHis').'-'.Str::lower(Str::random(8)); + $baseName = now()->format('YmdHis') . '-' . Str::lower(Str::random(8)); $mainPath = "markdown-images/{$subDir}/{$baseName}.webp"; $thumbPath = "markdown-images/{$subDir}/{$baseName}_thumb.webp"; Storage::disk('public')->put($mainPath, $mainBinary); Storage::disk('public')->put($thumbPath, $thumbBinary); - $mainUrl = '/storage/'.ltrim($mainPath, '/'); - $thumbUrl = '/storage/'.ltrim($thumbPath, '/'); + $mainUrl = '/storage/' . ltrim($mainPath, '/'); + $thumbUrl = '/storage/' . ltrim($thumbPath, '/'); return response()->json([ 'success' => true, 'url' => $mainUrl, 'thumb_url' => $thumbUrl, 'filename' => basename($mainPath), - 'markdown' => '![]('.$mainUrl.')', + 'markdown' => '![](' . $mainUrl . ')', ]); } catch (Throwable $exception) { report($exception); diff --git a/resources/css/home.css b/resources/css/home.css new file mode 100644 index 0000000..584c8b3 --- /dev/null +++ b/resources/css/home.css @@ -0,0 +1,1096 @@ +:root { + color-scheme: light; + --bg-page: #eef3fb; + --bg-surface: #ffffff; + --bg-soft: #f7f9ff; + --text-main: #121c2f; + --text-muted: #5f6f8b; + --brand: #3d5cff; + --brand-strong: #2b46e4; + --brand-soft: #e8edff; + --line: #d9e2f2; + --line-strong: #c8d6f0; + --radius-xl: 18px; + --radius-lg: 14px; + --radius-md: 10px; + --shadow-sm: 0 8px 20px rgba(29, 53, 116, .07); + --shadow-md: 0 14px 30px rgba(29, 53, 116, .12); + --page-max-width: 1480px; + --page-section-gap: .9rem; +} + +:root[data-theme="dark"] { + color-scheme: dark; + --bg-page: #0f1528; + --bg-surface: #141d35; + --bg-soft: #1a2747; + --text-main: #e7ecff; + --text-muted: #a5b1d6; + --brand: #6f88ff; + --brand-strong: #8ea3ff; + --brand-soft: #1c2a52; + --line: #27365f; + --line-strong: #334775; + --shadow-sm: 0 8px 20px rgba(4, 8, 20, .45); + --shadow-md: 0 14px 30px rgba(4, 8, 20, .58); +} + +html, +body { + min-height: 100%; +} + +body { + margin: 0; + font-family: "Noto Sans SC", "PingFang SC", "Microsoft YaHei", sans-serif; + color: var(--text-main); + background: + radial-gradient(circle at 12% -10%, #f8f3ff 0, rgba(248, 243, 255, 0) 45%), + radial-gradient(circle at 86% -12%, #e9f4ff 0, rgba(233, 244, 255, 0) 38%), + var(--bg-page); +} + +:root[data-theme="dark"] body { + background: + radial-gradient(circle at 12% -10%, rgba(67, 78, 136, .2) 0, rgba(67, 78, 136, 0) 45%), + radial-gradient(circle at 86% -12%, rgba(75, 98, 164, .22) 0, rgba(75, 98, 164, 0) 38%), + var(--bg-page); +} + +.container { + max-width: var(--page-max-width); +} + +a { + color: var(--brand-strong); + text-decoration: none; +} + +.skip-link { + position: absolute; + left: 1rem; + top: -3rem; + z-index: 1200; + border-radius: .65rem; + background: var(--brand); + color: #fff; + padding: .45rem .7rem; + text-decoration: none; + font-size: .86rem; + font-weight: 600; + transition: top .15s ease; +} + +.skip-link:focus { + top: .7rem; +} + +.site-header { + position: sticky; + top: 0; + z-index: 1080; + border-bottom: 1px solid var(--line); + background: rgba(255, 255, 255, .88); + backdrop-filter: blur(10px); +} + +.brand-link { + display: inline-flex; + align-items: center; + gap: .6rem; + color: var(--text-main); + font-family: "Outfit", sans-serif; + font-size: 1.18rem; + font-weight: 700; + letter-spacing: .02em; +} + +.brand-mark { + width: 2rem; + height: 2rem; + border-radius: .62rem; + display: inline-flex; + align-items: center; + justify-content: center; + color: #fff; + font-weight: 700; + font-size: .8rem; + background: linear-gradient(135deg, #6d7cff, #4f64ff 48%, #2d49e6); + box-shadow: 0 8px 18px rgba(61, 92, 255, .35); +} + +.site-nav { + display: flex; + gap: .2rem; + align-items: center; +} + +.site-nav-link { + color: var(--text-muted); + font-weight: 500; + padding: .44rem .75rem; + border-radius: .65rem; + transition: .18s ease; +} + +.site-nav-link:hover, +.site-nav-link.active { + color: var(--text-main); + background: var(--brand-soft); +} + +.admin-entry { + border: 1px solid var(--line); + border-radius: .65rem; + color: var(--text-main); + padding: .36rem .66rem; + background: #fff; + font-size: .9rem; +} + +.mobile-nav { + border-top: 1px solid var(--line); + background: rgba(255, 255, 255, .95); +} + +.mobile-nav .site-nav-link { + border-radius: .55rem; + padding: .52rem .62rem; +} + +.page-main { + padding: .85rem 0 1.1rem; +} + +.channel-layout { + display: grid; + grid-template-columns: 196px minmax(0, 1fr); + gap: .9rem; + align-items: start; +} + +.channel-sidebar { + position: sticky; + top: .85rem; + max-height: calc(100vh - 1.7rem); + border: 1px solid var(--line); + border-radius: 12px; + background: #fff; + box-shadow: var(--shadow-sm); + overflow: auto; + padding: .58rem .5rem; + scrollbar-width: thin; +} + +.channel-brand { + display: flex; + align-items: center; + gap: .42rem; + padding: .2rem .38rem .58rem; + border-bottom: 1px solid #e6ebf5; + margin-bottom: .42rem; + font-family: "Outfit", "Noto Sans SC", sans-serif; + font-size: 1.02rem; + font-weight: 800; + color: #1f2f53; +} + +.channel-brand-mark { + width: 1.45rem; + height: 1.45rem; + border-radius: .45rem; + display: inline-flex; + align-items: center; + justify-content: center; + background: linear-gradient(135deg, #8f8bff, #6471ff 45%, #4a58ed); + color: #fff; + font-size: .7rem; + font-family: "Outfit", "Noto Sans SC", sans-serif; + font-weight: 700; +} + +.channel-links { + display: grid; + gap: .12rem; +} + +.channel-link { + display: grid; + grid-template-columns: 1rem minmax(0, 1fr) auto; + align-items: center; + gap: .44rem; + border: 1px solid transparent; + border-radius: .52rem; + padding: .38rem .44rem; + text-decoration: none; + color: #4f5f80; + font-size: .83rem; + line-height: 1.15; + transition: .16s ease; +} + +.channel-link span { + font-weight: 500; +} + +.channel-link i { + color: #65789f; + font-size: .84rem; + text-align: center; +} + +.channel-link small { + color: #9aabc8; + font-size: .7rem; +} + +.channel-link:hover, +.channel-link.active { + border-color: #d6def0; + background: #f4f7ff; + color: #243861; + box-shadow: inset 2px 0 0 #5b6fff; +} + +.channel-main { + min-width: 0; + display: grid; + gap: .7rem; +} + +.channel-head { + display: flex; + align-items: center; + justify-content: space-between; + gap: .65rem; + border: 1px solid var(--line); + border-radius: 12px; + background: #fff; + box-shadow: var(--shadow-sm); + padding: .54rem .66rem; +} + +.channel-tabs { + display: flex; + align-items: center; + gap: .35rem; + flex-wrap: wrap; +} + +.channel-tab { + border: 1px solid transparent; + border-radius: 999px; + padding: .2rem .56rem; + color: #56698d; + text-decoration: none; + font-size: .79rem; + white-space: nowrap; + transition: .16s ease; +} + +.channel-tab.active, +.channel-tab:hover { + border-color: #d7dff1; + background: #f4f7ff; + color: #27406f; +} + +.channel-status { + display: inline-flex; + align-items: center; + gap: .4rem; + color: #7486a8; + font-size: .76rem; + white-space: nowrap; +} + +.channel-status b { + color: #2e4270; + font-family: "Outfit", "Noto Sans SC", sans-serif; + font-size: .92rem; +} + +.channel-mobile-nav { + display: none; + gap: .3rem; + flex-wrap: wrap; + border: 1px solid var(--line); + border-radius: 12px; + padding: .44rem; + background: #fff; + box-shadow: var(--shadow-sm); +} + +.channel-mobile-nav .channel-link { + min-width: 150px; + flex: 1 1 180px; +} + +.channel-hero { + border: 1px solid var(--line); + border-radius: 12px; + background: linear-gradient(180deg, #f7f9fd 0, #f3f6fb 100%); + box-shadow: var(--shadow-sm); + padding: .9rem .9rem .82rem; +} + +.channel-chip { + display: inline-flex; + border: 1px solid #d8e0f0; + border-radius: 999px; + background: #fff; + color: #7182a6; + font-size: .68rem; + font-weight: 700; + padding: .14rem .48rem; + margin-bottom: .2rem; +} + +.channel-title { + margin: 0; + font-family: "Outfit", "Noto Sans SC", sans-serif; + color: #202f4f; + font-weight: 800; + font-size: clamp(1.45rem, 2.4vw, 2.05rem); + letter-spacing: .01em; +} + +.channel-subtitle { + margin: .28rem 0 .55rem; + color: #5f6f8b; + font-size: .87rem; +} + +.channel-search { + display: grid; + grid-template-columns: minmax(0, 1fr) auto auto auto auto; + gap: .42rem; +} + +.channel-search input, +.channel-search select { + height: 2.24rem; + border: 1px solid #d6def0; + border-radius: 999px; + background: #fff; + color: #33496f; + font-size: .83rem; + padding: 0 .78rem; + min-width: 0; +} + +.channel-search .btn { + border-radius: 999px; + min-width: 92px; + height: 2.24rem; + padding: 0 .95rem; + font-size: .82rem; + font-weight: 600; +} + +.channel-kpis { + margin-top: .56rem; + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: .5rem; +} + +.channel-kpi { + border: 1px solid var(--line); + border-radius: 10px; + background: #fff; + box-shadow: var(--shadow-sm); + padding: .58rem .62rem; +} + +.channel-kpi span { + color: var(--text-muted); + font-size: .76rem; +} + +.channel-kpi b { + display: block; + margin-top: .14rem; + font-family: "Outfit", "Noto Sans SC", sans-serif; + font-size: 1.12rem; + font-weight: 800; + color: var(--text-main); + line-height: 1.1; +} + +.channel-body { + display: grid; + grid-template-columns: minmax(0, 1fr) 320px; + gap: var(--page-section-gap); +} + +.channel-panel { + border: 1px solid var(--line); + border-radius: 12px; + background: #fff; + box-shadow: var(--shadow-sm); + padding: .8rem; +} + +.channel-panel-title { + margin: 0; + font-family: "Outfit", "Noto Sans SC", sans-serif; + font-size: 1rem; + font-weight: 700; + color: #22365c; +} + +.channel-panel-head { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: .62rem; +} + +.channel-list { + display: grid; + gap: .5rem; +} + +.entity-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: .58rem; +} + +.entity-card { + border: 1px solid var(--line); + border-radius: 10px; + background: #fff; + padding: .66rem .7rem; + transition: .18s ease; +} + +.entity-card:hover { + transform: translateY(-2px); + border-color: color-mix(in srgb, var(--brand) 35%, var(--line)); + box-shadow: 0 12px 25px rgba(36, 65, 138, .12); +} + +.entity-title { + display: block; + color: #24385f; + text-decoration: none; + font-weight: 700; + line-height: 1.25; +} + +.entity-meta { + margin-top: .2rem; + color: var(--text-muted); + font-size: .79rem; +} + +.entity-desc { + margin: .42rem 0 .5rem; + color: var(--text-muted); + font-size: .82rem; +} + +.side-list-item { + border: 1px solid var(--line); + border-radius: 10px; + background: #fff; + padding: .52rem .58rem; +} + +.side-list-item a { + display: block; + color: #24385f; + text-decoration: none; + font-weight: 600; + line-height: 1.25; +} + +.side-list-item small { + display: block; + margin-top: .2rem; + color: var(--text-muted); + font-size: .76rem; +} + +.module-hero { + position: relative; + overflow: hidden; + border-radius: 12px; + border: 1px solid var(--line-strong); + background: linear-gradient(140deg, #f2f6ff, #ebf2ff 58%, #f6f3ff); + box-shadow: var(--shadow-md); + padding: 1rem .95rem; + margin-bottom: var(--page-section-gap); +} + +.module-hero::after { + content: ""; + position: absolute; + right: -56px; + top: -66px; + width: 220px; + height: 220px; + border-radius: 999px; + background: radial-gradient(circle, rgba(255, 255, 255, .75), rgba(255, 255, 255, .2)); + pointer-events: none; +} + +.module-hero .position-relative { + z-index: 2; +} + +.module-hero h1, +.module-hero h2, +.module-hero h3 { + color: var(--text-main); + margin-bottom: .45rem; + font-family: "Outfit", "Noto Sans SC", sans-serif; +} + +.module-hero p, +.hero-subtext { + color: var(--text-muted) !important; + margin: 0; +} + +.hero-chip, +.module-hero .chip { + display: inline-flex; + align-items: center; + gap: .28rem; + border-radius: 999px; + border: 1px solid var(--line-strong); + background: rgba(255, 255, 255, .78); + color: var(--brand-strong); + padding: .2rem .64rem; + font-size: .78rem; + font-weight: 600; +} + +.portal-grid, +.module-grid { + display: grid; + grid-template-columns: minmax(0, 1fr) 320px; + gap: var(--page-section-gap); +} + +.portal-card, +.surface-card, +.block-card { + background: var(--bg-surface); + border: 1px solid var(--line); + border-radius: 12px; + box-shadow: var(--shadow-sm); +} + +.entry-item { + border: 1px solid var(--line); + border-radius: 10px; + padding: .8rem; + background: #fff; + transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease; +} + +.entry-item:hover { + transform: translateY(-2px); + border-color: color-mix(in srgb, var(--brand) 35%, var(--line)); + box-shadow: 0 12px 25px rgba(36, 65, 138, .12); +} + +.hero-soft { + border: 1px solid var(--line); + border-radius: var(--radius-xl); + background: linear-gradient(135deg, #f4f7ff, #edf3ff 55%, #f8f5ff); + padding: 1.1rem; + box-shadow: var(--shadow-sm); +} + +.search-shell { + display: flex; + align-items: center; + gap: .45rem; + border: 1px solid var(--line-strong); + border-radius: 999px; + background: #fff; + padding: .42rem; +} + +.search-shell input { + border: 0; + box-shadow: none; + background: transparent; + color: var(--text-main); +} + +.search-shell .btn { + border-radius: 999px; +} + +.chip { + display: inline-flex; + align-items: center; + gap: .28rem; + border-radius: 999px; + border: 1px solid var(--line); + background: var(--bg-soft); + color: var(--text-muted); + padding: .18rem .6rem; + font-size: .78rem; +} + +.portal-tag { + display: inline-flex; + align-items: center; + margin-right: .35rem; + margin-bottom: .35rem; + border-radius: 999px; + border: 1px solid var(--line-strong); + background: #fff; + color: var(--brand-strong); + padding: .2rem .6rem; + font-size: .78rem; +} + +.line-clamp-2 { + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} + +.text-muted-soft { + color: var(--text-muted) !important; +} + +.section-title { + font-family: "Outfit", "Noto Sans SC", sans-serif; + font-size: 1.05rem; + font-weight: 700; + color: var(--text-main); +} + +.tiny-link { + font-size: .8rem; + color: var(--brand-strong); + text-decoration: none; +} + +.list-tight { + display: grid; + gap: .55rem; +} + +.list-tight article { + border: 1px solid var(--line); + border-radius: var(--radius-md); + padding: .6rem .7rem; + background: #fff; +} + +.metric-bar { + height: 6px; + border-radius: 999px; + overflow: hidden; + background: #e5ebf8; +} + +.metric-fill { + height: 100%; + border-radius: 999px; +} + +.md-content { + color: var(--text-main); + line-height: 1.86; + font-size: 1rem; +} + +.md-content h1, +.md-content h2, +.md-content h3, +.md-content h4, +.md-content h5, +.md-content h6 { + font-family: "Outfit", "Noto Sans SC", sans-serif; + margin-top: 1.45em; + margin-bottom: .65em; + color: var(--text-main); +} + +.md-content p { + margin-bottom: 1em; + color: #1f2d44; +} + +.md-content ul, +.md-content ol { + margin-bottom: 1em; + padding-left: 1.45rem; +} + +.md-content a { + color: var(--brand-strong); + text-decoration: underline; + text-underline-offset: 2px; +} + +.md-content pre { + border: 1px solid var(--line); + border-radius: .78rem; + background: #f4f7ff; + color: #12213b; + padding: .82rem; + overflow-x: auto; +} + +.md-content code { + border-radius: .45rem; + background: #edf2ff; + color: #223fbe; + padding: .15rem .4rem; + font-size: .9em; +} + +.md-content pre code { + background: transparent; + color: inherit; + padding: 0; +} + +.md-content img { + max-width: 100%; + height: auto; + border-radius: .85rem; + border: 1px solid var(--line); + margin: .45rem 0; + box-shadow: var(--shadow-sm); +} + +.md-content blockquote { + margin: 1rem 0; + border-left: 3px solid var(--brand); + background: #f7f9ff; + color: #2a3e63; + padding: .68rem .86rem; + border-radius: .5rem; +} + +.footer-shell { + border-top: 1px solid var(--line); + color: var(--text-muted); + background: rgba(255, 255, 255, .75); + font-size: .92rem; +} + +:root[data-theme="dark"] .footer-shell { + background: rgba(16, 24, 44, .78); +} + +.float-actions { + position: fixed; + right: 1rem; + bottom: 1rem; + z-index: 1200; + display: grid; + gap: .5rem; +} + +.float-btn { + border: 1px solid var(--line); + border-radius: 999px; + background: var(--bg-surface); + color: var(--text-main); + min-width: 42px; + height: 42px; + display: inline-flex; + align-items: center; + justify-content: center; + box-shadow: var(--shadow-sm); + cursor: pointer; +} + +.feedback-modal .modal-content { + border-color: var(--line); + background: var(--bg-surface); + color: var(--text-main); +} + +:where(a, button, input, textarea, select, [role="button"]):focus-visible { + outline: 2px solid color-mix(in srgb, var(--brand) 62%, transparent); + outline-offset: 2px; +} + +.form-control, +.form-select { + border-color: var(--line); + background: #fff; + color: var(--text-main); +} + +.form-control::placeholder { + color: #8b98af; +} + +.form-control:focus, +.form-select:focus { + border-color: color-mix(in srgb, var(--brand) 58%, transparent); + box-shadow: 0 0 0 .18rem rgba(61, 92, 255, .16); +} + +.table { + --bs-table-bg: transparent; + --bs-table-color: var(--text-main); + --bs-table-border-color: var(--line); +} + +.pagination { + --bs-pagination-bg: #fff; + --bs-pagination-color: var(--text-main); + --bs-pagination-border-color: var(--line); + --bs-pagination-hover-bg: var(--brand-soft); + --bs-pagination-hover-color: var(--text-main); + --bs-pagination-hover-border-color: var(--line-strong); + --bs-pagination-active-bg: var(--brand); + --bs-pagination-active-border-color: var(--brand); +} + +.page-tools .module-hero { + background: linear-gradient(120deg, #edf4ff, #e2eeff); +} + +.page-models .module-hero { + background: linear-gradient(120deg, #f2ecff, #ede7ff); +} + +.page-news .module-hero { + background: linear-gradient(120deg, #eafaf6, #e1f7f0); +} + +.page-guides .module-hero { + background: linear-gradient(120deg, #fff2e8, #ffede0); +} + +.page-home .module-hero { + background: linear-gradient(120deg, #edf4ff, #e9f0ff, #f0efff); +} + +.page-detail .module-hero { + border-color: color-mix(in srgb, var(--line) 88%, #fff); + background: linear-gradient(180deg, color-mix(in srgb, #fff 84%, var(--bg-soft)) 0, color-mix(in srgb, #fff 92%, var(--bg-soft)) 100%); + box-shadow: var(--shadow-sm); + padding: .82rem .88rem; +} + +.page-detail .module-hero::after { + opacity: .28; + transform: scale(.82); + transform-origin: top right; +} + +.page-detail .module-hero h1, +.page-detail .module-hero h2, +.page-detail .module-hero h3 { + font-size: clamp(1.4rem, 2vw, 1.85rem); + font-weight: 700; + letter-spacing: .004em; + margin-bottom: .34rem; + color: color-mix(in srgb, var(--text-main) 90%, var(--text-muted)); +} + +.page-detail .module-hero p, +.page-detail .hero-subtext { + font-size: .92rem; + color: color-mix(in srgb, var(--text-muted) 92%, #8ca0c4) !important; +} + +.page-detail .hero-chip, +.page-detail .module-hero .chip { + border-color: color-mix(in srgb, var(--line) 92%, #fff); + background: color-mix(in srgb, var(--bg-surface) 88%, transparent); + color: color-mix(in srgb, var(--text-muted) 86%, var(--brand)); + font-size: .7rem; + font-weight: 500; + padding: .12rem .5rem; +} + +.page-detail .section-title { + font-size: .96rem; + font-weight: 600; + letter-spacing: .01em; + color: color-mix(in srgb, var(--text-main) 72%, var(--text-muted)); +} + +.page-detail .section-title i { + opacity: .62; +} + +.page-detail .chip { + border-color: color-mix(in srgb, var(--line) 94%, #fff); + background: color-mix(in srgb, var(--bg-soft) 75%, #fff); + color: color-mix(in srgb, var(--text-muted) 90%, #8094b6); + font-size: .72rem; + padding: .12rem .5rem; +} + +.page-detail .lead { + font-size: 1.02rem; + color: color-mix(in srgb, var(--text-muted) 90%, var(--text-main)); + margin-bottom: .92rem; +} + +.page-detail .detail-content { + max-width: min(76ch, 100%); + margin-inline: auto; + font-size: 1.07rem; + line-height: 1.95; + color: color-mix(in srgb, var(--text-main) 94%, var(--text-muted)); + text-wrap: pretty; +} + +.page-detail .detail-content > :first-child { + margin-top: .1rem; +} + +.page-detail .detail-content p { + margin-bottom: 1.12em; + color: color-mix(in srgb, var(--text-main) 92%, var(--text-muted)); +} + +.page-detail .detail-content h1, +.page-detail .detail-content h2, +.page-detail .detail-content h3, +.page-detail .detail-content h4, +.page-detail .detail-content h5, +.page-detail .detail-content h6 { + margin-top: 1.55em; + margin-bottom: .58em; + letter-spacing: .006em; +} + +.page-detail .detail-content a { + font-weight: 500; +} + +.page-detail .detail-content blockquote { + border-left-width: 2px; + background: color-mix(in srgb, var(--bg-soft) 78%, #fff); +} + +@media (max-width: 575.98px) { + .page-detail .module-hero { + padding: .74rem .78rem; + } + + .page-detail .module-hero h1, + .page-detail .module-hero h2, + .page-detail .module-hero h3 { + font-size: clamp(1.26rem, 6vw, 1.6rem); + } + + .page-detail .detail-content { + font-size: 1.02rem; + line-height: 1.88; + } +} + +@media (max-width: 991.98px) { + .channel-layout { + grid-template-columns: 1fr; + } + + .channel-sidebar { + display: none; + } + + .channel-mobile-nav { + display: flex; + } + + .channel-head { + flex-direction: column; + align-items: stretch; + } + + .channel-status { + justify-content: space-between; + } + + .channel-body { + grid-template-columns: 1fr; + } + + .channel-kpis { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .entity-grid { + grid-template-columns: 1fr; + } + + .channel-search { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .channel-search .btn { + width: 100%; + grid-column: 1 / -1; + } + + .portal-grid, + .module-grid { + grid-template-columns: 1fr; + } +} + +@media (max-width: 767.98px) { + .site-nav-link { + padding: .45rem .62rem; + } +} + +@media (max-width: 575.98px) { + .channel-kpis { + grid-template-columns: 1fr; + } + + .channel-search { + grid-template-columns: 1fr; + } + + .channel-mobile-nav .channel-link { + flex: 1 1 100%; + } + + .module-hero, + .portal-card, + .surface-card, + .block-card { + border-radius: 10px; + } + + .module-hero { + padding: 1rem .95rem; + } + + .brand-link { + font-size: 1.03rem; + } + + .brand-mark { + width: 1.82rem; + height: 1.82rem; + } +} + +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + animation-duration: .01ms !important; + animation-iteration-count: 1 !important; + transition-duration: .01ms !important; + scroll-behavior: auto !important; + } +} \ No newline at end of file diff --git a/resources/views/layouts/site.blade.php b/resources/views/layouts/site.blade.php index 39f846e..4eba1f8 100644 --- a/resources/views/layouts/site.blade.php +++ b/resources/views/layouts/site.blade.php @@ -1,1239 +1,142 @@  + @yield('title', 'AIWeb - AI 工具与模型导航') @hasSection('canonical') - + @endif - + @vite(['resources/css/home.css', 'resources/css/app.css']) @yield('head') + - + -@php + @php $topNavItems = [ - ['route' => 'tools.index', 'label' => 'AI工具集'], - ['route' => 'models.index', 'label' => '模型推荐'], - ['route' => 'news.index', 'label' => '文章资讯'], - ['route' => 'guides.index', 'label' => '教程学习'] + ['route' => 'tools.index', 'label' => 'AI工具集'], + ['route' => 'models.index', 'label' => '模型推荐'], + ['route' => 'news.index', 'label' => '文章资讯'], + ['route' => 'guides.index', 'label' => '教程学习'] ]; -@endphp + @endphp - - -
-
- @yield('content') -
-
- - -
- - -
+ + - -@yield('scripts') + const initial = localStorage.getItem(storageKey) || + (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'); + applyTheme(initial); + + toggle?.addEventListener('click', () => { + const next = root.getAttribute('data-theme') === 'dark' ? 'light' : 'dark'; + localStorage.setItem(storageKey, next); + applyTheme(next); + }); + })(); + + @yield('scripts') - - - + \ No newline at end of file diff --git a/vite.config.js b/vite.config.js index f35b4e7..3d7907c 100644 --- a/vite.config.js +++ b/vite.config.js @@ -5,7 +5,7 @@ import tailwindcss from '@tailwindcss/vite'; export default defineConfig({ plugins: [ laravel({ - input: ['resources/css/app.css', 'resources/js/app.js'], + input: ['resources/css/app.css', 'resources/css/home.css', 'resources/js/app.js'], refresh: true, }), tailwindcss(),