Skip to content

Commit

Permalink
Merge pull request #37 from diffplug/feat/sub-navigation-tweaks
Browse files Browse the repository at this point in the history
Navigation polish
  • Loading branch information
WebsByTodd authored Oct 9, 2023
2 parents 207c193 + 90a6d26 commit 060bd31
Show file tree
Hide file tree
Showing 8 changed files with 184 additions and 10 deletions.
2 changes: 1 addition & 1 deletion docs/src/components/ButtonList.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import clsx from "clsx";
import Link from "next/link";
import { Button } from "./Button";
import { useRouter } from "next/dist/client/router";
import { useRouter } from "next/router";
import { getPathParts } from "@/lib/languageFromPath";

export function ButtonList() {
Expand Down
96 changes: 96 additions & 0 deletions docs/src/components/HeadingLanguageSelect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import {
LanguageSlug,
PathParts,
languageSlugsToLabels,
} from "@/lib/languageFromPath";
import { useResizing } from "@/lib/useResizing";
import clsx from "clsx";
import { Dispatch, SetStateAction } from "react";
import { Button } from "./Button";
import { CaretBottom } from "./Icons/CaretBottom";
import { Close } from "./Icons/Close";

type HeadingLanguageSelectProps = {
pathParts: PathParts;
setSelectIsOpen: Dispatch<SetStateAction<boolean>>;
isOpen: boolean;
handleChange(value: LanguageSlug): void;
};

export function HeadingLanguageSelect({
pathParts,
setSelectIsOpen,
isOpen,
handleChange,
}: HeadingLanguageSelectProps) {
const resizing = useResizing();
return (
<div className={clsx(["relative", "mb-[7px]"])}>
<Button
className={clsx([
"text-white",
"bg-blue",
"w-[70px]",
"rounded-[4px]",
"h-[30px]",
"z-20",
"relative",
"desktop:w-[94px]",
])}
onClick={() => setSelectIsOpen((prevIsOpen) => !prevIsOpen)}
>
{languageSlugsToLabels[pathParts.language]}
{isOpen ? (
<Close className={clsx(["h-[12px]", "w-[12px]"])} />
) : (
<CaretBottom className={clsx(["h-[12px]", "w-[12px]"])} />
)}
</Button>
<div className={clsx(["absolute", "top-0", "z-10", "flex", "flex-col"])}>
{Object.keys(languageSlugsToLabels)
.filter((slug) => slug !== pathParts.language)
.map((slug, idx) => (
<Button
className={clsx([
"w-[70px]",
"rounded-[4px]",
"h-[30px]",
"bg-white",
"hover:text-white",
"hover:bg-blue",
!resizing && "transition-transform",
"desktop:w-[94px]",
isOpen
? `translate-y-[${30 + (idx + 1) * 10}px]`
: `translate-y-[-${idx * 30}px]`,
isOpen
? `tablet:translate-y-[${35 + (idx + 1) * 10}px]`
: `tablet:translate-y-[-${idx * 35}px]`,
isOpen
? `desktop:translate-y-[${53 + (idx + 1) * 10}px]`
: `desktop:translate-y-[-${idx * 53}px]`,
])}
onClick={() => handleChange(slug as LanguageSlug)}
key={slug}
>
{languageSlugsToLabels[slug as LanguageSlug]}
</Button>
))}
</div>
</div>
);
}

/**
* **DO NOT DELETE** These are all possible outcomes of the math
* inside the string interpolation above. Tailwind magic isn't
* smart enough to do the math and it needs this list at build
* time in order to include these styles in the output.
*
* translate-y-[40px] translate-y-[50px] translate-y-[60px]
* translate-y-[-0px] translate-y-[-30px] translate-y-[-60px]
* tablet:translate-y-[45px] tablet:translate-y-[55px] tablet:translate-y-[65px]
* tablet:translate-y-[-0px] tablet:translate-y-[-35px] tablet:translate-y-[-70px]
* desktop:translate-y-[63px] desktop:translate-y-[73px] desktop:translate-y-[83px]
* desktop:translate-y-[-0px] desktop:translate-y-[-53px] desktop:translate-y-[-106px]
*/
46 changes: 46 additions & 0 deletions docs/src/components/NavHeading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { LanguageSlug, getPathParts } from "@/lib/languageFromPath";
import clsx from "clsx";
import { useRouter } from "next/router";
import { useState } from "react";
import { HeadingLanguageSelect } from "./HeadingLanguageSelect";
import { Selfie } from "./Selfie";

type NavHeadingProps = {
text: string;
};

export function NavHeading({ text }: NavHeadingProps) {
const router = useRouter();
const pathParts = getPathParts(router.pathname);
if (!pathParts.language) {
pathParts.language = "jvm";
}

function handleChange(value: LanguageSlug) {
let nextRoute = "/" + value;
if (pathParts.subpath) {
nextRoute += "/" + pathParts.subpath;
}
router.push(nextRoute + `#${text}`);
setSelectIsOpen(false);
}

const [selectIsOpen, setSelectIsOpen] = useState<boolean>(false);

return (
<>
<br />
<div className={clsx(["flex", "items-end", "justify-between"])}>
<h2 id={text}>
<Selfie /> is {text}{" "}
</h2>
<HeadingLanguageSelect
pathParts={pathParts}
isOpen={selectIsOpen}
setSelectIsOpen={setSelectIsOpen}
handleChange={handleChange}
/>
</div>
</>
);
}
6 changes: 4 additions & 2 deletions docs/src/components/Navigation/Navigation.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { LanguageSlug, getPathParts } from "@/lib/languageFromPath";
import clsx from "clsx";
import { useRouter } from "next/dist/client/router";
import { useRouter } from "next/router";
import { useState } from "react";
import { LanguageSelect } from "./LanguageSelect";
import { SubNavigation } from "./SubNavigation";
Expand Down Expand Up @@ -39,7 +39,9 @@ export function Navigation() {
setSelectIsOpen={setSelectIsOpen}
handleChange={handleChange}
/>
<SubNavigation pathParts={pathParts} selectIsOpen={selectIsOpen} />
{pathParts.language !== "other-platforms" && (
<SubNavigation pathParts={pathParts} selectIsOpen={selectIsOpen} />
)}
</div>
);
}
23 changes: 23 additions & 0 deletions docs/src/lib/useResizing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { useEffect, useState } from "react";

export function useResizing() {
const [resizing, setResizing] = useState(false);

useEffect(() => {
let timer: NodeJS.Timeout;
function doneResizing() {
setResizing(false);
}
function handleResize() {
setResizing(true);
clearTimeout(timer);

timer = setTimeout(doneResizing, 100);
}
window.addEventListener("resize", handleResize);

return () => window.removeEventListener("resize", handleResize);
}, []);

return resizing;
}
5 changes: 3 additions & 2 deletions docs/src/pages/index.mdx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Hero } from "@/components/Hero";
import { Selfie } from "@/components/Selfie";
import { NavHeading } from "@/components/NavHeading";

{/* show the homepage hero component and hide the navigation used everywhere else in the app */}
export const showHero = true

## <Selfie /> is literal
<NavHeading text="literal" />

Sure, you could write your assertions like this.

Expand Down Expand Up @@ -61,7 +62,7 @@ public void preventCssBloat() {
}
```
## <Selfie /> is lensable
<NavHeading text="lensable" />
Some snapshots are so big that it would be cumbersome to put them inline into your test code. So selfie helps you put them on disk.
Expand Down
11 changes: 8 additions & 3 deletions docs/src/pages/js/index.mdx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Hero } from "@/components/Hero";
import { Selfie } from "@/components/Selfie";
import { NavHeading } from "@/components/NavHeading";

export const showHero = true;

## <Selfie /> is literal
<NavHeading text="literal" />

Sure, you could write your assertions like this.

Expand Down Expand Up @@ -45,7 +46,7 @@ describe("login", () => {

... And so on ...

## <Selfie /> is lensable
<NavHeading text="lensable" />

Some snapshots are so big that it would be cumbersome to put them inline into your test code. So selfie helps you put them on disk.

Expand All @@ -68,4 +69,8 @@ describe("orderFlow", () => {
});
```

... Remaining content ...
## <Selfie /> is like a filesystem

Selfie's snapshot files `.ss` are incredibly simple to parse, and you can use `selfie-lib` to parse them for you if you want. You can treat them as an output deliverable of your code, and use them as an input to other tooling.

TODO.
5 changes: 3 additions & 2 deletions docs/src/pages/jvm/index.mdx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Hero } from "@/components/Hero";
import { Selfie } from "@/components/Selfie";
import { NavHeading } from "@/components/NavHeading";

export const showHero = true;

## <Selfie /> is literal
<NavHeading text="literal" />

Sure, you could write your assertions like this.

Expand Down Expand Up @@ -60,7 +61,7 @@ public void preventCssBloat() {
}
```
## <Selfie /> is lensable
<NavHeading text="lensable" />
Some snapshots are so big that it would be cumbersome to put them inline into your test code. So selfie helps you put them on disk.
Expand Down

0 comments on commit 060bd31

Please sign in to comment.