Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: getToggledStyles() #363

Merged
merged 6 commits into from
Jul 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 23 additions & 3 deletions components/Footer.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,41 @@
// Copyright 2023 the Deno authors. All rights reserved. MIT license.
import {
ACTIVE_LINK_STYLES,
LINK_STYLES,
NAV_STYLES,
SITE_BAR_STYLES,
SITE_NAME,
} from "@/utils/constants.ts";
import { Discord, GitHub } from "./Icons.tsx";
import { getToggledStyles } from "@/utils/display.ts";

export default function Footer() {
export default function Footer(props: { url: URL }) {
return (
<footer
class={`${SITE_BAR_STYLES} flex-col md:flex-row mt-8`}
>
<p>© {SITE_NAME}</p>
<nav class={NAV_STYLES}>
<a href="/stats" class={LINK_STYLES}>Stats</a>
<a href="/blog" class={LINK_STYLES}>Blog</a>
<a
href="/stats"
class={getToggledStyles(
LINK_STYLES,
ACTIVE_LINK_STYLES,
props.url.pathname === "/stats",
)}
>
Stats
</a>
<a
href="/blog"
class={getToggledStyles(
LINK_STYLES,
ACTIVE_LINK_STYLES,
props.url.pathname === "/blog",
)}
>
Blog
</a>
<a
href="https://discord.gg/deno"
target="_blank"
Expand Down
39 changes: 35 additions & 4 deletions components/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
// Copyright 2023 the Deno authors. All rights reserved. MIT license.
import {
ACTIVE_LINK_STYLES,
BUTTON_STYLES,
LINK_STYLES,
NAV_STYLES,
SITE_BAR_STYLES,
SITE_NAME,
} from "@/utils/constants.ts";
import { stripe } from "@/utils/payments.ts";
import { Bell, CircleFilled } from "./Icons.tsx";
import { getToggledStyles } from "@/utils/display.ts";

export default function Header(
props: { sessionId?: string; hasNotifications: boolean },
props: { sessionId?: string; hasNotifications: boolean; url: URL },
) {
return (
<header class={SITE_BAR_STYLES}>
Expand All @@ -23,13 +26,41 @@ export default function Header(
/>
</a>
<nav class={NAV_STYLES}>
{stripe ? <a href="/pricing" class={LINK_STYLES}>Pricing</a> : null}
{stripe
? (
<a
href="/pricing"
class={getToggledStyles(
LINK_STYLES,
ACTIVE_LINK_STYLES,
props.url.pathname === "/pricing",
)}
>
Pricing
</a>
)
: null}
{props.sessionId
? <a href="/account" class={LINK_STYLES}>Account</a>
? (
<a
href="/account"
class={getToggledStyles(
LINK_STYLES,
ACTIVE_LINK_STYLES,
props.url.pathname === "/account",
)}
>
Account
</a>
)
: <a href="/signin" class={LINK_STYLES}>Sign in</a>}
<a
href="/account/notifications"
class={LINK_STYLES + " relative"}
class={getToggledStyles(
LINK_STYLES,
ACTIVE_LINK_STYLES,
props.url.pathname === "/account/notifications",
) + " relative"}
aria-label="Notifications"
>
<Bell class="w-6 h-6" />
Expand Down
3 changes: 2 additions & 1 deletion routes/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,12 @@ export default function App(props: AppProps) {
<div class="dark:bg-gray-900">
<div class="flex flex-col min-h-screen mx-auto max-w-7xl w-full dark:text-white">
<Header
url={props.url}
sessionId={props.data?.sessionId}
hasNotifications={props.data?.hasNotifications}
/>
<props.Component />
<Footer />
<Footer url={props.url} />
</div>
</div>
</>
Expand Down
43 changes: 36 additions & 7 deletions routes/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// Copyright 2023 the Deno authors. All rights reserved. MIT license.
import type { Handlers, PageProps } from "$fresh/server.ts";
import { INPUT_STYLES } from "@/utils/constants.ts";
import { calcLastPage, calcPageNum, PAGE_LENGTH } from "@/utils/pagination.ts";
import type { State } from "./_middleware.ts";
import ItemSummary from "@/components/ItemSummary.tsx";
Expand All @@ -15,6 +14,8 @@ import {
type User,
} from "@/utils/db.ts";
import { DAY, WEEK } from "std/datetime/constants.ts";
import { getToggledStyles } from "@/utils/display.ts";
import { ACTIVE_LINK_STYLES, LINK_STYLES } from "@/utils/constants.ts";

interface HomePageData extends State {
itemsUsers: User[];
Expand Down Expand Up @@ -57,21 +58,49 @@ export const handler: Handlers<HomePageData, State> = {
},
};

function TimeSelector() {
function TimeSelector(props: { url: URL }) {
const timeAgo = props.url.searchParams.get("time-ago");
return (
<div class="flex justify-center my-4 gap-2">
<div class="flex justify-center my-4 gap-8">
{/* These links do not preserve current URL queries. E.g. if ?page=2, that'll be removed once one of these links is clicked */}
<a class={INPUT_STYLES} href="/?time-ago=week">Last Week</a>
<a class={INPUT_STYLES} href="/?time-ago=month">Last Month</a>
<a class={INPUT_STYLES} href="/?time-ago=all">All time</a>
<a
class={getToggledStyles(
LINK_STYLES,
ACTIVE_LINK_STYLES,
timeAgo === null || timeAgo === "week",
)}
href="/?time-ago=week"
>
Last Week
</a>
<a
class={getToggledStyles(
LINK_STYLES,
ACTIVE_LINK_STYLES,
timeAgo === "month",
)}
href="/?time-ago=month"
>
Last Month
</a>
<a
class={getToggledStyles(
LINK_STYLES,
ACTIVE_LINK_STYLES,
timeAgo === "all",
)}
href="/?time-ago=all"
>
All time
</a>
</div>
);
}

export default function HomePage(props: PageProps<HomePageData>) {
return (
<main class="flex-1 p-4">
<TimeSelector />
<TimeSelector url={props.url} />
{props.data.items.map((item, index) => (
<ItemSummary
item={item}
Expand Down
3 changes: 2 additions & 1 deletion utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ export const SITE_BAR_STYLES = "flex justify-between p-4 gap-4";
export const NAV_STYLES =
"flex flex-wrap justify-start gap-x-8 gap-y-4 items-center justify-between h-full";
export const LINK_STYLES =
"text-gray-500 transition duration-300 hover:text-black dark:hover:text-white";
"text-gray-500 transition duration-300 hover:(text-black dark:text-white)";
export const ACTIVE_LINK_STYLES = "!text-black !dark:text-white";
25 changes: 25 additions & 0 deletions utils/display.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,28 @@ export function timeAgo(time: number | Date) {
else if (minutes < 24 * 60) return pluralize(~~(minutes / 60), "hour");
else return pluralize(~~(minutes / (24 * 60)), "day");
}

/**
* Dynamically generates styles depending on whether the given condition is truthy.
* This is used to visually highlight a link if it matches the current page.
*
* @example
* ```ts
* import { getToggledStyles } from "@/utils/display.ts";
*
* // Returns "text-gray !text-black"
* const activeLinkStyles = getToggledStyles("text-gray", "!text-black", true);
*
* // Returns "text-gray"
* const inactiveLinkStyles = getToggledStyles("text-gray", "!text-black", false);
* ```
*/
export function getToggledStyles(
baseStyles: string,
toggledStyles: string,
cond: boolean,
) {
let styles = baseStyles;
if (cond) styles += " " + toggledStyles;
return styles;
}
14 changes: 13 additions & 1 deletion utils/display_test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// Copyright 2023 the Deno authors. All rights reserved. MIT license.
import { pluralize, timeAgo } from "./display.ts";
import { getToggledStyles, pluralize, timeAgo } from "./display.ts";
import { DAY, HOUR, MINUTE, SECOND } from "std/datetime/constants.ts";
import { assertEquals } from "std/testing/asserts.ts";
import { ACTIVE_LINK_STYLES, LINK_STYLES } from "@/utils/constants.ts";

Deno.test("[display] pluralize()", () => {
assertEquals(pluralize(0, "item"), "0 items");
Expand All @@ -22,3 +23,14 @@ Deno.test("[display] timeAgo()", () => {
assertEquals(timeAgo(Date.now() - DAY - HOUR * 12), "1 day");
assertEquals(timeAgo(Date.now() - DAY * 5), "5 days");
});

Deno.test("[display] getToggledStyles()", () => {
assertEquals(
getToggledStyles(LINK_STYLES, ACTIVE_LINK_STYLES, false),
LINK_STYLES,
);
assertEquals(
getToggledStyles(LINK_STYLES, ACTIVE_LINK_STYLES, true),
LINK_STYLES + " " + ACTIVE_LINK_STYLES,
);
});