Merge terry-staging into main
All checks were successful
Deploy to Frontend Servers / deploy (push) Successful in 19s
All checks were successful
Deploy to Frontend Servers / deploy (push) Successful in 19s
This commit is contained in:
@@ -16,8 +16,13 @@ function isPlaceholderAsset(path: string | undefined | null) {
|
|||||||
return !path || path.includes("placeholder-cover");
|
return !path || path.includes("placeholder-cover");
|
||||||
}
|
}
|
||||||
|
|
||||||
const CARD_CLASS =
|
const CARD_BASE_CLASS =
|
||||||
"group flex w-[208px] shrink-0 flex-col overflow-hidden rounded-xl border bg-[#1D1E23] transition hover:border-ark-gold/55 md:w-[240px] lg:w-[246.4px] min-[1100px]:max-xl:w-[273px] xl:w-[246.4px]";
|
"group flex shrink-0 flex-col overflow-hidden rounded-xl border bg-[#1D1E23] transition hover:border-ark-gold/55";
|
||||||
|
|
||||||
|
const CARD_CAROUSEL_SIZE_CLASS =
|
||||||
|
"w-[208px] md:w-[240px] lg:w-[246.4px] min-[1100px]:max-xl:w-[273px] xl:w-[246.4px]";
|
||||||
|
|
||||||
|
const CARD_GRID_SIZE_CLASS = "w-full max-w-[360px] md:max-w-none";
|
||||||
|
|
||||||
type RecommendedResource = Resource & {
|
type RecommendedResource = Resource & {
|
||||||
downloadPostId?: string;
|
downloadPostId?: string;
|
||||||
@@ -28,10 +33,12 @@ export function RecommendedCard({
|
|||||||
r,
|
r,
|
||||||
visualIndex = 0,
|
visualIndex = 0,
|
||||||
useFigmaDesign = false,
|
useFigmaDesign = false,
|
||||||
|
layout = "carousel",
|
||||||
}: {
|
}: {
|
||||||
r: RecommendedResource;
|
r: RecommendedResource;
|
||||||
visualIndex?: number;
|
visualIndex?: number;
|
||||||
useFigmaDesign?: boolean;
|
useFigmaDesign?: boolean;
|
||||||
|
layout?: "carousel" | "grid";
|
||||||
}) {
|
}) {
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const [isDownloading, setIsDownloading] = useState(false);
|
const [isDownloading, setIsDownloading] = useState(false);
|
||||||
@@ -78,7 +85,9 @@ export function RecommendedCard({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<article
|
<article
|
||||||
className={`${CARD_CLASS} ${
|
className={`${CARD_BASE_CLASS} ${
|
||||||
|
layout === "grid" ? CARD_GRID_SIZE_CLASS : CARD_CAROUSEL_SIZE_CLASS
|
||||||
|
} ${
|
||||||
useFigmaDesign
|
useFigmaDesign
|
||||||
? "border-[#27292E]"
|
? "border-[#27292E]"
|
||||||
: "border-transparent md:border-ark-line md:bg-ark-panel"
|
: "border-transparent md:border-ark-line md:bg-ark-panel"
|
||||||
@@ -86,7 +95,7 @@ export function RecommendedCard({
|
|||||||
>
|
>
|
||||||
<Link
|
<Link
|
||||||
to={`/resource/${r.id}`}
|
to={`/resource/${r.id}`}
|
||||||
className="relative block h-[108px] overflow-hidden bg-[#111116] md:aspect-[246.4/138.6] md:h-auto"
|
className="relative block aspect-[208/108] overflow-hidden bg-[#111116]"
|
||||||
>
|
>
|
||||||
{cover ? (
|
{cover ? (
|
||||||
<img
|
<img
|
||||||
@@ -202,7 +211,7 @@ export function ComingSoonRecommendedCard({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<article
|
<article
|
||||||
className={`${CARD_CLASS} cursor-default border-transparent opacity-95 md:border-ark-line md:bg-ark-panel`}
|
className={`${CARD_BASE_CLASS} ${CARD_CAROUSEL_SIZE_CLASS} cursor-default border-transparent opacity-95 md:border-ark-line md:bg-ark-panel`}
|
||||||
aria-label="即将到来"
|
aria-label="即将到来"
|
||||||
>
|
>
|
||||||
<div className="relative block h-[108px] overflow-hidden bg-black md:aspect-[246.4/138.6] md:h-auto">
|
<div className="relative block h-[108px] overflow-hidden bg-black md:aspect-[246.4/138.6] md:h-auto">
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ export function Home() {
|
|||||||
getJSON<{ items: Post[] }>(`/api/posts/recommended${postQ}&limit=12`),
|
getJSON<{ items: Post[] }>(`/api/posts/recommended${postQ}&limit=12`),
|
||||||
getJSON<{ items: Post[] }>(`/api/posts${postQ}&sort=latest&limit=5`),
|
getJSON<{ items: Post[] }>(`/api/posts${postQ}&sort=latest&limit=5`),
|
||||||
getJSON<{ items: Post[] }>(
|
getJSON<{ items: Post[] }>(
|
||||||
`/api/posts${postQ}&sort=popular&limit=5`,
|
`/api/posts${postQ}&tag=popular&limit=5`,
|
||||||
).catch((): { items: Post[] } => ({ items: [] })),
|
).catch((): { items: Post[] } => ({ items: [] })),
|
||||||
])
|
])
|
||||||
.then(([c, r, l, p]) => {
|
.then(([c, r, l, p]) => {
|
||||||
@@ -179,6 +179,7 @@ export function Home() {
|
|||||||
}, [hash, cats.length, rec.length, latest.length, popular.length]);
|
}, [hash, cats.length, rec.length, latest.length, popular.length]);
|
||||||
|
|
||||||
const latestPlaceholderCount = Math.max(0, 5 - latest.length);
|
const latestPlaceholderCount = Math.max(0, 5 - latest.length);
|
||||||
|
const hasPopular = popular.length > 0 || popularPosts.length > 0;
|
||||||
const popularPlaceholderCount = Math.max(0, 5 - popular.length);
|
const popularPlaceholderCount = Math.max(0, 5 - popular.length);
|
||||||
const recommendedDotCount = rec.length;
|
const recommendedDotCount = rec.length;
|
||||||
const activeRecommendedDot =
|
const activeRecommendedDot =
|
||||||
@@ -375,7 +376,7 @@ export function Home() {
|
|||||||
<MessageBubble key={post.id} post={post} />
|
<MessageBubble key={post.id} post={post} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-7 hidden gap-3 min-[576px]:grid-cols-2 md:grid md:gap-4 lg:grid-cols-3 xl:grid-cols-5">
|
<div className="mt-7 hidden grid-cols-1 gap-3 min-[576px]:grid-cols-2 md:grid md:grid-cols-2 md:gap-4 lg:grid-cols-3 xl:grid-cols-5">
|
||||||
{latest.map((r) => (
|
{latest.map((r) => (
|
||||||
<LatestUpdateRow key={r.id} r={r} iconKey={iconKeyForResource(r)} />
|
<LatestUpdateRow key={r.id} r={r} iconKey={iconKeyForResource(r)} />
|
||||||
))}
|
))}
|
||||||
@@ -388,31 +389,37 @@ export function Home() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section id="popular" className="scroll-mt-16 md:scroll-mt-24">
|
{hasPopular ? (
|
||||||
<div className="px-4 md:px-0">
|
<section id="popular" className="scroll-mt-16 md:scroll-mt-24">
|
||||||
<SectionHeader
|
<div className="px-4 md:px-0">
|
||||||
title={t("popularSection")}
|
<SectionHeader
|
||||||
viewAllTo="/browse?sort=popular"
|
title={t("popularSection")}
|
||||||
viewAllLabel={t("viewAll")}
|
viewAllTo="/browse?sort=popular"
|
||||||
/>
|
viewAllLabel={t("viewAll")}
|
||||||
</div>
|
|
||||||
<div className="flex flex-col gap-3 md:hidden">
|
|
||||||
{popularPosts.slice(0, 5).map((post) => (
|
|
||||||
<MessageBubble key={post.id} post={post} />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
<div className="mt-7 hidden gap-3 min-[576px]:grid-cols-2 md:grid md:gap-4 lg:grid-cols-3 xl:grid-cols-5">
|
|
||||||
{popular.map((r) => (
|
|
||||||
<LatestUpdateRow key={r.id} r={r} iconKey={iconKeyForResource(r)} />
|
|
||||||
))}
|
|
||||||
{Array.from({ length: popularPlaceholderCount }).map((_, index) => (
|
|
||||||
<ComingSoonLatestUpdateRow
|
|
||||||
key={`popular-coming-soon-${index}`}
|
|
||||||
index={popular.length + index}
|
|
||||||
/>
|
/>
|
||||||
))}
|
</div>
|
||||||
</div>
|
<div className="flex flex-col gap-3 md:hidden">
|
||||||
</section>
|
{popularPosts.slice(0, 5).map((post) => (
|
||||||
|
<MessageBubble key={post.id} post={post} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="mt-7 hidden grid-cols-1 gap-3 min-[576px]:grid-cols-2 md:grid md:grid-cols-2 md:gap-4 lg:grid-cols-3 xl:grid-cols-5">
|
||||||
|
{popular.map((r) => (
|
||||||
|
<LatestUpdateRow
|
||||||
|
key={r.id}
|
||||||
|
r={r}
|
||||||
|
iconKey={iconKeyForResource(r)}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
{Array.from({ length: popularPlaceholderCount }).map((_, index) => (
|
||||||
|
<ComingSoonLatestUpdateRow
|
||||||
|
key={`popular-coming-soon-${index}`}
|
||||||
|
index={popular.length + index}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
) : null}
|
||||||
|
|
||||||
{categoryUnavailableOpen ? (
|
{categoryUnavailableOpen ? (
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -45,14 +45,17 @@ export function OfficialRecommendationsPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<section>
|
<section>
|
||||||
<SectionHeader title={t("officialSection")} />
|
<div className="mx-auto max-w-full px-4 md:max-w-[820px] md:px-0 lg:max-w-[1080px] xl:max-w-[1180px]">
|
||||||
<div className="mt-7 grid grid-cols-[repeat(auto-fill,208px)] justify-center gap-3 md:grid-cols-[repeat(auto-fill,240px)] md:justify-start md:gap-4 lg:grid-cols-[repeat(auto-fill,246.4px)]">
|
<SectionHeader title={t("officialSection")} />
|
||||||
|
</div>
|
||||||
|
<div className="mx-auto mt-7 grid max-w-full grid-cols-1 justify-items-center gap-3 px-4 min-[560px]:grid-cols-2 md:max-w-[820px] md:grid-cols-3 md:px-0 lg:max-w-[1080px] lg:grid-cols-4 xl:max-w-[1180px]">
|
||||||
{items.map((item, index) => (
|
{items.map((item, index) => (
|
||||||
<RecommendedCard
|
<RecommendedCard
|
||||||
key={item.id}
|
key={item.id}
|
||||||
r={item}
|
r={item}
|
||||||
visualIndex={index}
|
visualIndex={index}
|
||||||
useFigmaDesign
|
useFigmaDesign
|
||||||
|
layout="grid"
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user