Skip to content

Commit

Permalink
add 404 page
Browse files Browse the repository at this point in the history
  • Loading branch information
Vahor committed Apr 28, 2024
1 parent 0f1ff27 commit 17ee449
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 21 deletions.
Binary file added public/where-am-i.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 25 additions & 4 deletions src/app/not-found.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,32 @@
import { TriggerSearch } from "@/components/TriggerSearch";
import { Button } from "@/components/ui/button";
import Image from "next/image";
import Link from "next/link";
import whereAmI from "../../public/where-am-i.gif";

export default function NotFound() {
return (
<div>
<h2>Not Found</h2>
<p>Could not find requested resource</p>
<Link href="/">Return Home</Link>
<div className="h-full w-full flex flex-col lg:flex-row gap-8 md:gap-12 items-center sm:justify-center md:mt-[-100px] container">
<Image src={whereAmI} alt="Where am I?" className="rounded-md shadow" />
<main className="flex flex-col gap-4">
<h1 className="font-semibold text-6xl text-black dark:text-white">
Oops !
</h1>
<div className="text-muted-foreground">
<p>La page que vous cherchez n'existe pas.</p>
<p>
Peut-être que vous avez mal tapé l'adresse ou que la page a été
supprimée.
</p>
</div>
<div className="space-x-2">
<Button asChild variant="secondary" className="w-max">
<Link href="/">Returner à l'accueil</Link>
</Button>
<span className="text-sm">ou</span>
<TriggerSearch variant="secondary">Chercher une page</TriggerSearch>
</div>
</main>
</div>
);
}
17 changes: 17 additions & 0 deletions src/components/TriggerSearch.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"use client";
import { searchStore } from "@/stores/search.store";
import { useStore } from "zustand";
import { Button, type ButtonProps } from "./ui/button";

export const TriggerSearch = ({
children,
...props
}: React.PropsWithChildren<ButtonProps>) => {
const openSearch = useStore(searchStore, (state) => state.setOpen);

return (
<Button {...props} type="button" onClick={() => openSearch(true)}>
{children}
</Button>
);
};
4 changes: 2 additions & 2 deletions src/components/header/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import { ThemeSwitcher } from "./theme-switcher";

export function Header() {
return (
<header className="py-8 px-8 max-w-screen-xl mx-auto">
<header className="py-4 sm:py-8 px-8 max-w-screen-xl mx-auto">
<div id="maybe-a-logo-one-day" />
<div className="flex justify-end gap-3 items-center">
<nav className="flex gap-6 text-xs sm:text-sm">
<nav className="flex gap-6">
{HEADER_LINKS.map(({ label, href }) => (
<Link
href={href}
Expand Down
21 changes: 6 additions & 15 deletions src/components/header/search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,13 @@ import {
CommandList,
} from "@/components/ui/command";
import { INITIAL_DATA, SEARCH_INDEX } from "@/lib/search";
import { searchStore } from "@/stores/search.store";
import { Search } from "lucide-react";
import Link from "next/link";
import { useRouter } from "next/navigation";
import React, { useEffect, useTransition } from "react";
import { useIsMounted, useMediaQuery } from "usehooks-ts";
import { create, useStore } from "zustand";

const openStore = create<{
open: boolean;
toogleOpen: () => void;
setOpen: (open: boolean) => void;
}>((set) => ({
open: false,
toogleOpen: () => set((state) => ({ open: !state.open })),
setOpen: (open) => set({ open }),
}));
import { useStore } from "zustand";

const commandProps: CommandDialogProps["commandProps"] = {
loop: false,
Expand All @@ -41,9 +32,9 @@ export function SearchMenu() {
}

function SearchWrapper({ children }: React.PropsWithChildren) {
const toggle = useStore(openStore, (state) => state.toogleOpen);
const setOpen = useStore(openStore, (state) => state.setOpen);
const open = useStore(openStore, (state) => state.open);
const toggle = useStore(searchStore, (state) => state.toogleOpen);
const setOpen = useStore(searchStore, (state) => state.setOpen);
const open = useStore(searchStore, (state) => state.open);
const md = useMediaQuery("(min-width: 640px)", { defaultValue: true });
const isMounted = useIsMounted();

Expand Down Expand Up @@ -133,7 +124,7 @@ const groupByType = (results: typeof INITIAL_DATA) => {
};

function SearchInput() {
const setOpen = useStore(openStore, (state) => state.setOpen);
const setOpen = useStore(searchStore, (state) => state.setOpen);

const [query, setQuery] = React.useState("");
const router = useRouter();
Expand Down
13 changes: 13 additions & 0 deletions src/stores/search.store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { create } from "zustand";

interface SearchStore {
open: boolean;
toogleOpen: () => void;
setOpen: (open: boolean) => void;
}

export const searchStore = create<SearchStore>((set) => ({
open: false,
toogleOpen: () => set((state) => ({ open: !state.open })),
setOpen: (open) => set({ open }),
}));
7 changes: 7 additions & 0 deletions src/styles/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@

--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
"Liberation Mono", "Courier New", monospace;

color-scheme: light dark;
}

.dark {
Expand Down Expand Up @@ -66,6 +68,11 @@
font-feature-settings: "cv11", "salt", "ss01", "ss03", "cv01", "cv02",
"cv03", "cv04", "cv05", "cv06", "cv07", "cv08", "cv09", "cv10";
}
html,
body,
div#__next {
@apply h-full;
}
}

@layer components {
Expand Down

0 comments on commit 17ee449

Please sign in to comment.