页面优化,功能修复
This commit is contained in:
@@ -83,6 +83,13 @@
|
||||
box-shadow: inset 2px 0 0 #5f72ff;
|
||||
}
|
||||
|
||||
.tool-side-link.is-active {
|
||||
border-color: #d4ddf2;
|
||||
background: #eef3ff;
|
||||
color: #1f3157;
|
||||
box-shadow: inset 3px 0 0 #536eff;
|
||||
}
|
||||
|
||||
.tool-side-link i {
|
||||
color: #687ba2;
|
||||
text-align: center;
|
||||
@@ -474,47 +481,51 @@
|
||||
<aside class="tool-side" aria-label="工具分类侧边栏">
|
||||
<div class="tool-side-logo"><span class="tool-side-logo-dot">AI</span>AI工具集</div>
|
||||
<nav class="tool-side-links">
|
||||
<a class="tool-side-link active" href="#section-hot">
|
||||
<i class="bi bi-fire"></i>
|
||||
<span>热门工具</span>
|
||||
<small>{{ $hotTools->count() }}</small>
|
||||
</a>
|
||||
<a class="tool-side-link" href="#section-latest">
|
||||
<i class="bi bi-clock-history"></i>
|
||||
<span>最新收录</span>
|
||||
<small>{{ $latestTools->count() }}</small>
|
||||
</a>
|
||||
@foreach($categorySections as $index => $section)
|
||||
<a class="tool-side-link" href="#section-{{ $section['slug'] }}">
|
||||
<i class="bi {{ $icons[$index % count($icons)] }}"></i>
|
||||
<span>{{ $section['name'] }}</span>
|
||||
<small>{{ $section['count'] }}</small>
|
||||
@if(($modules['hot_tools']['enabled'] ?? true) === true)
|
||||
<a class="tool-side-link" href="#section-hot">
|
||||
<i class="bi bi-fire"></i>
|
||||
<span>热门工具</span>
|
||||
<small>{{ $hotTools->count() }}</small>
|
||||
</a>
|
||||
@endforeach
|
||||
@endif
|
||||
@if(($modules['latest_tools']['enabled'] ?? true) === true)
|
||||
<a class="tool-side-link" href="#section-latest">
|
||||
<i class="bi bi-clock-history"></i>
|
||||
<span>最新收录</span>
|
||||
<small>{{ $latestTools->count() }}</small>
|
||||
</a>
|
||||
@endif
|
||||
@if(($modules['category_sections']['enabled'] ?? true) === true)
|
||||
@foreach($categorySections as $index => $section)
|
||||
<a class="tool-side-link" href="#section-{{ $section['slug'] }}">
|
||||
<i class="bi {{ $icons[$index % count($icons)] }}"></i>
|
||||
<span>{{ $section['name'] }}</span>
|
||||
<small>{{ $section['count'] }}</small>
|
||||
</a>
|
||||
@endforeach
|
||||
@endif
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
<section class="tool-main">
|
||||
<header class="tool-top">
|
||||
<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('guides.index') }}">AI教程资源</a>
|
||||
</nav>
|
||||
<div class="tool-status">收录工具 <b>{{ $toolStats['total'] ?? 0 }}</b></div>
|
||||
</header>
|
||||
<x-portal.top-nav active="tools" status-label="收录工具" :status-value="$toolStats['total'] ?? 0" wrapper-class="tool-top" />
|
||||
|
||||
<nav class="tool-mobile-cats" aria-label="移动分类导航">
|
||||
<a class="tool-side-link" href="#section-hot"><i class="bi bi-fire"></i><span>热门</span><small>{{ $hotTools->count() }}</small></a>
|
||||
<a class="tool-side-link" href="#section-latest"><i class="bi bi-clock-history"></i><span>最新</span><small>{{ $latestTools->count() }}</small></a>
|
||||
@foreach($categorySections as $index => $section)
|
||||
<a class="tool-side-link" href="#section-{{ $section['slug'] }}">
|
||||
<i class="bi {{ $icons[$index % count($icons)] }}"></i>
|
||||
<span>{{ $section['name'] }}</span>
|
||||
<small>{{ $section['count'] }}</small>
|
||||
</a>
|
||||
@endforeach
|
||||
@if(($modules['hot_tools']['enabled'] ?? true) === true)
|
||||
<a class="tool-side-link" href="#section-hot"><i class="bi bi-fire"></i><span>热门</span><small>{{ $hotTools->count() }}</small></a>
|
||||
@endif
|
||||
@if(($modules['latest_tools']['enabled'] ?? true) === true)
|
||||
<a class="tool-side-link" href="#section-latest"><i class="bi bi-clock-history"></i><span>最新</span><small>{{ $latestTools->count() }}</small></a>
|
||||
@endif
|
||||
@if(($modules['category_sections']['enabled'] ?? true) === true)
|
||||
@foreach($categorySections as $index => $section)
|
||||
<a class="tool-side-link" href="#section-{{ $section['slug'] }}">
|
||||
<i class="bi {{ $icons[$index % count($icons)] }}"></i>
|
||||
<span>{{ $section['name'] }}</span>
|
||||
<small>{{ $section['count'] }}</small>
|
||||
</a>
|
||||
@endforeach
|
||||
@endif
|
||||
</nav>
|
||||
|
||||
<section class="tool-hero">
|
||||
@@ -534,14 +545,19 @@
|
||||
@endforeach
|
||||
</nav>
|
||||
|
||||
<section class="tool-kpis" aria-label="工具统计">
|
||||
<article class="tool-kpi"><span>收录工具</span><b>{{ $toolStats['total'] ?? 0 }}</b></article>
|
||||
<article class="tool-kpi"><span>支持 API</span><b>{{ $toolStats['api'] ?? 0 }}</b></article>
|
||||
<article class="tool-kpi"><span>免费可用</span><b>{{ $toolStats['free'] ?? 0 }}</b></article>
|
||||
<article class="tool-kpi"><span>7天更新</span><b>{{ $toolStats['updated_7d'] ?? 0 }}</b></article>
|
||||
</section>
|
||||
<x-portal.stat-grid
|
||||
grid-class="tool-kpis"
|
||||
item-class="tool-kpi"
|
||||
:stats="[
|
||||
['label' => '收录工具', 'value' => $toolStats['total'] ?? 0],
|
||||
['label' => '支持 API', 'value' => $toolStats['api'] ?? 0],
|
||||
['label' => '免费可用', 'value' => $toolStats['free'] ?? 0],
|
||||
['label' => '7天更新', 'value' => $toolStats['updated_7d'] ?? 0],
|
||||
]"
|
||||
/>
|
||||
</section>
|
||||
|
||||
@if(($modules['channel_cards']['enabled'] ?? true) === true)
|
||||
<section class="tool-channel" aria-label="频道入口">
|
||||
<aside class="tool-channel-mini">
|
||||
<a href="{{ route('news.index') }}"><i class="bi bi-newspaper"></i>AI资讯</a>
|
||||
@@ -555,7 +571,9 @@
|
||||
<a class="tool-channel-card tutorial" href="{{ route('guides.index') }}">热门教程</a>
|
||||
<a class="tool-channel-card ad" href="{{ route('tools.list') }}">工具列表</a>
|
||||
</section>
|
||||
@endif
|
||||
|
||||
@if(($modules['promo_banners']['enabled'] ?? true) === true)
|
||||
<section class="tool-banner-row" aria-label="横幅推荐">
|
||||
<article class="tool-banner">
|
||||
<b>超全图片视频模板一键复制</b>
|
||||
@@ -566,39 +584,29 @@
|
||||
<small>免费试用</small>
|
||||
</article>
|
||||
</section>
|
||||
@endif
|
||||
|
||||
@if(($modules['hot_tools']['enabled'] ?? true) === true)
|
||||
<section id="section-hot" class="tool-section" aria-label="热门工具">
|
||||
<header class="tool-section-head">
|
||||
<h2><i class="bi bi-fire text-danger"></i> 热门工具</h2>
|
||||
<a href="{{ route('tools.list', ['tab' => 'recommended']) }}">查看更多</a>
|
||||
</header>
|
||||
<div class="tool-grid">
|
||||
@foreach($hotTools as $tool)
|
||||
<a class="tool-card" href="{{ route('tools.show', $tool->slug) }}">
|
||||
<div class="tool-card-name">{{ $tool->name }}</div>
|
||||
<div class="tool-card-meta">{{ $tool->category?->name ?? '未分类' }} · {{ $tool->pricing_type }}</div>
|
||||
<span class="tool-card-tag">{{ $tool->has_api ? '支持 API' : '无 API' }}</span>
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
<x-portal.tool-grid :tools="$hotTools" />
|
||||
</section>
|
||||
@endif
|
||||
|
||||
@if(($modules['latest_tools']['enabled'] ?? true) === true)
|
||||
<section id="section-latest" class="tool-section" aria-label="最新收录">
|
||||
<header class="tool-section-head">
|
||||
<h2><i class="bi bi-clock-history text-primary"></i> 最新收录</h2>
|
||||
<a href="{{ route('tools.list', ['tab' => 'latest']) }}">查看更多</a>
|
||||
</header>
|
||||
<div class="tool-grid">
|
||||
@foreach($latestTools as $tool)
|
||||
<a class="tool-card" href="{{ route('tools.show', $tool->slug) }}">
|
||||
<div class="tool-card-name">{{ $tool->name }}</div>
|
||||
<div class="tool-card-meta">{{ $tool->category?->name ?? '未分类' }} · {{ $tool->pricing_type }}</div>
|
||||
<span class="tool-card-tag">{{ $tool->has_api ? '支持 API' : '无 API' }}</span>
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
<x-portal.tool-grid :tools="$latestTools" />
|
||||
</section>
|
||||
@endif
|
||||
|
||||
@if(($modules['category_sections']['enabled'] ?? true) === true)
|
||||
@foreach($categorySections as $section)
|
||||
<section id="section-{{ $section['slug'] }}" class="tool-section" aria-label="{{ $section['name'] }}工具">
|
||||
<header class="tool-section-head">
|
||||
@@ -607,22 +615,108 @@
|
||||
</header>
|
||||
|
||||
@if($section['tools']->isNotEmpty())
|
||||
<div class="tool-grid">
|
||||
@foreach($section['tools'] as $tool)
|
||||
<a class="tool-card" href="{{ route('tools.show', $tool->slug) }}">
|
||||
<div class="tool-card-name">{{ $tool->name }}</div>
|
||||
<div class="tool-card-meta">{{ $tool->category?->name ?? '未分类' }} · {{ $tool->pricing_type }}</div>
|
||||
<span class="tool-card-tag">{{ $tool->has_api ? '支持 API' : '无 API' }}</span>
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
<x-portal.tool-grid :tools="$section['tools']" />
|
||||
@else
|
||||
<p class="text-muted-soft mb-0">该分类暂未收录工具</p>
|
||||
@endif
|
||||
</section>
|
||||
@endforeach
|
||||
@endif
|
||||
</section>
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
|
||||
@section('scripts')
|
||||
<script>
|
||||
(() => {
|
||||
const links = Array.from(document.querySelectorAll('.tool-side-link[href^="#section-"]'));
|
||||
const sections = Array.from(document.querySelectorAll('.tool-section[id^="section-"]'));
|
||||
|
||||
if (!links.length || !sections.length || !('IntersectionObserver' in window)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const linksById = new Map();
|
||||
links.forEach((link) => {
|
||||
const id = link.getAttribute('href')?.replace('#', '');
|
||||
if (id) {
|
||||
const group = linksById.get(id) || [];
|
||||
group.push(link);
|
||||
linksById.set(id, group);
|
||||
}
|
||||
});
|
||||
|
||||
const setActive = (activeId) => {
|
||||
links.forEach((link) => {
|
||||
const id = link.getAttribute('href')?.replace('#', '') || '';
|
||||
link.classList.toggle('is-active', id === activeId);
|
||||
});
|
||||
};
|
||||
|
||||
const syncHash = (id) => {
|
||||
const hash = `#${id}`;
|
||||
if (window.location.hash !== hash) {
|
||||
history.replaceState(null, '', hash);
|
||||
}
|
||||
};
|
||||
|
||||
links.forEach((link) => {
|
||||
link.addEventListener('click', (event) => {
|
||||
const id = link.getAttribute('href')?.replace('#', '');
|
||||
if (!id) {
|
||||
return;
|
||||
}
|
||||
|
||||
const target = document.getElementById(id);
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
setActive(id);
|
||||
syncHash(id);
|
||||
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
});
|
||||
});
|
||||
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
const visible = entries
|
||||
.filter((entry) => entry.isIntersecting)
|
||||
.sort((a, b) => b.intersectionRatio - a.intersectionRatio);
|
||||
|
||||
if (!visible.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const top = visible[0].target;
|
||||
if (top instanceof HTMLElement) {
|
||||
setActive(top.id);
|
||||
syncHash(top.id);
|
||||
}
|
||||
}, {
|
||||
rootMargin: '-18% 0px -64% 0px',
|
||||
threshold: [0.2, 0.45, 0.7],
|
||||
});
|
||||
|
||||
sections.forEach((section) => observer.observe(section));
|
||||
|
||||
if (window.location.hash) {
|
||||
const hashId = window.location.hash.replace('#', '');
|
||||
const target = document.getElementById(hashId);
|
||||
if (target) {
|
||||
setActive(hashId);
|
||||
window.requestAnimationFrame(() => {
|
||||
target.scrollIntoView({ behavior: 'auto', block: 'start' });
|
||||
});
|
||||
} else {
|
||||
setActive(sections[0].id);
|
||||
syncHash(sections[0].id);
|
||||
}
|
||||
} else {
|
||||
setActive(sections[0].id);
|
||||
syncHash(sections[0].id);
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
@endsection
|
||||
|
||||
Reference in New Issue
Block a user