Compare commits
No commits in common. "2a0283785a923d59d28a9b9181fae1c5e1a9bbe2" and "e4f11527230d4e7be162dde9480e367d5d3091bd" have entirely different histories.
2a0283785a
...
e4f1152723
@ -18,20 +18,24 @@ function ArrowIcon(props: JSX.IntrinsicElements["svg"]) {
|
||||
type PageLinkProps = Omit<JSX.IntrinsicElements["div"], "dir" | "title"> & {
|
||||
title: string;
|
||||
href: string;
|
||||
dir: "previous" | "next";
|
||||
dir?: "previous" | "next";
|
||||
};
|
||||
|
||||
function PageLink(props: PageLinkProps) {
|
||||
const getPageCategory = () =>
|
||||
navigation.find((section) => {
|
||||
return section.links.some(
|
||||
(link) => link.href === props.href || link.subitems.some((subitem) => subitem.href === props.href),
|
||||
(link) =>
|
||||
link.href === props.href ||
|
||||
link.subitems.some((subitem) => subitem.href === props.href),
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<div {...cleanProps(props, "dir", "title", "href", "subitems")}>
|
||||
<dt class="font-display text-sm font-medium text-slate-900">{props.dir === "next" ? "Suivant" : "Précédent"}</dt>
|
||||
<dt class="font-display text-sm font-medium text-slate-900">
|
||||
{props.dir === "next" ? "Suivant" : "Précédent"}
|
||||
</dt>
|
||||
<dd class="mt-1">
|
||||
<Link
|
||||
href={props.href}
|
||||
@ -42,11 +46,18 @@ function PageLink(props: PageLinkProps) {
|
||||
>
|
||||
<p class="flex flex-col gap-0">
|
||||
{getPageCategory() && (
|
||||
<span class="text-violet-600 text-sm mb-1 leading-3">{getPageCategory()?.title}</span>
|
||||
<span class="text-violet-600 text-sm mb-1 leading-3">
|
||||
{getPageCategory()?.title}
|
||||
</span>
|
||||
)}
|
||||
<span class="leading-4">{props.title}</span>
|
||||
</p>
|
||||
<ArrowIcon class={clsx("h-6 w-6 flex-none fill-current", props.dir === "previous" && "-scale-x-100")} />
|
||||
<ArrowIcon
|
||||
class={clsx(
|
||||
"h-6 w-6 flex-none fill-current",
|
||||
props.dir === "previous" && "-scale-x-100",
|
||||
)}
|
||||
/>
|
||||
</Link>
|
||||
</dd>
|
||||
</div>
|
||||
@ -82,7 +93,9 @@ export function PrevNextLinks() {
|
||||
});
|
||||
|
||||
const getNeighboringLinks = () => {
|
||||
const linkIndex = allLinks.findIndex((link) => link.href === pageContext.urlPathname);
|
||||
const linkIndex = allLinks.findIndex(
|
||||
(link) => link.href === pageContext.urlPathname,
|
||||
);
|
||||
if (linkIndex === -1) return [null, null];
|
||||
|
||||
const previousPage = allLinks[linkIndex - 1] || null;
|
||||
@ -99,10 +112,18 @@ export function PrevNextLinks() {
|
||||
|
||||
return (
|
||||
<dl class="mt-12 mx-4 lg:mr-0 flex gap-4 border-t border-slate-200 pt-6">
|
||||
{getNeighboringLinks()[0] && <PageLink dir="previous" {...(getNeighboringLinks()[0] as NavigationSubItem)} />}
|
||||
{getNeighboringLinks()[0] && (
|
||||
<PageLink
|
||||
dir="previous"
|
||||
{...(getNeighboringLinks()[0] as NavigationSubItem)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{getNeighboringLinks()[1] && (
|
||||
<PageLink class="ml-auto text-right" dir="next" {...(getNeighboringLinks()[1] as NavigationSubItem)} />
|
||||
<PageLink
|
||||
class="ml-auto text-right"
|
||||
{...(getNeighboringLinks()[1] as NavigationSubItem)}
|
||||
/>
|
||||
)}
|
||||
</dl>
|
||||
);
|
||||
|
||||
@ -1,7 +1,13 @@
|
||||
import type { SearchResult } from "@/services/FlexSearchService";
|
||||
import type { JSX, Accessor, Setter } from "solid-js";
|
||||
|
||||
import { createContext, useContext, For, createEffect, createSignal } from "solid-js";
|
||||
import {
|
||||
createContext,
|
||||
useContext,
|
||||
For,
|
||||
createEffect,
|
||||
createSignal,
|
||||
} from "solid-js";
|
||||
|
||||
import { Highlighter } from "solid-highlight-words";
|
||||
import { useDebounce } from "@/hooks/useDebounce";
|
||||
@ -47,9 +53,21 @@ function LoadingIcon(props: JSX.IntrinsicElements["svg"]) {
|
||||
return (
|
||||
<svg viewBox="0 0 20 20" fill="none" aria-hidden="true" {...props}>
|
||||
<circle cx="10" cy="10" r="5.5" stroke-linejoin="round" />
|
||||
<path stroke={`url(#${id})`} stroke-linecap="round" stroke-linejoin="round" d="M15.5 10a5.5 5.5 0 1 0-5.5 5.5" />
|
||||
<path
|
||||
stroke={`url(#${id})`}
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M15.5 10a5.5 5.5 0 1 0-5.5 5.5"
|
||||
/>
|
||||
<defs>
|
||||
<linearGradient id={id} x1="13" x2="9.5" y1="9" y2="15" gradientUnits="userSpaceOnUse">
|
||||
<linearGradient
|
||||
id={id}
|
||||
x1="13"
|
||||
x2="9.5"
|
||||
y1="9"
|
||||
y2="15"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="currentColor" />
|
||||
<stop offset="1" stop-color="currentColor" stop-opacity="0" />
|
||||
</linearGradient>
|
||||
@ -113,15 +131,14 @@ function SearchResultItem(props: { result: SearchResult; query: string }) {
|
||||
|
||||
const getHierarchy = (): string[] => {
|
||||
const sectionTitle = navigation.find((section) => {
|
||||
return section.links.find((link) => link.href === props.result.url.split("#")[0]);
|
||||
return section.links.find(
|
||||
(link) => link.href === props.result.url.split("#")[0],
|
||||
);
|
||||
})?.title;
|
||||
|
||||
return [sectionTitle, props.result.pageTitle].filter((x): x is string => typeof x === "string");
|
||||
};
|
||||
|
||||
const handleNavigate = (url: string) => {
|
||||
navigate(`/${url}`.replace(/\/+/g, "/"));
|
||||
close();
|
||||
return [sectionTitle, props.result.pageTitle].filter(
|
||||
(x): x is string => typeof x === "string",
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
@ -130,11 +147,21 @@ function SearchResultItem(props: { result: SearchResult; query: string }) {
|
||||
aria-labelledby={`${id}-hierarchy ${id}-title`}
|
||||
tab-index={0}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === "Enter") handleNavigate(props.result.url);
|
||||
if (event.key === "Enter") {
|
||||
navigate(props.result.url);
|
||||
close();
|
||||
}
|
||||
}}
|
||||
onClick={() => {
|
||||
navigate(props.result.url);
|
||||
close();
|
||||
}}
|
||||
onClick={() => handleNavigate(props.result.url)}
|
||||
>
|
||||
<div id={`${id}-title`} aria-hidden="true" class="text-sm text-slate-700 group-aria-selected:text-violet-600">
|
||||
<div
|
||||
id={`${id}-title`}
|
||||
aria-hidden="true"
|
||||
class="text-sm text-slate-700 group-aria-selected:text-violet-600"
|
||||
>
|
||||
<HighlightQuery text={props.result.title} query={props.query} />
|
||||
</div>
|
||||
{getHierarchy().length > 0 && (
|
||||
@ -149,7 +176,9 @@ function SearchResultItem(props: { result: SearchResult; query: string }) {
|
||||
<HighlightQuery text={item} query={props.query} />
|
||||
<span
|
||||
class={
|
||||
itemIndex() === getHierarchy().length - 1 ? "sr-only" : "mx-2 text-slate-300 dark:text-slate-700"
|
||||
itemIndex() === getHierarchy().length - 1
|
||||
? "sr-only"
|
||||
: "mx-2 text-slate-300 dark:text-slate-700"
|
||||
}
|
||||
>
|
||||
/
|
||||
@ -219,7 +248,11 @@ function SearchDialog(props: { class?: string }) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Dialog isOpen={isOpened()} onClose={close} class={clsx("fixed inset-0 z-50", props.class)}>
|
||||
<Dialog
|
||||
isOpen={isOpened()}
|
||||
onClose={close}
|
||||
class={clsx("fixed inset-0 z-50", props.class)}
|
||||
>
|
||||
<div class="fixed inset-0 bg-slate-900/50 backdrop-blur-sm" />
|
||||
|
||||
<div
|
||||
@ -302,7 +335,9 @@ export function Search() {
|
||||
onClick={() => setIsOpened(true)}
|
||||
>
|
||||
<SearchIcon class="h-5 w-5 flex-none fill-slate-400 group-hover:fill-slate-500 md:group-hover:fill-slate-400" />
|
||||
<span class="sr-only md:not-sr-only md:ml-2 md:text-slate-500">Rechercher...</span>
|
||||
<span class="sr-only md:not-sr-only md:ml-2 md:text-slate-500">
|
||||
Rechercher...
|
||||
</span>
|
||||
{modifierKey && (
|
||||
<kbd class="ml-auto hidden font-medium text-slate-400 md:block">
|
||||
<kbd class="font-sans">{modifierKey()}</kbd>
|
||||
|
||||
@ -30,13 +30,13 @@ Le design pattern MVC est un modèle d'architecture logicielle qui sépare les d
|
||||
- **Contrôleur** : fait le lien entre le modèle et la vue. Il contient la logique métier de l'application.
|
||||
|
||||
<Callout type="warning" title="Les schémas disponibles en ligne">
|
||||
Il existe de nombreux schémas qui expliquent le design pattern MVC mais ils ne sont pas tous corrects. Enfin, si, ils
|
||||
sont corrects... mais certains ne s'appliquent pas à tous les frameworks et architectures.
|
||||
Il existe de nombreux schémas qui expliquent le design pattern MVC mais ils ne sont pas tous corrects.
|
||||
Enfin, si, ils sont corrects... mais certains ne s'appliquent pas à tous les frameworks et architectures.
|
||||
</Callout>
|
||||
|
||||
Pour t'aider à mieux te représenter un schéma MVC avec les ordres de flux de données et de contrôle :
|
||||
|
||||
<Image alt="Schéma MVC pour une application web basique" src="/images/patterns/mvc.webp" class="max-h-96 mx-auto" />
|
||||
<Image alt="Schéma MVC pour une application web basique" src="/patterns/mvc.webp" class="max-h-96 mx-auto" />
|
||||
|
||||
<Callout type="question" title="Pourquoi la Vue ne retourne pas directement au client ?">
|
||||
La vue ne retourne pas directement au client car elle doit passer par le contrôleur.
|
||||
@ -49,10 +49,8 @@ Pour t'aider à mieux te représenter un schéma MVC avec les ordres de flux de
|
||||
Le concept est simple : chaque partie de l'application a un **rôle bien défini** et ne doit pas empiéter sur le rôle des autres.
|
||||
|
||||
<Callout type="question" title="Et si j'ai des middlewares ?">
|
||||
Dans la majorité des cas, les middlewares s'exécutent avant le contrôleur même si on peut en avoir à différents
|
||||
moments de la circulation de la donnée. Si tu as déjà utilisé Express, tu as probablement déjà utilisé un middleware
|
||||
pour vérifier si l'utilisateur est connecté avant de lui afficher une page qui est réservée aux utilisateurs
|
||||
connectés.
|
||||
Dans la majorité des cas, les middlewares s'exécutent avant le contrôleur même si on peut en avoir à différents moments de la circulation de la donnée.
|
||||
Si tu as déjà utilisé Express, tu as probablement déjà utilisé un middleware pour vérifier si l'utilisateur est connecté avant de lui afficher une page qui est réservée aux utilisateurs connectés.
|
||||
</Callout>
|
||||
|
||||
<Callout type="note" title="Le cas de React (ou Vue, Angular, Solid, etc.)">
|
||||
@ -76,8 +74,9 @@ Si tu fais un projet personnel, tu peux définir les tiennes, du moment que tu e
|
||||
Pense à être cohérent en ce qui concerne la langue utilisée.
|
||||
|
||||
<Callout type="warning" title="Pas de franglais !">
|
||||
Évite de mélanger plusieurs langues dans tes nommages. Si tu choisis de travailler en français, reste en français. Si
|
||||
tu choisis de travailler en anglais, reste en anglais.
|
||||
Évite de mélanger plusieurs langues dans tes nommages.
|
||||
Si tu choisis de travailler en français, reste en français.
|
||||
Si tu choisis de travailler en anglais, reste en anglais.
|
||||
</Callout>
|
||||
|
||||
D'ailleurs, je te recommande chaudement de travailler en anglais ne serait-ce que pour te familiariser avec la langue de Shakespeare qui est, on le rappelle, la langue la plus répandue dans le monde de l'informatique.
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 14 KiB |
Loading…
Reference in New Issue
Block a user