Skip to content

Commit

Permalink
fix/refactor: deal with images in mdx, refactor mdx compilation
Browse files Browse the repository at this point in the history
  • Loading branch information
grzegorzpokorski committed Apr 14, 2024
1 parent 2cb734a commit 83e6700
Show file tree
Hide file tree
Showing 15 changed files with 129 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@ ed blandit nulla quis libero consequat volutpat. Phasellus gravida imperdiet sap
Vivamus nec leo in ante tincidunt varius. Nam mollis tristique sem dignissim porta.

![writing machine on desk](/images/posts/dlaczego-strona-na-nextjs-z-mdx/writing-machine.jpg)
<Image
alt="writing machine on desk"
src="/images/posts/dlaczego-strona-na-nextjs-z-mdx/writing-machine.jpg"
width={1920}
height={1280}
/>

### Donec vehicula mi quis consequat gravida

Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,23 @@ Nawigowanie klawiaturą po stronie powinno być tak samo przyjemne, jak nawigowa

Projektując dostępną stronę internetową, warto dopilnować, aby poszczególne elementy posiadały dobry kontrast. To, co na przysłowiowy pierwszy rzut oka może wyglądać ładnie, może okazać się niedostępne. Najlepiej ilustruje to poniższy obraz:

![obraz prezentuje stronę z czarnym tłem, nagłówkami koloru białego oraz tekstem w ciemnym szarym kolorze](/images/posts/dostepnosc-w-kilku-krokach/low-contrast-ratio-example.png)
<Image
alt="obraz prezentuje stronę z czarnym tłem, nagłówkami koloru białego oraz tekstem w ciemnym szarym kolorze"
src="/images/posts/dostepnosc-w-kilku-krokach/low-contrast-ratio-example.png"
width={582}
height={337}
/>

Jak można łatwo zauważyć, kolor nagłówków bardzo dobrze kontrastuje z czarnym tłem. Co innego można powiedzieć o kolorze tekstu pod nagłówkami oraz kolorze elementów listy po lewo. To bardzo skrajny przykład i czasami to czy dany element posiada wystarczający kontrast, jest trudne do ocenienia na oko. Polecam wspomagać się narzędziami takimi jak to: [WebAIM color checker](https://webaim.org/resources/contrastchecker/), które na podstawie dostarczonych kolorów określa współczynnik kontrastu oraz daje natychmiastową informację czy i jakie standardy spełnia.

Dobry kontrast to również **dobór odpowiedniej czcionki**, która nie jest zbyć wąska, aby można było ją wygodnie czytać. Zaleca się ograniczenie ilości krojów czcionki na stronie do dwóch. Odpowiednia wielkość odstępu od poszczególnych linii tekstu czy liter oraz wyrazów nie pozwala na "zlewanie się" tekstu w jedną trudną do odczytania całość. Warto zadbać o takie szczegóły. Uniwersalną praktyką jest to, aby stosować proporcjonalnie coraz większą interlinię wraz ze zmniejszaniem rozmiaru fontu.

![Kolaż: 1. mężczyzna patrzy z obrzydzeniem na przykład tekstu z nieprawidłowo dobraną interlinią. 2. Mężczyzna z kolażu pierwszego, patrzy z zadowoleniem na poprawone odstępy w tekście.](/images/posts/dostepnosc-w-kilku-krokach/good-bad-lineheight.png)
<Image
alt="Kolaż: 1. mężczyzna patrzy z obrzydzeniem na przykład tekstu z nieprawidłowo dobraną interlinią. 2. Mężczyzna z kolażu pierwszego, patrzy z zadowoleniem na poprawone odstępy w tekście."
src="/images/posts/dostepnosc-w-kilku-krokach/good-bad-lineheight.png"
width={1380}
height={796}
/>

## Nie przesadzajmy z animacjami

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@ Nikt nie lubi długo czekać, aż strona się załaduje. Chcąc uniknąć niezad

Zgodnie z zaleceniami Google, aby zapewnić dobre wrażenia z użytkowania strony internetowej, należy skrócić czas jej ładowania do maksymalnie 2.5 sekund. Każda kolejna sekunda przekłada się zwiększony współczynnik odrzucenia (tzw. bounce rate) - to nic innego jak użytkownik, który zrezygnował z jakiegoś powodu z dalszego przeglądania naszej strony, bez jakiej podjęcia jakiejkolwiek akcji. Jak się okazuje najczęstszym powodem jest zbyt długi czas ładowania się strony.

![wykres obrazujący zalażność między szybkością ładowania się strony, a współczynnikiem odrzucenia](/images/posts/jak-przyspieszyc-strone-internetowa/web-page-time-load-vs-bounce-rate.png)
<Image
alt="wykres obrazujący zalażność między szybkością ładowania się strony, a współczynnikiem odrzucenia"
src="/images/posts/jak-przyspieszyc-strone-internetowa/web-page-time-load-vs-bounce-rate.png"
width={1539}
height={1014}
/>

Powyżej znajduje się grafika ze strony [pingdom.com](https://www.pingdom.com/blog/page-load-time-really-affect-bounce-rate/).Obrazuje ona, jakie przełożenie ma czas ładowania strony na wspomniany współczynnik odrzucenia. Jak można zaobserwować, współczynnik odrzucenia drastycznie wzrasta w przypadku kiedy strona ładuje się powyżej 3 sekund.

Expand All @@ -38,7 +43,12 @@ W przypadku kiedy chcemy, aby nasza witryna internetowa równie szybko ładował

W świecie internetu fizyczne odległości również mają znaczenie. Dostarczenie obrazu wysłanego z serwera znajdującego się w USA do użytkownika znajdującego się w Holandii może zająć więcej czasu niż gdyby został wysłany z serwera znajdującego się np. w Niemczech. Aby zrozumieć, dlaczego tak się dzieje, należy zdać sobie sprawę, że w dużym uproszczeniu sieć Internet, to siec połączonych ze sobą komputerów, które komunikują się nawzajem ze sobą i przesyłają dane. Im bliżej siebie znajdują się komunikujące się ze sobą komputery, tym mniejsze występują przy tym opóźnienia w przesyle danych.

![wizualizacja sieci cdn](/images/posts/jak-przyspieszyc-strone-internetowa/cdn-visualization.webp)
<Image
alt="wizualizacja sieci cdn"
src="/images/posts/jak-przyspieszyc-strone-internetowa/cdn-visualization.webp"
width={1412}
height={941}
/>

Sieć CDN powiela dane naszej strony, które przesłaliśmy na główny serwer dostawcy hostingu. Następnie przesłane dane są przesyłane do serwerów znajdujących się najczęściej przy głównych węzłach sieci Internet na całym świecie. Takie działanie pozwala dostarczać pliki naszej strony do użytkownika z serwera znajdującego się najbliżej jego lokalizacji.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,12 @@ Taka zamiana zawsze wiązała się z odszukaniem i zamianą wartości koloru we

Od tamtego momentu wszystko stało się prostsze. Zazwyczaj w jednym pliku zapisuje wszystkie zmienne z wartościami, które zamierzam wykorzystywać wielokrotnie w danym projekcie i drobne zmiany np. koloru trwają już dosłownie sekundy🚀.

![proces wyboru koloru z palet](/images/posts/korzysci-ze-stosowania-scss/wybor-koloru.jpg)
<Image
alt="kobieta wybiera kolory z palety barw"
src="/images/posts/korzysci-ze-stosowania-scss/wybor-koloru.jpg"
width={1920}
height={1280}
/>

#### Zobacz jakie to proste!

Expand Down Expand Up @@ -85,7 +90,12 @@ a {

Jak można zauważyć, aby uzyskać konkretna wartość z mapy, korzystamy ze wbudowanej funkcji `map-get()`, która przyjmuje dwie wartości: nazwę mapy i etykietę przypisaną do wartości, którą chcemy uzyskać.

![ustawione kontenery jako mapa, a wózek z kontenerem jako funkcja map-get](/images/posts/korzysci-ze-stosowania-scss/mapy-w-scss.jpg)
<Image
alt="ustawione kontenery jako mapa, a wózek z kontenerem jako funkcja map-get"
src="/images/posts/korzysci-ze-stosowania-scss/mapy-w-scss.jpg"
width={1560}
height={965}
/>

### Po trzecie — mixiny, czyli koniec z powtarzalną pracą

Expand Down Expand Up @@ -292,7 +302,12 @@ Są to szczegóły, lecz dbanie o takie wydawało się by drobnostki, pozwala op

Jeśli zainteresował cię ten temat, zachęcam do zapoznania się z oficjalna dokumentacja, którą znajdziesz pod tym adresem: [sass-lang.com/documentation](https://sass-lang.com/documentation/).

![passion lead us here](/images/posts/korzysci-ze-stosowania-scss/passion-lead-us-here.jpg)
<Image
alt="passion lead us here"
src="/images/posts/korzysci-ze-stosowania-scss/passion-lead-us-here.jpg"
width={1920}
height={1282}
/>

W moim przypadku, podczas nauki SCSS pomocne okazało się również analizowanie kodu innych programistów np. na [githubie](https://github.com/topics/scss). Jeśli korzystasz z frameworkow takich, jak bootstrap warto zbadać, jak dane funkcjonalności zostały zaimplementowane. Przyda się to również, jeśli chciałbyś dostosować bootstrapa do swoich potrzeb, ponieważ on sam został napisany w SCSS.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,12 @@ Jeśli chciałbyś dowiedzieć się więcej o znacznikach HTML, aby wzbogacić s

Omówienie każdego z dostępnych znaczników starczyłoby na niejeden artykuł. Podpowiem jednak, że warto zacząć od takich kluczowych, jak znaczniki poziomów nagłówka (`H1`, `H2`, `H3`, ...), ponieważ często można spotkać się z tym, iż nie są one stosowane, aby odzwierciedlić prawidłową strukturę treści strony, lecz większą uwagę przywiązuje się do kwestii estetycznych — jak dany nagłówek wygląda na stronie.

![projektowanie strony internetowej](/images/posts/na-co-zwrocic-uwage-przy-tworzeniu-wlasnej-strony-internetowej/projektowanie-strony-internetowej.jpg)
<Image
alt="projektowanie strony internetowej"
src="/images/posts/na-co-zwrocic-uwage-przy-tworzeniu-wlasnej-strony-internetowej/projektowanie-strony-internetowej.jpg"
width={1920}
height={1280}
/>

Z własnego doświadczenie mogę polecić tworzenie w pierwszej kolejności struktury strony, stosując odpowiednie, semantyczne znaczniki HTML. W dalszej kolejności zajmuje się pisaniem stylów strony. Takie podejście może wymagać trochę doświadczenia, lecz pozwala skupić się na tym, aby wszystkie znaczniki miały odzwierciedlenie w treści, którą zawierają.

Expand All @@ -57,7 +62,12 @@ Przy doborze odpowiedniego koloru najbardziej wyczerpujące wytyczne można znal

### Jedziesz samochodem i 'przeglądasz' internet — czyli urządzenia wspomagające przeglądanie internetu

![czlowiek korzystajacy z technilogi asystującej](/images/posts/na-co-zwrocic-uwage-przy-tworzeniu-wlasnej-strony-internetowej/uzytkownik-korzystajacy-z-technologi-asystujacej.jpg)
<Image
alt="czlowiek korzystajacy z technilogi asystującej"
src="/images/posts/na-co-zwrocic-uwage-przy-tworzeniu-wlasnej-strony-internetowej/uzytkownik-korzystajacy-z-technologi-asystujacej.jpg"
width={1920}
height={1440}
/>

Ważne jest, aby elementy graficzne takie jak zdjęcia miały odpowiednio uzupełniony atrybut `alt`, czy `width` i `height` — są one wykorzystywany przez czytniki ekranowe do opisania znajdujących się na stronie grafik.

Expand All @@ -75,7 +85,12 @@ Do opisywania zawartości strony dla czytników ekranowych służą nie tylko zn

### Popsuła Ci się myszka — obsługa strony klawiaturą

![kot czychajacy na mysz](/images/posts/na-co-zwrocic-uwage-przy-tworzeniu-wlasnej-strony-internetowej/kot-czychajacy-na-mysz.jpg)
<Image
alt="kot czychajacy na mysz"
src="/images/posts/na-co-zwrocic-uwage-przy-tworzeniu-wlasnej-strony-internetowej/kot-czychajacy-na-mysz.jpg"
width={1920}
height={1211}
/>

Funkcją często pomijaną lub – co gorsza – całkowicie wyłączaną jest prawidłowe oznaczanie (focusowanie) elementów na stronie podczas nawigowania po niej klawiaturą. Strona internetowa powinna zawierać czytelny i wyraźny 'focus' pozwalający bezproblemu namierzyć aktywny element. Rozwijane listy, guziki czy wyskakujące okienka powinny prawidłowo reagować przy naciśnięciu, czy to spacji, czy klawisza Escape.

Expand All @@ -93,8 +108,12 @@ Funkcją często pomijaną lub – co gorsza – całkowicie wyłączaną jest p
- w miarę możliwości i potrzeby korzysta z serwisów CDN pozwalających serwować treść naszej strony z serwera możliwie jak najbliższego naszemu odwiedzającemu.
- obrazy niebędące w obszarze okna przeglądarki, gdzie dochodzi do renderowania treści stron internetowej ([dowiedz się węcej o Largest Contentful Paint' (LCP)](https://web.dev/optimize-lcp/)) posiadają atrybut `loading="lazy"` pozwalający wczytywać obrazy tylko gdy powinnny pojawić się w oknie naszej przeglądarki.

![ameryka widziana noca z orbity](/images/posts/na-co-zwrocic-uwage-przy-tworzeniu-wlasnej-strony-internetowej/ameryka-widziana-noca-z-orbity.jpg)

<Image
alt="ameryka widziana noca z orbity"
src="/images/posts/na-co-zwrocic-uwage-przy-tworzeniu-wlasnej-strony-internetowej/ameryka-widziana-noca-z-orbity.jpg"
width={1920}
height={1280}
/>
## Zadbaj o kwestie związane z SEO

Dobra strona internetowa to również taka strona, którą można łatwo znaleźć w wyszukiwarce internetowej. Choć jest to temat bardzo szeroki, a w niektórych konkurencyjnych branżach ciężko jest się wybić na szczyt list wyszukiwarek, każdy może wykonać kilka czynności, aby przyspieszyć indeksowanie naszej strony.
Expand Down
Binary file not shown.
1 change: 0 additions & 1 deletion src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import "@/styles/globals.css";
import "@/styles/prism-theme.css";

import type { ReactNode } from "react";
import { Analytics } from "@vercel/analytics/react";
Expand Down
43 changes: 8 additions & 35 deletions src/components/molecules/PostContent/PostContent.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,22 @@
"use client";

import type { MDXRemoteSerializeResult } from "next-mdx-remote";
import { MDXRemote } from "next-mdx-remote";
import type { ImageProps } from "next/image";
import Image from "next/image";
import { Link } from "@/components/atoms/Link/Link";
import { SharePostLinks } from "@/components/molecules/SharePostLinks/SharePostLinks";
import { MdxHeading } from "@/components/molecules/MdxHeading/MdxHeading";
import type { MDXComponents } from "mdx/types";
import type { Post } from "@/types";

type PostContentProps = {
source: MDXRemoteSerializeResult;
compiledSource: Post["compiledSource"];
slug: string;
title: string;
};

export const PostContent = ({ source, slug, title }: PostContentProps) => {
const components = {
a: Link,
img: (props: ImageProps) => (
<Image
{...props}
alt={props.alt}
sizes="(max-width: 720px) 100vw, (max-width: 1140px) 50vw, 33vw"
/>
),
h2: (props: JSX.IntrinsicElements["h2"]) => (
<MdxHeading as="h2" isAnchor {...props} />
),
h3: (props: JSX.IntrinsicElements["h3"]) => (
<MdxHeading as="h3" isAnchor {...props} />
),
h4: (props: JSX.IntrinsicElements["h4"]) => (
<MdxHeading as="h4" isAnchor {...props} />
),
h5: (props: JSX.IntrinsicElements["h5"]) => (
<MdxHeading as="h5" isAnchor {...props} />
),
} as MDXComponents;

export const PostContent = ({
compiledSource,
slug,
title,
}: PostContentProps) => {
return (
<article className="pb-16">
<div className="container px-3 mx-auto">
<div className="w-full lg:w-7/12 prose dark:prose-invert max-w-none mx-auto">
<MDXRemote {...source} components={components} />
{compiledSource}
</div>
<footer className="w-full lg:w-7/12 mx-auto mt-16 pt-8 border-t-2 border-light-green dark:border-zinc-700 flex flex-col lg:flex-row gap-6 items-center">
<p className="font-bold text-zinc-800 dark:text-zinc-200">
Expand Down
4 changes: 3 additions & 1 deletion src/components/pages/SinglePostPage/SinglePostPage.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import "@/styles/prism-theme.css";

import { PostContent } from "@/components/molecules/PostContent/PostContent";
import { PostHeader } from "@/components/organisms/PostHeader/PostHeader";
import { PromoPosts } from "@/components/organisms/PromoPosts/PromoPosts";
Expand All @@ -14,7 +16,7 @@ export const SinglePostPage = ({
<article>
<PostHeader {...post.frontmatter} />
<PostContent
source={post.source}
compiledSource={post.compiledSource}
slug={post.frontmatter.slug}
title={post.frontmatter.title}
/>
Expand Down
12 changes: 0 additions & 12 deletions src/lib/markdown.ts

This file was deleted.

28 changes: 28 additions & 0 deletions src/lib/mdxCustomComponents.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import type { MDXComponents } from "mdx/types";
import type { ImageProps } from "next/image";
import Link from "next/link";
import { MdxHeading } from "@/components/molecules/MdxHeading/MdxHeading";
import Image from "next/image";

export const mdxCustomComponents = {
a: Link,
Image: (props: ImageProps) => (
<Image
{...props}
alt={props.alt}
sizes="(max-width: 720px) 100vw, (max-width: 1140px) 50vw, 33vw"
/>
),
h2: (props: JSX.IntrinsicElements["h2"]) => (
<MdxHeading as="h2" isAnchor {...props} />
),
h3: (props: JSX.IntrinsicElements["h3"]) => (
<MdxHeading as="h3" isAnchor {...props} />
),
h4: (props: JSX.IntrinsicElements["h4"]) => (
<MdxHeading as="h4" isAnchor {...props} />
),
h5: (props: JSX.IntrinsicElements["h5"]) => (
<MdxHeading as="h5" isAnchor {...props} />
),
} as MDXComponents;
21 changes: 16 additions & 5 deletions src/lib/posts.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import path from "path";
import * as fs from "node:fs/promises";
import { serializeSource } from "./markdown";
import { compileMDX } from "next-mdx-remote/rsc";
import { z } from "zod";
import type { Post } from "@/types";
import { getPlaiceholder } from "plaiceholder";
import { getSlug } from "@/utils/getSlug";
import { getISODateFromPublicatedDate } from "@/utils/getISODateFromPublicationDate";
import rehypePrism from "rehype-prism-plus";
import { mdxCustomComponents } from "@/lib/mdxCustomComponents";

const postsDir = path.join(process.cwd(), "src/content/posts");
const postsDir = path.join(process.cwd(), "posts");

export const getAllSlugs = async () => {
const allFileNames = await fs.readdir(postsDir);
Expand All @@ -34,7 +36,16 @@ const getFrontmatterFeaturedImage = async (src: string) => {
export const getPostBySlug = async (slug: string): Promise<Post> => {
const postPath = path.join(postsDir, `${slug}.mdx`);
const postSource = await fs.readFile(postPath, "utf-8");
const mdxSource = await serializeSource(postSource);
const compiled = await compileMDX({
source: postSource,
options: {
parseFrontmatter: true,
mdxOptions: {
rehypePlugins: [rehypePrism],
},
},
components: mdxCustomComponents,
});

const frontMatterShema = z.object({
title: z.string(),
Expand All @@ -49,7 +60,7 @@ export const getPostBySlug = async (slug: string): Promise<Post> => {
featuredImageAlt: z.string(),
});

const frontmatter = frontMatterShema.parse(mdxSource.frontmatter);
const frontmatter = frontMatterShema.parse(compiled.frontmatter);
const plaiceholder = await getFrontmatterFeaturedImage(
frontmatter.featuredImage,
);
Expand All @@ -72,7 +83,7 @@ export const getPostBySlug = async (slug: string): Promise<Post> => {
},
slug,
},
source: mdxSource,
compiledSource: compiled.content,
};
};

Expand Down
4 changes: 2 additions & 2 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { MDXRemoteSerializeResult } from "next-mdx-remote";
import type { ReactNode } from "react";

export type PostFrontmatter = {
title: string;
Expand All @@ -20,5 +20,5 @@ export type PostFrontmatter = {

export type Post = {
frontmatter: PostFrontmatter;
source: MDXRemoteSerializeResult;
compiledSource: ReactNode;
};

0 comments on commit 83e6700

Please sign in to comment.