Update transitions to persist theme color smoothly
This commit is contained in:
+43
-38
@@ -1,53 +1,58 @@
|
||||
.link-card {
|
||||
list-style: none;
|
||||
display: flex;
|
||||
background-color: var(--background-secondary);
|
||||
background-position: 100%;
|
||||
border-radius: var(--spacing-03);
|
||||
height: 8.5rem;
|
||||
position: relative;
|
||||
--shadow-color: rgb(0 0 0 / 0.04);
|
||||
box-shadow: 0px 0px 0px 1px var(--background-selected),
|
||||
0px 1px 1px -0.5px var(--shadow-color),
|
||||
0px 3px 3px -1.5px var(--shadow-color),
|
||||
0px 12px 12px -6px var(--shadow-color);
|
||||
transition:all .2s ease-out;
|
||||
list-style: none;
|
||||
display: flex;
|
||||
background-color: var(--background-secondary);
|
||||
background-position: 100%;
|
||||
border-radius: var(--spacing-03);
|
||||
height: 8.5rem;
|
||||
position: relative;
|
||||
--shadow-color: rgb(0 0 0 / 0.04);
|
||||
box-shadow:
|
||||
0px 0px 0px 1px var(--background-selected),
|
||||
0px 1px 1px -0.5px var(--shadow-color),
|
||||
0px 3px 3px -1.5px var(--shadow-color),
|
||||
0px 12px 12px -6px var(--shadow-color);
|
||||
content-visibility: auto;
|
||||
contain-intrinsic-size: 8.5rem;
|
||||
will-change: transform;
|
||||
transition: box-shadow 0.2s ease-out;
|
||||
}
|
||||
|
||||
.link-card>a {
|
||||
width: 100%;
|
||||
text-decoration: none;
|
||||
padding: 0.8rem 1.2rem;
|
||||
color: var(--support-info);
|
||||
justify-content: space-between;
|
||||
.link-card > a {
|
||||
width: 100%;
|
||||
text-decoration: none;
|
||||
padding: 0.8rem 1.2rem;
|
||||
color: var(--support-info);
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
p {
|
||||
color: var(--text-secondary);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.link-card:is(:hover, :focus-within) {
|
||||
background-position: 0;
|
||||
box-shadow: 0px 0px 0px 2px var(--link),
|
||||
0px 1px 1px -0.5px var(--shadow-color),
|
||||
0px 3px 3px -1.5px var(--shadow-color),
|
||||
0px 12px 12px -6px var(--shadow-color);
|
||||
background-position: 0;
|
||||
box-shadow:
|
||||
0px 0px 0px 2px var(--link),
|
||||
0px 1px 1px -0.5px var(--shadow-color),
|
||||
0px 3px 3px -1.5px var(--shadow-color),
|
||||
0px 12px 12px -6px var(--shadow-color);
|
||||
}
|
||||
|
||||
p.distribution {
|
||||
margin: var(--spacing-00);
|
||||
position: absolute;
|
||||
bottom: var(--spacing-06);
|
||||
margin: var(--spacing-00);
|
||||
position: absolute;
|
||||
bottom: var(--spacing-06);
|
||||
}
|
||||
|
||||
span.tag {
|
||||
background-color: var(--background-selected);
|
||||
padding: calc(.25rem - 1px) calc(.5rem - 1px);
|
||||
border-radius: var(--spacing-02);
|
||||
display: inline-block;
|
||||
color: var(--text-secondary);
|
||||
margin-top: var(--spacing-08);
|
||||
font-size: var(--desktop-caption);
|
||||
line-height: var(--lh-desktop-caption);
|
||||
font-family: var(--body-copy);
|
||||
}
|
||||
background-color: var(--background-selected);
|
||||
padding: calc(0.25rem - 1px) calc(0.5rem - 1px);
|
||||
border-radius: var(--spacing-02);
|
||||
display: inline-block;
|
||||
color: var(--text-secondary);
|
||||
margin-top: var(--spacing-08);
|
||||
font-size: var(--desktop-caption);
|
||||
line-height: var(--lh-desktop-caption);
|
||||
font-family: var(--body-copy);
|
||||
}
|
||||
|
||||
+12
-14
@@ -1,19 +1,17 @@
|
||||
import "./Card.css";
|
||||
|
||||
export default function Card(props) {
|
||||
const {href, title, body, tag} = props;
|
||||
const { href, title, body, tag } = props;
|
||||
|
||||
return <li className="link-card">
|
||||
<a href={href}>
|
||||
<strong className="nu-c-h6 nu-u-mt-1 nu-u-mb-1">
|
||||
{title}
|
||||
</strong>
|
||||
<p className="nu-c-fs-small nu-u-mt-1 nu-u-mb-1">
|
||||
{body}
|
||||
</p>
|
||||
<p className="distribution">
|
||||
<span className="tag">{tag}</span>
|
||||
</p>
|
||||
</a>
|
||||
</li>
|
||||
return (
|
||||
<li className="link-card">
|
||||
<a href={href}>
|
||||
<strong className="nu-c-h6 nu-u-mt-1 nu-u-mb-1">{title}</strong>
|
||||
<p className="nu-c-fs-small nu-u-mt-1 nu-u-mb-1">{body}</p>
|
||||
<p className="distribution">
|
||||
<span className="tag">{tag}</span>
|
||||
</p>
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,33 +1,29 @@
|
||||
import { useMemo } from "react";
|
||||
import Card from "./Card";
|
||||
import "./CardsContainer.css";
|
||||
import data from "../data/tools.json";
|
||||
|
||||
import data from "../data/tools.json"
|
||||
export default function CardsContainer({ filter }) {
|
||||
const filteredCards = useMemo(() => {
|
||||
return data.tools
|
||||
.filter((item) => filter === "all" || filter === item.category)
|
||||
.flatMap((item) => item.content)
|
||||
.sort((a, b) => a.title.localeCompare(b.title));
|
||||
}, [filter]);
|
||||
|
||||
export default function CardsContainer(props) {
|
||||
const { filter } = props;
|
||||
|
||||
return <section>
|
||||
<ul role="list" className="link-card-grid">
|
||||
{data.tools
|
||||
.filter(item => {
|
||||
if (filter === "all" || filter === item.category) {
|
||||
return item;
|
||||
}
|
||||
})
|
||||
.flatMap(item => item.content)
|
||||
.sort((a, b) => {
|
||||
return a.title < b.title ? -1 : 1;
|
||||
})
|
||||
.map(({url, title, body, tag}, i) => {
|
||||
return <Card
|
||||
key={i}
|
||||
return (
|
||||
<section>
|
||||
<ul role="list" className="link-card-grid">
|
||||
{filteredCards.map(({ url, title, body, tag }, i) => (
|
||||
<Card
|
||||
key={`${title}-${i}`}
|
||||
href={url}
|
||||
title={title}
|
||||
body={body}
|
||||
tag={tag}
|
||||
/>
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
</section>
|
||||
}
|
||||
))}
|
||||
</ul>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,39 +4,47 @@ import data from "../data/tools.json";
|
||||
import "./CategoryNavItem.css";
|
||||
|
||||
export default function CategoryNavItem(props) {
|
||||
const { title, category, filter } = props;
|
||||
const [isActive, setIsActive] = useState(false);
|
||||
const { title, category, filter } = props;
|
||||
const [isActive, setIsActive] = useState(false);
|
||||
|
||||
const getCategoryCount = () => {
|
||||
if (category === "all") {
|
||||
return data.tools.reduce((acc, item) => acc + item.content.length, 0);
|
||||
}
|
||||
const handleNavigation = (e) => {
|
||||
e.preventDefault();
|
||||
navigate(`/categories/${category}`, {
|
||||
history: "push",
|
||||
state: { category },
|
||||
});
|
||||
};
|
||||
|
||||
const navItemData = data.tools.filter((item) => item.category === category);
|
||||
return navItemData[0]?.content.length;
|
||||
};
|
||||
const getCategoryCount = () => {
|
||||
if (category === "all") {
|
||||
return data.tools.reduce((acc, item) => acc + item.content.length, 0);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
let subscription = true;
|
||||
const navItemData = data.tools.filter((item) => item.category === category);
|
||||
return navItemData[0]?.content.length;
|
||||
};
|
||||
|
||||
if (filter === category) {
|
||||
setIsActive(true);
|
||||
} else {
|
||||
setIsActive(false);
|
||||
}
|
||||
useEffect(() => {
|
||||
let subscription = true;
|
||||
|
||||
return () => (subscription = !subscription);
|
||||
}, [filter]);
|
||||
if (filter === category) {
|
||||
setIsActive(true);
|
||||
} else {
|
||||
setIsActive(false);
|
||||
}
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={() => navigate(`/categories/${category}`)}
|
||||
className={`nav__item nu-u-text--secondary-alt nu-c-fs-normal nu-u-py-5 nu-u-px-0 nu-u-me-8 nav__item--filter ${
|
||||
isActive ? "is-active" : ""
|
||||
}`}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `${title} - ${getCategoryCount()}`,
|
||||
}}
|
||||
></button>
|
||||
);
|
||||
return () => (subscription = !subscription);
|
||||
}, [filter]);
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={() => navigate(`/categories/${category}`)}
|
||||
className={`nav__item nu-u-text--secondary-alt nu-c-fs-normal nu-u-py-5 nu-u-px-0 nu-u-me-8 nav__item--filter ${
|
||||
isActive ? "is-active" : ""
|
||||
}`}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `${title} - ${getCategoryCount()}`,
|
||||
}}
|
||||
></button>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import CategoryNav from "./CategoryNav";
|
||||
import CardsContainer from "./CardsContainer";
|
||||
|
||||
export default function Dashboard({ category }) {
|
||||
return (
|
||||
<>
|
||||
<CategoryNav filter={category} />
|
||||
<CardsContainer filter={category} />
|
||||
</>
|
||||
);
|
||||
const [currentCategory, setCurrentCategory] = useState(category);
|
||||
|
||||
useEffect(() => {
|
||||
setCurrentCategory(category);
|
||||
}, [category]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<CategoryNav filter={category} />
|
||||
<CardsContainer filter={category} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user