feat: Added featured technique spotlight section and converted recently…
- "frontend/src/pages/Home.tsx" - "frontend/src/App.css" GSD-Task: S03/T02
This commit is contained in:
parent
810f96a640
commit
348089d635
2 changed files with 136 additions and 7 deletions
|
|
@ -1173,8 +1173,78 @@ a.app-footer__repo:hover {
|
|||
|
||||
/* ── Recently Added section ───────────────────────────────────────────────── */
|
||||
|
||||
/* ── Featured technique spotlight ──────────────────────────────────────── */
|
||||
|
||||
.home-featured {
|
||||
max-width: 42rem;
|
||||
margin: 0 auto 1.5rem;
|
||||
padding: 1.25rem 1.5rem;
|
||||
background: var(--color-bg-surface);
|
||||
border: 1px solid var(--color-border);
|
||||
border-left: 3px solid var(--color-accent);
|
||||
border-radius: 0.5rem;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.home-featured__label {
|
||||
font-size: 0.6875rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
color: var(--color-accent);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.home-featured__title {
|
||||
display: block;
|
||||
font-size: 1.25rem;
|
||||
font-weight: 700;
|
||||
color: var(--color-text);
|
||||
text-decoration: none;
|
||||
margin-bottom: 0.5rem;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.home-featured__title:hover {
|
||||
color: var(--color-accent-hover);
|
||||
}
|
||||
|
||||
.home-featured__summary {
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-text-secondary);
|
||||
line-height: 1.5;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.home-featured__meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.home-featured__moments {
|
||||
font-size: 0.75rem;
|
||||
color: var(--color-text-tertiary);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.home-featured__creator {
|
||||
display: block;
|
||||
font-size: 0.8125rem;
|
||||
color: var(--color-text-secondary);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.home-featured__creator:hover {
|
||||
color: var(--color-accent-hover);
|
||||
}
|
||||
|
||||
/* ── Recently added ───────────────────────────────────────────────────── */
|
||||
|
||||
.recent-section {
|
||||
max-width: 36rem;
|
||||
max-width: 42rem;
|
||||
margin: 0 auto 2rem;
|
||||
}
|
||||
|
||||
|
|
@ -1185,8 +1255,8 @@ a.app-footer__repo:hover {
|
|||
}
|
||||
|
||||
.recent-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
|
|
@ -2209,6 +2279,14 @@ a.app-footer__repo:hover {
|
|||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.recent-list {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.home-featured {
|
||||
padding: 1rem 1.25rem;
|
||||
}
|
||||
|
||||
.technique-header__title {
|
||||
font-size: 1.375rem;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ export default function Home() {
|
|||
const [query, setQuery] = useState("");
|
||||
const [suggestions, setSuggestions] = useState<SearchResultItem[]>([]);
|
||||
const [showDropdown, setShowDropdown] = useState(false);
|
||||
const [featured, setFeatured] = useState<TechniqueListItem | null>(null);
|
||||
const [recent, setRecent] = useState<TechniqueListItem[]>([]);
|
||||
const [recentLoading, setRecentLoading] = useState(true);
|
||||
const [popularTopics, setPopularTopics] = useState<{name: string; count: number}[]>([]);
|
||||
|
|
@ -33,12 +34,28 @@ export default function Home() {
|
|||
inputRef.current?.focus();
|
||||
}, []);
|
||||
|
||||
// Load featured technique (random)
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
void (async () => {
|
||||
try {
|
||||
const res = await fetchTechniques({ sort: "random", limit: 1 });
|
||||
if (!cancelled && res.items.length > 0) setFeatured(res.items[0]);
|
||||
} catch {
|
||||
// silently ignore — optional section
|
||||
}
|
||||
})();
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Load recently added techniques
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
void (async () => {
|
||||
try {
|
||||
const res = await fetchTechniques({ limit: 5 });
|
||||
const res = await fetchTechniques({ sort: "recent", limit: 6 });
|
||||
if (!cancelled) setRecent(res.items);
|
||||
} catch {
|
||||
// silently ignore — not critical
|
||||
|
|
@ -255,6 +272,37 @@ export default function Home() {
|
|||
</Link>
|
||||
</section>
|
||||
|
||||
{/* Featured Technique Spotlight */}
|
||||
{featured && (
|
||||
<section className="home-featured">
|
||||
<h3 className="home-featured__label">Featured Technique</h3>
|
||||
<Link to={`/techniques/${featured.slug}`} className="home-featured__title">
|
||||
{featured.title}
|
||||
</Link>
|
||||
{featured.summary && (
|
||||
<p className="home-featured__summary">{featured.summary}</p>
|
||||
)}
|
||||
<div className="home-featured__meta">
|
||||
{featured.topic_category && (
|
||||
<span className="badge badge--category">{featured.topic_category}</span>
|
||||
)}
|
||||
{featured.topic_tags && featured.topic_tags.length > 0 && featured.topic_tags.map(tag => (
|
||||
<span key={tag} className="pill pill--tag">{tag}</span>
|
||||
))}
|
||||
{featured.key_moment_count > 0 && (
|
||||
<span className="home-featured__moments">
|
||||
{featured.key_moment_count} moment{featured.key_moment_count !== 1 ? "s" : ""}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{featured.creator_name && (
|
||||
<Link to={`/creators/${featured.creator_slug}`} className="home-featured__creator">
|
||||
by {featured.creator_name}
|
||||
</Link>
|
||||
)}
|
||||
</section>
|
||||
)}
|
||||
|
||||
{/* Recently Added */}
|
||||
<section className="recent-section">
|
||||
<h3 className="recent-section__title">Recently Added</h3>
|
||||
|
|
@ -264,7 +312,10 @@ export default function Home() {
|
|||
<div className="empty-state">No techniques yet.</div>
|
||||
) : (
|
||||
<div className="recent-list">
|
||||
{recent.map((t) => (
|
||||
{recent
|
||||
.filter((t) => t.id !== featured?.id)
|
||||
.slice(0, 4)
|
||||
.map((t) => (
|
||||
<Link
|
||||
key={t.id}
|
||||
to={`/techniques/${t.slug}`}
|
||||
|
|
@ -285,8 +336,8 @@ export default function Home() {
|
|||
))}
|
||||
{t.summary && (
|
||||
<span className="recent-card__summary">
|
||||
{t.summary.length > 100
|
||||
? `${t.summary.slice(0, 100)}…`
|
||||
{t.summary.length > 150
|
||||
? `${t.summary.slice(0, 150)}…`
|
||||
: t.summary}
|
||||
</span>
|
||||
)}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue