Files
ai-web/resources/views/public/tools/index.blade.php
jiangdong.cheng a633234239 优化界面
2026-02-12 10:31:53 +08:00

672 lines
20 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
@extends('layouts.site')
@section('page_class', 'page-tools')
@section('title', 'AI 工具集 - AIWeb')
@section('meta_description', '参考门户站样式的 AI 工具导航页,支持分类浏览、搜索筛选与热门工具发现。')
@section('canonical', route('tools.index'))
@section('head')
<style>
.portal-shell {
display: grid;
grid-template-columns: 186px minmax(0, 1fr);
gap: .68rem;
align-items: start;
}
.portal-sidebar {
position: sticky;
top: .7rem;
border: 1px solid #d8e1f1;
border-radius: 12px;
background: #fff;
box-shadow: 0 8px 18px rgba(40, 63, 120, .08);
padding: .62rem .5rem;
max-height: calc(100vh - 1.4rem);
overflow: auto;
}
.portal-logo {
display: flex;
align-items: center;
gap: .38rem;
padding: .24rem .3rem .56rem;
margin-bottom: .35rem;
border-bottom: 1px solid #e7edf8;
font-family: "Outfit", "Noto Sans SC", sans-serif;
color: #131e44;
font-size: 1.12rem;
font-weight: 800;
}
.portal-logo-dot {
width: 1.35rem;
height: 1.35rem;
border-radius: .38rem;
background: linear-gradient(135deg, #a777ff, #6e77ff);
color: #fff;
font-weight: 700;
font-size: .68rem;
display: inline-flex;
align-items: center;
justify-content: center;
}
.portal-side-links {
display: grid;
gap: .16rem;
}
.portal-side-link {
display: grid;
grid-template-columns: 1rem minmax(0, 1fr) auto;
align-items: center;
gap: .42rem;
border: 1px solid transparent;
border-radius: .58rem;
text-decoration: none;
color: #4e6189;
padding: .38rem .42rem;
font-size: .82rem;
transition: .16s ease;
}
.portal-side-link i {
font-size: .86rem;
color: #687ba2;
text-align: center;
}
.portal-side-link span {
font-weight: 500;
}
.portal-side-link small {
color: #97a9c8;
font-size: .7rem;
}
.portal-side-link:hover,
.portal-side-link.active {
border-color: #d4ddf2;
background: #f4f7ff;
color: #21345f;
box-shadow: inset 2px 0 0 #5f72ff;
}
.portal-main {
min-width: 0;
display: grid;
gap: .62rem;
}
.portal-topbar {
display: flex;
align-items: center;
justify-content: space-between;
gap: .5rem;
border: 1px solid #d8e1f1;
border-radius: 12px;
background: #fff;
box-shadow: 0 8px 18px rgba(40, 63, 120, .08);
padding: .5rem .62rem;
}
.portal-topbar .channel-tabs {
gap: .24rem;
}
.portal-topbar .channel-tab {
padding: .16rem .52rem;
font-size: .78rem;
}
.portal-topbar .portal-status {
color: #7387ad;
font-size: .76rem;
white-space: nowrap;
}
.portal-topbar .portal-status b {
color: #2c4172;
font-family: "Outfit", "Noto Sans SC", sans-serif;
font-size: .9rem;
}
.portal-hero {
border: 1px solid #d8e1f1;
border-radius: 12px;
background: linear-gradient(180deg, #f5f8ff 0, #eef3fb 100%);
box-shadow: 0 8px 18px rgba(40, 63, 120, .08);
padding: .95rem .95rem .82rem;
text-align: center;
}
.portal-chip {
display: inline-flex;
border: 1px solid #d8e0f0;
border-radius: 999px;
background: #fff;
color: #6f81a7;
font-size: .68rem;
font-weight: 700;
padding: .14rem .5rem;
}
.portal-title {
margin: .34rem 0 .2rem;
font-family: "Outfit", "Noto Sans SC", sans-serif;
font-size: clamp(1.6rem, 2.8vw, 2.45rem);
font-weight: 800;
color: #141f47;
letter-spacing: .01em;
}
.portal-sub {
margin: 0;
color: #66799f;
font-size: .84rem;
}
.portal-switch {
display: inline-flex;
gap: .5rem;
margin-top: .58rem;
padding: .13rem;
border-radius: 999px;
background: rgba(255, 255, 255, .8);
border: 1px solid #d7dff1;
}
.portal-switch a {
text-decoration: none;
color: #7384a8;
font-size: .78rem;
border-radius: 999px;
padding: .16rem .56rem;
}
.portal-switch a.active,
.portal-switch a:hover {
color: #243863;
background: #fff;
}
.portal-search {
margin: .62rem auto .36rem;
width: min(860px, 100%);
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: .38rem;
border: 1px solid #d4deef;
background: #fff;
border-radius: 999px;
padding: .3rem;
}
.portal-search input {
border: 0;
box-shadow: none;
height: 2.16rem;
padding: 0 .82rem;
background: transparent;
}
.portal-search button {
border-radius: 999px;
min-width: 90px;
height: 2.16rem;
font-size: .82rem;
}
.portal-search-tabs {
display: flex;
justify-content: center;
gap: .42rem;
flex-wrap: wrap;
}
.portal-search-tabs a {
text-decoration: none;
color: #7384a8;
font-size: .75rem;
border-bottom: 2px solid transparent;
padding-bottom: .12rem;
}
.portal-search-tabs a.active,
.portal-search-tabs a:hover {
color: #253a65;
border-bottom-color: #5f74ff;
}
.portal-kpis {
margin-top: .56rem;
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: .48rem;
}
.portal-kpi {
border: 1px solid #d7e0f1;
border-radius: 10px;
background: #fff;
padding: .56rem .6rem;
text-align: left;
}
.portal-kpi span {
font-size: .74rem;
color: #6d80a5;
}
.portal-kpi b {
display: block;
margin-top: .12rem;
font-family: "Outfit", "Noto Sans SC", sans-serif;
font-size: 1.08rem;
font-weight: 800;
color: #1c2d55;
}
.portal-channel-grid {
border: 1px solid #d8e1f1;
border-radius: 12px;
background: #fff;
box-shadow: 0 8px 18px rgba(40, 63, 120, .08);
padding: .52rem;
display: grid;
grid-template-columns: 62px repeat(5, minmax(0, 1fr));
gap: .46rem;
}
.portal-channel-mini {
border: 1px solid #dee6f5;
border-radius: 10px;
background: #f8faff;
display: grid;
gap: .34rem;
padding: .44rem .3rem;
}
.portal-channel-mini a {
text-decoration: none;
color: #5f7399;
font-size: .72rem;
text-align: center;
}
.portal-channel-mini i {
display: block;
font-size: .86rem;
margin-bottom: .12rem;
}
.portal-card {
border: 1px solid #dce4f3;
border-radius: 10px;
min-height: 94px;
display: flex;
align-items: center;
justify-content: center;
text-decoration: none;
font-family: "Outfit", "Noto Sans SC", sans-serif;
font-size: 2rem;
font-weight: 800;
letter-spacing: .01em;
color: #273a63;
transition: .16s ease;
}
.portal-card:hover {
transform: translateY(-2px);
box-shadow: 0 12px 24px rgba(45, 66, 122, .14);
}
.portal-card.news { background: #dce8ff; }
.portal-card.community { background: #dff3da; }
.portal-card.project { background: #ede0fa; }
.portal-card.tutorial { background: #d8f0ff; }
.portal-card.ad { background: #f4f6ff; }
.portal-banner-row {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: .52rem;
}
.portal-banner {
border: 1px solid #d8e1f1;
border-radius: 10px;
background: linear-gradient(90deg, #e8f3ff, #e4f7ef);
min-height: 66px;
display: flex;
align-items: center;
justify-content: space-between;
gap: .52rem;
padding: .58rem .72rem;
}
.portal-banner.alt {
background: linear-gradient(90deg, #e6f6ff, #dff8dd);
}
.portal-banner b {
color: #1d3058;
font-size: 1.06rem;
font-family: "Outfit", "Noto Sans SC", sans-serif;
}
.portal-banner small {
border: 1px solid #d6def0;
border-radius: 999px;
background: #fff;
color: #5f749a;
font-size: .72rem;
padding: .14rem .48rem;
}
.portal-block {
border: 1px solid #d8e1f1;
border-radius: 12px;
background: #fff;
box-shadow: 0 8px 18px rgba(40, 63, 120, .08);
padding: .62rem;
}
.portal-block-head {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: .48rem;
}
.portal-block-head h2 {
margin: 0;
color: #20335d;
font-size: 1rem;
font-family: "Outfit", "Noto Sans SC", sans-serif;
font-weight: 700;
}
.portal-block-head a {
color: #4d63a4;
text-decoration: none;
font-size: .76rem;
font-weight: 600;
}
.tool-grid {
display: grid;
grid-template-columns: repeat(6, minmax(0, 1fr));
gap: .52rem;
}
.tool-item {
border: 1px solid #dbe3f2;
border-radius: 10px;
background: #fff;
padding: .52rem .56rem;
text-decoration: none;
color: #1f3157;
transition: .16s ease;
min-height: 88px;
display: grid;
align-content: start;
gap: .25rem;
}
.tool-item:hover {
border-color: #cdd9f0;
box-shadow: 0 12px 24px rgba(45, 66, 122, .12);
transform: translateY(-2px);
}
.tool-name {
font-size: .85rem;
font-weight: 700;
line-height: 1.3;
}
.tool-meta {
font-size: .72rem;
color: #7084a8;
line-height: 1.25;
}
.tool-tag {
display: inline-flex;
align-items: center;
border: 1px solid #d6def0;
border-radius: 999px;
background: #f6f8ff;
color: #4f639b;
font-size: .68rem;
padding: .06rem .4rem;
}
.portal-mobile-nav {
display: none;
gap: .28rem;
flex-wrap: wrap;
border: 1px solid #d8e1f1;
border-radius: 12px;
background: #fff;
box-shadow: 0 8px 18px rgba(40, 63, 120, .08);
padding: .42rem;
}
.portal-mobile-nav .portal-side-link {
flex: 1 1 160px;
min-width: 144px;
}
@media (max-width: 1399.98px) {
.tool-grid {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
}
@media (max-width: 991.98px) {
.portal-shell {
grid-template-columns: 1fr;
}
.portal-sidebar {
display: none;
}
.portal-mobile-nav {
display: flex;
}
.portal-topbar {
flex-direction: column;
align-items: stretch;
}
.portal-channel-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.portal-channel-mini {
grid-column: 1 / -1;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: .22rem;
}
.tool-grid {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.portal-banner-row {
grid-template-columns: 1fr;
}
.portal-kpis {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 575.98px) {
.portal-title {
font-size: 2rem;
}
.tool-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.portal-kpis {
grid-template-columns: 1fr;
}
.portal-search {
grid-template-columns: 1fr;
border-radius: 12px;
}
.portal-search button {
width: 100%;
border-radius: 10px;
}
}
</style>
@endsection
@section('content')
@php
$icons = ['bi-stars', 'bi-pencil', 'bi-image', 'bi-camera-video', 'bi-briefcase', 'bi-cpu', 'bi-chat-dots', 'bi-code-slash', 'bi-kanban'];
@endphp
<div class="portal-shell">
<aside class="portal-sidebar" aria-label="工具分类侧边栏">
<div class="portal-logo"><span class="portal-logo-dot">AI</span>AI工具集</div>
<nav class="portal-side-links">
<a class="portal-side-link @if(empty($filters['category'])) active @endif" href="{{ route('tools.index') }}">
<i class="bi bi-stars"></i>
<span>全部工具</span>
<small>{{ $toolStats['total'] ?? 0 }}</small>
</a>
@foreach($categories as $index => $category)
<a class="portal-side-link @if(($filters['category'] ?? '') === $category->slug) active @endif" href="{{ route('tools.by-category', $category->slug) }}">
<i class="bi {{ $icons[$index % count($icons)] }}"></i>
<span>{{ $category->name }}</span>
<small>{{ $category->published_tools_count ?? 0 }}</small>
</a>
@endforeach
</nav>
</aside>
<section class="portal-main">
<header class="portal-topbar">
<nav class="channel-tabs" aria-label="顶部频道导航">
<a class="channel-tab active" href="{{ route('tools.index') }}">AI工具集</a>
<a class="channel-tab" href="{{ route('models.index') }}">AI应用集</a>
<a class="channel-tab" href="{{ route('news.index') }}">每日AI资讯</a>
<a class="channel-tab" href="{{ route('tools.index', ['tab' => 'latest']) }}">最新AI项目</a>
<a class="channel-tab" href="{{ route('guides.index') }}">AI教程资源</a>
<a class="channel-tab" href="{{ route('home') }}">关于我们</a>
</nav>
<div class="portal-status">收录工具 <b>{{ $toolStats['total'] ?? 0 }}</b></div>
</header>
<nav class="portal-mobile-nav" aria-label="移动分类导航">
<a class="portal-side-link @if(empty($filters['category'])) active @endif" href="{{ route('tools.index') }}">
<i class="bi bi-stars"></i>
<span>全部</span>
<small>{{ $toolStats['total'] ?? 0 }}</small>
</a>
@foreach($categories->take(6) as $index => $category)
<a class="portal-side-link @if(($filters['category'] ?? '') === $category->slug) active @endif" href="{{ route('tools.by-category', $category->slug) }}">
<i class="bi {{ $icons[$index % count($icons)] }}"></i>
<span>{{ $category->name }}</span>
<small>{{ $category->published_tools_count ?? 0 }}</small>
</a>
@endforeach
</nav>
<section class="portal-hero">
<span class="portal-chip">AI-BOT.CN</span>
<h1 class="portal-title">AI工具集</h1>
<p class="portal-sub">参考示例门户布局:分类检索、频道入口与热门内容聚合一体化。</p>
<nav class="portal-switch" aria-label="搜索模式">
@foreach($tabOptions as $tab)
<a class="@if($activeTab === $tab['key']) active @endif" href="{{ route('tools.index', array_filter(array_merge($filters, ['tab' => $tab['key']]))) }}">{{ $tab['label'] }}</a>
@endforeach
</nav>
<form class="portal-search" method="get" action="{{ route('tools.index') }}" role="search" aria-label="站内 AI 工具搜索">
<input type="hidden" name="tab" value="{{ $activeTab }}">
<input type="search" name="q" value="{{ $filters['q'] ?? '' }}" placeholder="站内AI工具搜索写作、图像、办公自动化" autocomplete="off" spellcheck="false">
<button class="btn btn-primary" type="submit"><i class="bi bi-search"></i> 搜索</button>
</form>
<nav class="portal-search-tabs" aria-label="快速筛选">
<a class="active" href="{{ route('tools.index') }}">站内</a>
<a href="{{ route('models.index') }}">模型</a>
<a href="{{ route('news.index') }}">资讯</a>
<a href="{{ route('guides.index') }}">教程</a>
<a href="{{ route('home') }}">首页</a>
</nav>
<section class="portal-kpis" aria-label="工具统计">
<article class="portal-kpi"><span>收录工具</span><b>{{ $toolStats['total'] ?? 0 }}</b></article>
<article class="portal-kpi"><span>支持 API</span><b>{{ $toolStats['api'] ?? 0 }}</b></article>
<article class="portal-kpi"><span>免费可用</span><b>{{ $toolStats['free'] ?? 0 }}</b></article>
<article class="portal-kpi"><span>7天更新</span><b>{{ $toolStats['updated_7d'] ?? 0 }}</b></article>
</section>
</section>
<section class="portal-channel-grid" aria-label="频道入口">
<aside class="portal-channel-mini">
<a href="{{ route('news.index') }}"><i class="bi bi-newspaper"></i>AI资讯</a>
<a href="{{ route('models.index') }}"><i class="bi bi-box"></i>AI项目</a>
<a href="{{ route('guides.index') }}"><i class="bi bi-journal"></i>AI百科</a>
<a href="{{ route('home') }}"><i class="bi bi-house"></i>首页</a>
</aside>
<a class="portal-card news" href="{{ route('news.index') }}">每日快讯</a>
<a class="portal-card community" href="{{ route('guides.index') }}">免费社群</a>
<a class="portal-card project" href="{{ route('models.index') }}">最新项目</a>
<a class="portal-card tutorial" href="{{ route('guides.index') }}">热门教程</a>
<a class="portal-card ad" href="{{ route('tools.index', ['tab' => 'free']) }}">办公不求人</a>
</section>
<section class="portal-banner-row" aria-label="横幅推荐">
<article class="portal-banner">
<b>超全图片视频模板一键复制</b>
<small>全球顶尖模型</small>
</article>
<article class="portal-banner alt">
<b>一站式 AI 创作平台</b>
<small>免费试用</small>
</article>
</section>
<section class="portal-block" aria-label="热门工具">
<header class="portal-block-head">
<h2><i class="bi bi-fire text-danger"></i> 热门工具</h2>
<a href="{{ route('tools.index', ['tab' => 'latest']) }}">最新收录</a>
</header>
@if($items->isNotEmpty())
<div class="tool-grid">
@foreach($items as $tool)
<a class="tool-item" href="{{ route('tools.show', $tool->slug) }}">
<div class="tool-name">{{ $tool->name }}</div>
<div class="tool-meta">{{ $tool->category?->name ?? '未分类' }} · {{ $tool->pricing_type }}</div>
<span class="tool-tag">{{ $tool->has_api ? '支持 API' : '无 API' }}</span>
</a>
@endforeach
</div>
<div class="mt-3">{{ $items->links() }}</div>
@else
<p class="text-muted-soft mb-0">没有命中工具,试试更换关键词或筛选条件。</p>
@endif
</section>
</section>
</div>
@endsection