Add new article
This commit is contained in:
@@ -3,7 +3,11 @@ import "./prism-one-dark.css";
|
||||
import Navbar from "$lib/components/Navbar.svelte";
|
||||
</script>
|
||||
|
||||
<Navbar title="Блог"></Navbar>
|
||||
<Navbar>
|
||||
<div slot="title">
|
||||
<a href="/blog">Блог</a>
|
||||
</div>
|
||||
</Navbar>
|
||||
|
||||
<article class="px-2 py-8 md:px-8 max-w-[980px] mx-auto text-lg">
|
||||
<slot />
|
||||
@@ -11,7 +15,7 @@ import Navbar from "$lib/components/Navbar.svelte";
|
||||
|
||||
<style lang="postcss">
|
||||
:global(h1) {
|
||||
@apply text-3xl my-6;
|
||||
@apply text-5xl font-semibold my-6;
|
||||
}
|
||||
|
||||
:global(h2) {
|
||||
@@ -26,6 +30,10 @@ import Navbar from "$lib/components/Navbar.svelte";
|
||||
@apply text-xl my-3;
|
||||
}
|
||||
|
||||
:global(pre) {
|
||||
max-width: calc(100vw - 16px);
|
||||
}
|
||||
|
||||
:global(pre, code) {
|
||||
@apply rounded-lg;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import {metadata as htmlInCssMetadata} from "./html-in-css/+page.svx"
|
||||
import {metadata as thisBlogMetadata} from "./this-blog/+page.svx"
|
||||
|
||||
const posts = [
|
||||
{
|
||||
href: '/blog/this-blog',
|
||||
...thisBlogMetadata
|
||||
},
|
||||
{
|
||||
href: '/blog/html-in-css',
|
||||
...htmlInCssMetadata
|
||||
|
||||
@@ -3,9 +3,18 @@
|
||||
</script>
|
||||
|
||||
<section class="px-2 md:px-8 mb-16 max-w-[1280px] mx-auto">
|
||||
{#each data.posts as post}
|
||||
<a href={post.href}>
|
||||
<h2 class="text-3xl mb-4 md:text-4xl">{post.title}</h2>
|
||||
</a>
|
||||
{/each}
|
||||
<h2 class="text-4xl mb-10 md:text-5xl">
|
||||
Статьи
|
||||
</h2>
|
||||
|
||||
<div class="flex flex-col gap-14">
|
||||
{#each data.posts as post}
|
||||
<a
|
||||
href={post.href}
|
||||
>
|
||||
<div class="text-sm">{post.date}</div>
|
||||
<h4 class="text-2xl md:text-3xl">{post.title}</h4>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -3,11 +3,11 @@ title: "HTML in CSS: как сократить HTML-код и писать то
|
||||
date: "2024-08-01"
|
||||
---
|
||||
|
||||
<div class="text-xs">
|
||||
{date}
|
||||
</div>
|
||||
<script>
|
||||
import ArticleTitle from "$lib/components/ArticleTitle.svelte"
|
||||
</script>
|
||||
|
||||
# {title}
|
||||
<ArticleTitle metadata={metadata}/>
|
||||
|
||||
## О проекте
|
||||
|
||||
|
||||
207
src/routes/blog/this-blog/+page.svx
Normal file
207
src/routes/blog/this-blog/+page.svx
Normal file
@@ -0,0 +1,207 @@
|
||||
---
|
||||
title: "Как сделан этот блог?"
|
||||
date: "2024-10-04"
|
||||
---
|
||||
|
||||
<script>
|
||||
import ArticleTitle from "$lib/components/ArticleTitle.svelte"
|
||||
import CustomTabs from "./CustomTabs.svelte"
|
||||
</script>
|
||||
|
||||
<ArticleTitle metadata={metadata} />
|
||||
|
||||
## Предисловие
|
||||
|
||||
Существует такой удивительный формат под названием MDX. Он представляет из себя смесь JSX и Markdown,
|
||||
отсюда и MDX.
|
||||
|
||||
Он удобен тем, что на нем легко писать форматированный текст, но при этом не надо отказываться от возможности писать сложные
|
||||
интерактивные компоненты, поскольку их можно вставить как обычный React JSX прямо в тело MDX файла.
|
||||
|
||||
<div class='grid md:grid-cols-2 gap-4'>
|
||||
<div>
|
||||
|
||||
```markdown
|
||||
### Пример статьи
|
||||
|
||||
<CustomTabs>
|
||||
<CustomTab
|
||||
value={1}
|
||||
>
|
||||
Да, можно **прямо тут** форматировать!
|
||||
</CustomTab>
|
||||
<CustomTab
|
||||
value={2}
|
||||
>
|
||||
Или оставлять [ссылки](https://kopyl.dev)
|
||||
привычным способом
|
||||
</CustomTab>
|
||||
</CustomTabs>
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
</div>
|
||||
<div class='my-2 p-4'>
|
||||
|
||||
<h3 class='text-2xl'>Пример статьи</h3>
|
||||
|
||||
<CustomTabs>
|
||||
<div slot="1">
|
||||
|
||||
Да, можно **прямо тут** форматировать!
|
||||
|
||||
</div>
|
||||
<div slot="2">
|
||||
|
||||
Или оставлять [ссылки](https://kopyl.dev) привычным способом
|
||||
|
||||
</div>
|
||||
</CustomTabs>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Есть целый ряд фреймворков, которые позволяют писать на нем, а для особо ушлых, конечно, есть и варианты без фреймворка.
|
||||
MDX, в конце концов, просто компилируется в обычный React JSX, так что прикрутив этот компилятор MDX к обычному React проекту,
|
||||
можно начать писать в нем MDX.
|
||||
|
||||
## А как все таки сделан этот блог?
|
||||
|
||||
Ведь эта страница, как и остальные на этом сайте, написана на Svelte!
|
||||
|
||||
К счастью для меня и остальных фанатов MDX, есть подобная альтернатива, интегрирующая Markdown и Svelte: <a href="https://github.com/pngwn/MDsveX" target="_blank">MDsveX</a>.
|
||||
|
||||
Хоть название и не лучшее, возможности не уступают оригиналу.
|
||||
Самое главное, что у SVX (я буду так его называть), есть возможность передавать в компилятор <a href="https://github.com/remarkjs/remark" target="_blank">remark</a> и <a href="https://github.com/rehypejs/rehype" target="_blank">rehype</a> плагины.
|
||||
|
||||
## Создание проекта
|
||||
|
||||
### 1. Инициализация проекта
|
||||
|
||||
```bash
|
||||
npm create svelte@latest my-blog
|
||||
cd my-blog
|
||||
```
|
||||
|
||||
Инициализируем проект на SvelteKit и переходим в каталог с ним.
|
||||
|
||||
### 2. Установка зависимостей
|
||||
|
||||
```bash
|
||||
npm i -D mdsvex @mavrin/remark-typograf
|
||||
```
|
||||
|
||||
Ставим наши зависимости, про вторую чуть позже.
|
||||
|
||||
### 3. Настройка конфигов
|
||||
|
||||
```js
|
||||
// svelte.config.js
|
||||
import adapter from "@sveltejs/adapter-auto";
|
||||
import {vitePreprocess} from '@sveltejs/vite-plugin-svelte';
|
||||
import {mdsvex} from "mdsvex";
|
||||
import remarkTypograf from "@mavrin/remark-typograf";
|
||||
|
||||
const config = {
|
||||
extensions: [
|
||||
".svelte",
|
||||
".svx"
|
||||
],
|
||||
preprocess: [
|
||||
vitePreprocess(),
|
||||
mdsvex({
|
||||
remarkPlugins: [remarkTypograf]
|
||||
})
|
||||
],
|
||||
kit: {
|
||||
adapter: adapter()
|
||||
}
|
||||
};
|
||||
|
||||
export default config;
|
||||
```
|
||||
|
||||
Отличается от стандартного конфига лишь тем, что мы добавили `mdsvex` в `preprocess` и закинули `.svx` в `extensions`.
|
||||
|
||||
### 4. Создание страницы
|
||||
|
||||
Создадим каталог `src/routes/blog`, в нем будут все наши статьи.
|
||||
Чтобы создать страницу, создадим в этом каталоге каталог с произвольным именем `this-blog` и в нем файл `+page.svx`.
|
||||
В нем можно писать как будто это обычный `.svelte` файл, но весь Markdown будет на выходе форматирован.
|
||||
|
||||
Помимо этого SVX поддерживает Frontmatter -- в начале файла напишем блок выделенный минусами.
|
||||
|
||||
```markdown
|
||||
---
|
||||
title: "Как сделан этот блог?"
|
||||
date: "2024-10-02"
|
||||
---
|
||||
```
|
||||
|
||||
Теперь эти поля доступны как переменные как в документе, так и для экспорта внутри объекта `metadata`.
|
||||
|
||||
```markdown
|
||||
---
|
||||
title: "Как сделан этот блог?"
|
||||
date: "2024-10-02"
|
||||
---
|
||||
|
||||
<h1>{title}</h1>
|
||||
```
|
||||
|
||||
### 5. Создание списка статей
|
||||
|
||||
Теперь создадим файл `+page.server.ts` в каталоге `src/routes/blog`. Он будет предоставлять странице список всех статей.
|
||||
|
||||
```typescript
|
||||
// src/routes/blog/+page.server.ts
|
||||
import {metadata as thisBlogMetadata} from "./this-blog/+page.svx"
|
||||
|
||||
const posts = [
|
||||
{
|
||||
href: "/blog/this-blog",
|
||||
...thisBlogMetadata
|
||||
}
|
||||
]
|
||||
|
||||
export const load = async () => {
|
||||
return {
|
||||
posts
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
А в файл `+page.svelte` используем переданный список.
|
||||
|
||||
```html
|
||||
// src/routes/blog/+page.svelte
|
||||
<script>
|
||||
export let data;
|
||||
</script>
|
||||
|
||||
<h2>
|
||||
Статьи
|
||||
</h2>
|
||||
|
||||
<div class="flex flex-col gap-14">
|
||||
{#each data.posts as post}
|
||||
<a
|
||||
href={post.href}
|
||||
>
|
||||
<div class="text-sm">{post.date}</div>
|
||||
<h4 class="text-2xl md:text-3xl">{post.title}</h4>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
```
|
||||
|
||||
Готово!
|
||||
|
||||
## Наслаждаемся результатами
|
||||
|
||||
В нашем блоге настроен <a href="https://github.com/typograf/typograf" target="_blank">типограф</a>, что позволяет нам не заботиться о переносах строк в неположенных местах,
|
||||
он заполняет текст неразрывными пробелами где надо.
|
||||
Помимо этого, он заменяет `"` на `»`, выносит кавычки за пределы ссылки, заменяет `...` на `…`, превращает `--` в `—`.
|
||||
|
||||
Это только наиболее часто встречающиеся исправления, помимо них еще огромное количество исправлений и замен.
|
||||
18
src/routes/blog/this-blog/CustomTabs.svelte
Normal file
18
src/routes/blog/this-blog/CustomTabs.svelte
Normal file
@@ -0,0 +1,18 @@
|
||||
<script lang="ts">
|
||||
let firstTabActive = true;
|
||||
</script>
|
||||
|
||||
<div class="p-8 border rounded-t-lg rounded-br-lg mt-8">
|
||||
{#if firstTabActive}
|
||||
<slot name="1"></slot>
|
||||
{:else}
|
||||
<slot name="2"></slot>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<button
|
||||
on:click={() => firstTabActive = !firstTabActive}
|
||||
class="p-4 border rounded-b-lg bg-slate-800 hover:bg-slate-700"
|
||||
>
|
||||
Сменить таб
|
||||
</button>
|
||||
Reference in New Issue
Block a user