Merge pull request #9 from michalvankodev/dev

Broadcasts segment
This commit is contained in:
Michal Vanko 2023-02-21 22:09:17 +01:00 committed by GitHub
commit f9b68c52be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
79 changed files with 503 additions and 193 deletions

2
.nvmrc
View File

@ -1 +1 @@
v16.15.1
lts/*

View File

@ -1,6 +1,8 @@
---
layout: blog
title: How I've built my website
segments:
- blog
published: true
date: 2020-02-28T16:00:55.791Z
thumbnail: /images/uploads/DSC01202.jpg

View File

@ -1,6 +1,8 @@
---
layout: blog
title: Custom Redox keyboard assembly
segments:
- blog
published: true
date: 2020-04-10T15:16:54.820Z
thumbnail: /images/uploads/img_20200301_171735.jpg

View File

@ -1,6 +1,8 @@
---
layout: blog
title: Transition to Colemak keyboard layout
segments:
- blog
published: true
date: 2020-05-11T05:38:18.797Z
tags:

View File

@ -1,6 +1,8 @@
---
layout: blog
title: Samsung Galaxy Buds+ Review
segments:
- blog
published: true
date: 2020-06-07T22:58:18.797Z # TODO executable line for generating date
tags:

View File

@ -1,6 +1,8 @@
---
layout: blog
title: I've made an RSS feed
segments:
- blog
published: true
date: 2020-06-15T15:48:18.797Z # TODO executable line for generating date
tags:

View File

@ -1,6 +1,8 @@
---
layout: blog
title: WebAssembly briefing
segments:
- blog
published: true
date: 2020-08-05T15:38:18.797Z # TODO executable line for generating date
tags:

View File

@ -1,6 +1,8 @@
---
layout: blog
title: How to deal with technical debt
segments:
- blog
published: true
date: 2020-11-08T15:57:18.797Z
tags:

View File

@ -1,6 +1,8 @@
---
layout: blog
title: I've moved my site to Netlify
segments:
- blog
published: true
date: 2020-11-20T20:35:05.230Z
tags:

View File

@ -1,6 +1,8 @@
---
layout: blog
title: Guide on error handling
segments:
- blog
published: true
date: 2020-12-09T14:44:11.948Z
tags:

View File

@ -1,6 +1,8 @@
---
layout: blog
title: Logging recommendations
segments:
- blog
published: true
date: 2020-12-18T14:39:53.533Z
tags:

View File

@ -1,6 +1,8 @@
---
layout: blog
title: Podcast episode about Agile development
segments:
- blog
published: true
date: 2021-02-16T09:09:57.102Z
tags:

View File

@ -1,6 +1,8 @@
---
layout: blog
title: Introduction to JavaScript Application testing
segments:
- blog
published: true
date: 2021-05-07T14:44:57.102Z # update date accordingly
tags:

View File

@ -1,6 +1,8 @@
---
layout: blog
title: How we handle the rapid growth of the project team
segments:
- blog
published: true
date: 2021-12-16T11:02:10.123Z
tags:

View File

@ -1,6 +1,8 @@
---
layout: blog
title: First Weekly
segments:
- blog
published: true
date: 2022-02-06T17:13:02.611Z
tags:

View File

@ -1,6 +1,8 @@
---
layout: blog
title: "I've started streaming - Weekly #06-2022 "
segments:
- blog
published: true
date: 2022-02-13T19:39:33.578Z
tags:

View File

@ -1,6 +1,8 @@
---
layout: blog
title: "Laptop battery got fat - Weekly #07-2022"
segments:
- blog
published: true
date: 2022-02-20T17:50:56.214Z
tags:

View File

@ -1,6 +1,8 @@
---
layout: blog
title: Error handling with Either<Type>
segments:
- blog
published: true
date: 2022-02-28T11:30:54.195Z
tags:

View File

@ -1,6 +1,8 @@
---
layout: blog
title: "Second attempt @ Weekly #08-2022"
segments:
- blog
published: true
date: 2022-02-28T11:49:53.914Z
tags:

View File

@ -0,0 +1,18 @@
---
layout: blog
title: "DevBreak #1 State of JS 2021 review with Lukáš Orgován"
segments:
- broadcasts
published: true
date: 2022-03-15T20:22:21.191Z
tags:
- DevBreak
---
The first episode of the [DevBreak talk show](/broadcasts/tags/DevBreak).
I've invited my close friend and a tech lead [Lukáš Orgován](https://www.linkedin.com/in/lukasorgovan/) to talk about the opinions on the results of the [State of JS 2021 survey](https://2021.stateofjs.com/en-us/).
This episode aired on the 15th of March 2022 and is in the Slovak language.
<div class="video-embed">
<iframe src="https://player.twitch.tv/?video=1427225407&parent=localhost&parent=michalvanko.dev" frameborder="0" allowfullscreen="true" scrolling="no" height="100%" width="100%" class="embed"></iframe>
</div>

View File

@ -1,6 +1,8 @@
---
layout: blog
title: "Coming from DevBreak - Weekly #11-2022"
segments:
- blog
published: true
date: 2022-03-19T21:22:35.128Z
tags:

View File

@ -1,6 +1,8 @@
---
layout: blog
title: "Happy Easter - Weekly #15-2022"
segments:
- blog
published: true
date: 2022-04-17T08:05:05.489Z
tags:

View File

@ -0,0 +1,17 @@
---
layout: blog
title: "DevBreak #2 Stories and impressions from Hack Kosice 2022"
segments:
- broadcasts
published: true
date: 2022-04-26T20:22:21.191Z
tags:
- DevBreak
---
At the last possible moment, I have been able to invite **Daniela, Samuel, and Filip** over to talk about stories and their impressions of the _Hack Kosice 2022_ event that took place last weekend.
This episode aired on the 26th of April 2022 and is in the Slovak language.
<div class="video-embed">
<iframe src="https://player.twitch.tv/?video=1468441353&parent=localhost&parent=michalvanko.dev" frameborder="0" allowfullscreen="true" scrolling="no" height="100%" width="100%" class="embed"></iframe>
</div>

View File

@ -1,6 +1,8 @@
---
layout: blog
title: 'Treasure hunt - Weekly #18-2022'
segments:
- blog
published: true
date: 2022-05-07T08:35:51.818Z
tags:

View File

@ -0,0 +1,17 @@
---
layout: blog
title: "DevBreak #3 Full-stack development with Dominik Štefan"
segments:
- broadcasts
published: true
date: 2022-06-09T20:22:21.191Z
tags:
- DevBreak
---
My friend and former colleague [Dominik Štefan](https://www.linkedin.com/in/dominik-%C5%A1tefan-167266180/) came by to talk about his experience working on full-stack web application development. We talked about many different topics but most importantly we had a lot of fun.
This episode aired on the 9th of June 2022 and is in the Slovak language.
<div class="video-embed">
<iframe src="https://player.twitch.tv/?video=1503339615&parent=localhost&parent=michalvanko.dev" frameborder="0" allowfullscreen="true" scrolling="no" height="100%" width="100%" class="embed"></iframe>
</div>

View File

@ -1,6 +1,8 @@
---
layout: blog
title: "Our attempt at Rusty game jam - Weekly #25-2022"
segments:
- blog
published: true
date: 2022-06-26T20:02:47.419Z
tags:

View File

@ -1,6 +1,8 @@
---
layout: blog
title: Lovely London Trip
segments:
- blog
published: true
date: 2022-11-27T19:49:09.204Z
tags:

View File

@ -0,0 +1,17 @@
---
layout: blog
title: "DevBreak #4 State of JS 2022 review with Filip Seman"
segments:
- broadcasts
published: true
date: 2023-01-21T20:22:21.191Z
tags:
- DevBreak
---
After another year, the results of the [State of JS](https://2022.stateofjs.com/en-us/) survey have been published.
I've invited my #1 fan and friend [Filip Seman](https://www.linkedin.com/in/xseman/).
This episode aired on the 21st of January 2023 and is in the Slovak language.
<div class="video-embed">
<iframe src="https://player.twitch.tv/?video=1715138585&parent=localhost&parent=michalvanko.dev" frameborder="0" allowfullscreen="true" scrolling="no" height="100%" width="100%" class="embed"></iframe>
</div>

View File

@ -0,0 +1,16 @@
---
layout: blog
title: "DevBreak #5 Joys and concerns of Engineering manager with Pavol Dudrík"
segments:
- broadcasts
published: true
date: 2023-02-04T20:22:21.191Z
tags:
- DevBreak
---
In this episode, I've invited my friend [Pavol Dudrík](https://www.linkedin.com/in/pavol-dudr%C3%ADk-043100168/) to talk about what motivates us and makes us happy about the work of the Engineering manager. This job combines two views, and the transition from engineer to manager is often full of pitfalls. We want to share our experience and dispel misconceptions often associated with managerial positions in IT.
This episode aired on the 4th of February 2023 and is in the Slovak language.
<div class="video-embed">
<iframe src="https://player.twitch.tv/?video=1728904048&parent=localhost&parent=michalvanko.dev" frameborder="0" allowfullscreen="true" scrolling="no" height="100%" width="100%" class="embed"></iframe>
</div>

View File

@ -1,6 +1,10 @@
---
layout: blog
title: dev - Ide to ? copy
segments:
- blog
- broadcasts
- cookbook
published: true
date: 2020-01-09T17:24:13.481Z
thumbnail: /images/uploads/screenshot.gif

View File

@ -1,6 +1,10 @@
---
layout: blog
title: dev - Ide to ?
segments:
- blog
- broadcasts
- cookbook
published: true
date: 2019-08-09T17:24:13.481Z
thumbnail: /images/uploads/screenshot.gif

View File

@ -1,6 +1,10 @@
---
layout: blog
title: dev - Anothert one
segments:
- blog
- broadcasts
- cookbook
published: true
date: 2019-11-03T11:01:32.621Z
thumbnail: /images/uploads/responzio.png

View File

@ -1,6 +1,10 @@
---
layout: blog
title: New Title
segments:
- blog
- broadcasts
- cookbook
published: true
date: 2020-05-11T05:38:18.797Z # TODO executable line for generating date
tags:

View File

@ -1,29 +0,0 @@
<section id="personal">
<h3>Personal Information</h3>
<p>I was born on 26th of May in Košice, Slovakia and I still live here.</p>
<h4>Hobbies:</h4>
<p>
I enjoy playing basketball with my friends. I also like to play other team sports like football and hockey.
I also play squash and table tennis. Once I've won a competition in squash at my university.
During summer I love water skiing and swimming in a nearby lake.
<br />
I am very passionate about music. I've also tried some software for composing music but I am not really hooked into that yet.
From time to time I enjoy playing board games with my friends.
</p>
<h4>Interests:</h4>
<p>
I like to explore new technologies and I'm passionate about <em>Open Source movement</em>,
<em>Internet of Things</em> applications and <em>Linux desktop evolution</em>.
<br />
I am interested in modern software architecture and <em>reactive programming</em>.
<br />
I've attended various <strong>tech conferences and hackathons</strong>. I like them for all of the fascinating ideas that might be invented.
<br />
I've given presentations on various topics related to <em>web development</em>. You can <a href='#presentations'>take a look at some of them here</a>.
<br />
I enjoy <strong>teaching and explaining</strong> how various technologies and techniques work to my colleagues for their better understanding.
<br />
I take advantage of <strong>test driven development</strong>.
</p>
</section><!--/personal-->

View File

@ -0,0 +1,38 @@
import { error } from '@sveltejs/kit'
import fm from 'front-matter'
import { readFile } from 'fs'
import { parseField } from '$lib/markdown/parse-markdown'
import { promisify } from 'util'
export interface ArticleAttributes {
slug: string
layout: string
segments: string[]
title: string
published: boolean
date: string
thumbnail: string
tags: string[]
body: string
}
export async function getArticleContent(slug: string) {
let postSource: string
try {
postSource = await promisify(readFile)(`_posts/blog/${slug}.md`, 'utf-8')
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (e: any) {
if (e.code === 'ENOENT') {
throw error(404, 'Post not found \n' + e.toString())
}
throw e
}
const parsedPost = fm<ArticleAttributes>(postSource)
const post = parseField<ArticleAttributes>('body')({
...parsedPost.attributes,
body: parsedPost.body,
})
return post
}

View File

@ -8,24 +8,13 @@ import {
filterAndCount,
type PaginationQuery,
} from '$lib/pagination/pagination'
import type { ArticleAttributes } from './articleContent'
export interface ArticlePreviewAttributes extends ArticleAttributes {
preview: string
}
const { NODE_ENV } = process.env
export interface PostAttributes {
layout: string
title: string
published: boolean
date: string
thumbnail: string
tags: string[]
}
export interface PostContent extends PostAttributes {
preview: string
slug: string
published: boolean
}
export async function getBlogListing(paginationQuery: PaginationQuery) {
const files = await promisify(readdir)(`_posts/blog/`, 'utf-8')
const filteredFiles = filterDevelopmentFiles(files)
@ -36,7 +25,7 @@ export async function getBlogListing(paginationQuery: PaginationQuery) {
`_posts/blog/${file}`,
'utf-8'
)
const parsedAttributes = fm<PostAttributes>(fileContent)
const parsedAttributes = fm<ArticleAttributes>(fileContent)
const lineOfTextRegExp = /^(?:\w|\[).+/gm
const lines = parsedAttributes.body
@ -53,7 +42,7 @@ export async function getBlogListing(paginationQuery: PaginationQuery) {
})
)
const filteredContents = pipe(
sortBy<PostContent>(prop('date')),
sortBy<ArticlePreviewAttributes>(prop('date')),
(items) => reverse(items),
filter<(typeof contents)[0]>((article) => article.published),
filterAndCount(paginationQuery)

View File

@ -0,0 +1,11 @@
declare global {
interface Window {
onMountScripts?: Array<() => void>
}
}
export function runOnMountScripts() {
window.onMountScripts?.forEach((fn) => {
fn()
})
}

View File

@ -1,6 +1,6 @@
<script lang="ts">
import { format } from 'date-fns'
import type { PostContent } from 'src/routes/blog/content'
import type { ArticlePreviewAttributes } from '$lib/articleContent/articleContentListing'
import SvgIcon from './SvgIcon.svelte'
import {
boldClass,
@ -22,7 +22,7 @@
licenceText,
} from './Footer.css'
export let latestPosts: PostContent[]
export let latestPosts: ArticlePreviewAttributes[]
</script>
<footer class="site-footer navigation-theme {siteFooterClass}">
@ -61,7 +61,7 @@
<ul class={listUlClass}>
{#each latestPosts as post}
<li class={listLiClass}>
<a rel="prefetch" href="/blog/{post.slug}">
<a rel="prefetch" href="/{post.segments[0]}/{post.slug}">
<span>{post.title}</span>
<time class="date {dateClass}" datetime={post.date}>
- {format(new Date(post.date), 'do MMM, yyyy')}

View File

@ -12,40 +12,48 @@
portfolioPageNavigationLinksClass,
selectedClass,
} from './Nav.css'
import { page } from "$app/stores"
import { page } from '$app/stores'
$: segment = $page.url.pathname
let links = [
{
label: 'Introduction',
url: '/',
},
{
label: 'Blog',
url: '/blog',
},
{
label: 'Broadcasts',
url: '/broadcasts',
},
// {
// label: "Dev's Cookery",
// url: '/cookery',
// },
{
label: 'Portfolio',
url: '/portfolio',
},
]
</script>
<nav class={navigationClass}>
<section class={navigationContentClass}>
<ul class={navigationLinksClass}>
<li>
<a class={classNames({ [selectedClass]: segment === '/' })} href="/">
Introduction
</a>
</li>
<!-- for the blog link, we're using rel=prefetch so that Sapper prefetches
the blog data when we hover over the link or tap it on a touchscreen -->
<li>
<a
rel="prefetch"
class={classNames({ [selectedClass]: segment.startsWith('/blog') })}
href="/blog"
>
Blog
</a>
</li>
<li>
<a
class={classNames({
[selectedClass]: segment.startsWith('/portfolio'),
})}
href="/portfolio"
>
Portfolio
</a>
</li>
{#each links as link}
<li>
<a
rel="prefetch"
class={classNames({ [selectedClass]: segment === link.url })}
href={link.url}
>
{link.label}
</a>
</li>
{/each}
</ul>
<aside class="logo-section {logoSectionClass}">

View File

@ -1,5 +1,5 @@
<script lang="ts">
import svgSprite from '../svg/build/icons-sprite.svg'
import svgSprite from '../../svg/build/icons-sprite.svg'
export let className: string
export let name: string
</script>

View File

@ -0,0 +1,18 @@
<script lang="ts">
interface ArticleDetails {
title: string
slug: string
preview: string
}
export let segment: string
export let article: ArticleDetails
</script>
<article>
<header>
<h2>
<a rel="prefetch" href={`/${segment}/${article.slug}`}>{article.title}</a>
</h2>
</header>
{@html article.preview}
</article>

View File

@ -2,26 +2,27 @@
import { horizontalBorderTopClass } from '$lib/styles/scoops.css'
import { format } from 'date-fns'
import type { PostContent } from '../../routes/blog/content'
import type { ArticleContent } from '$lib/content/articleContentListing'
import {
footerClass,
publishedClass,
publishedLabelClass,
tagsListClass,
tagsListLiClass,
} from './ArticleFooter.css'
} from './ArticlePreviewFooter.css'
export let post: PostContent
export let segment: string
export let article: ArticleContent
</script>
<footer class="{footerClass} {horizontalBorderTopClass}">
<div class="article-tags">
{#if post.tags.length > 0}
{#if article.tags.length > 0}
<span class="lighten">Tags:</span>
<ul class={tagsListClass}>
{#each post.tags as tag}
{#each article.tags as tag}
<li class={tagsListLiClass}>
<a href="/blog/tags/{tag}">{tag}</a>
<a href="/{segment}/tags/{tag}">{tag}</a>
</li>
{/each}
</ul>
@ -29,8 +30,8 @@
</div>
<div class="created-at">
<span class={publishedLabelClass}>Published on</span>
<time datetime={post.date} class={publishedClass}>
{format(new Date(post.date), "do MMMM',' y")}
<time datetime={article.date} class={publishedClass}>
{format(new Date(article.date), "do MMMM',' y")}
</time>
</div>
</footer>

View File

@ -0,0 +1,41 @@
<script lang="ts">
import ArticleFooter from '$lib/components/articles/ArticlePreviewFooter/ArticlePreviewFooter.svelte'
import Paginator from '$lib/components/paginator/Paginator.svelte'
import { postListClass } from './ArticlePreviewList.css'
import ArticlePreviewCard from '$lib/components/articles/ArticlePreviewCard/ArticlePreviewCard.svelte'
import type { PaginationResult } from '$lib/pagination/pagination'
import type { ArticleContent } from '$lib/content/articleContentListing'
export let page: number
export let pageSize: number
export let filters: Record<string, string>
export let posts: PaginationResult<ArticleContent>
export let segment: string
</script>
<header>
<Paginator
{segment}
{page}
{pageSize}
{filters}
totalCount={posts.totalCount}
/>
</header>
<ul class="post-list {postListClass}">
{#each posts.items as article (article.slug)}
<li>
<ArticlePreviewCard {article} {segment} />
<ArticleFooter {article} {segment} />
</li>
{/each}
</ul>
<footer>
<Paginator
{segment}
{page}
{pageSize}
{filters}
totalCount={posts.totalCount}
/>
</footer>

View File

@ -10,12 +10,11 @@
export const Divider = 'divider'
export let href: string
export let segment: string
export let page: number
export let pageSize: number
export let totalCount: number
export let filters: Record<string, string>
let paginatorPages: (number | typeof Divider)[]
$: paginatorPages = getPaginatorPages({ page, pageSize, totalCount })
</script>
@ -23,7 +22,7 @@
<ul class={listClass}>
{#if page !== 1}
<li class="{listItemClass} ">
<a class={pageLinkClass} href={createHref(href, filters, page - 1)}
<a class={pageLinkClass} href={createHref(segment, filters, page - 1)}
>&lt;</a
>
</li>
@ -35,7 +34,7 @@
<li class="{listItemClass} {activePage}">{pageNumber}</li>
{:else}
<li class="{listItemClass} ">
<a class={pageLinkClass} href={createHref(href, filters, pageNumber)}
<a class={pageLinkClass} href={createHref(segment, filters, pageNumber)}
>{pageNumber}</a
>
</li>
@ -43,7 +42,7 @@
{/each}
{#if page !== paginatorPages.length}
<li class="{listItemClass} ">
<a class={pageLinkClass} href={createHref(href, filters, page + 1)}
<a class={pageLinkClass} href={createHref(segment, filters, page + 1)}
>&gt;</a
>
</li>

View File

@ -11,11 +11,13 @@ export function getPaginatorPages({
page: number
pageSize: number
totalCount: number
}) {
}): (number | typeof Divider)[] {
const maxLinksLength = 7
const linksAroundActive = 2
const totalPages = Math.ceil(totalCount / pageSize)
const daco = range(1, totalPages + 1).reduce((acc, link) => {
const shownPages = range(1, totalPages + 1).reduce<
(number | typeof Divider)[]
>((acc, link) => {
const isFirst = link === 1
const isLast = link === totalPages
const isPageOnStart = page <= 3 && link < maxLinksLength
@ -36,7 +38,7 @@ export function getPaginatorPages({
return [...acc, link]
}, [])
return daco
return shownPages
}
export function createHref(

View File

@ -1,9 +1,9 @@
import { splitEvery } from 'ramda'
import { init, splitEvery } from 'ramda'
export function parseParams(params: string) {
const splittedParams = params.split('/')
let splittedParams = params.split('/')
if (splittedParams.length % 2 !== 0) {
return []
splittedParams = init(splittedParams)
}
const splits = splitEvery(2, splittedParams)
return Object.fromEntries(splits)

View File

@ -17,7 +17,10 @@ export function dropAndTake<Item>({ offset = 0, limit = Infinity }) {
) => Item[]
}
export function filterByPropContains<Item>(filters: Record<string, string>) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function filterByPropContains<Item extends Record<string, any>>(
filters: Record<string, string>
) {
return function (items: Item[]) {
return items.filter((item) => {
return Object.entries(filters).every(([fieldName, value]) =>
@ -27,7 +30,8 @@ export function filterByPropContains<Item>(filters: Record<string, string>) {
}
}
export function filterAndCount<Item>({
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function filterAndCount<Item extends Record<string, any>>({
filters,
...dropTakeParams
}: PaginationQuery) {

View File

@ -19,3 +19,9 @@ globalStyle(`${contentClass} img:only-child`, {
display: 'block',
margin: '0 auto',
})
globalStyle(`${contentClass} .video-embed`, {
margin: '0 auto',
maxWidth: vars.width.image,
aspectRatio: vars.aspectRatio.monitor,
})

View File

@ -1,7 +1,7 @@
<script lang="ts">
import type { LayoutData } from "./$types"
import Nav from '../components/Nav.svelte'
import Footer from '../components/Footer.svelte'
import type { LayoutData } from './$types'
import Nav from '$lib/components/Nav.svelte'
import Footer from '$lib/components/Footer.svelte'
import 'modern-normalize/modern-normalize.css'
import '$lib/styles/global.css'
import { mainContentClass } from './layout.css'

View File

@ -2,7 +2,7 @@ import type { LayoutLoad } from './$types'
export const prerender = true
export const load = (async ({ fetch }) => {
const blogPostsResponse = await fetch(`/blog/articles/pageSize/5.json`)
const blogPostsResponse = await fetch(`/articles/pageSize/5.json`)
const blogPostsContent = await blogPostsResponse.json()
return {

View File

@ -3,7 +3,7 @@ import {
parseParams,
} from '$lib/pagination/dropTakeParams'
import { json } from '@sveltejs/kit'
import { getBlogListing } from '../../content'
import { getBlogListing } from '$lib/articleContent/articleContentListing'
import type { RequestHandler } from './$types'
export const prerender = true

View File

@ -1,12 +1,10 @@
<script lang="ts">
import ArticleFooter from '../../../components/blog/ArticleFooter.svelte'
import Paginator from '../../../components/paginator/Paginator.svelte'
import { postListClass, seeAllClass } from './page.css'
import type { PageData } from './$types'
import ArticlePreviewList from '$lib/components/articles/ArticlePreviewList/ArticlePreviewList.svelte'
import { seeAllClass } from '$lib/components/articles/ArticlePreviewList/ArticlePreviewList.css'
export let data: PageData
let { posts, filters, page, pageSize } = data
$: ({ posts, filters, page, pageSize } = data)
$: ({ posts, filters } = data)
</script>
<svelte:head>
@ -30,36 +28,5 @@
</div>
{/if}
{/if}
<header>
<Paginator
href="blog"
{page}
{pageSize}
{filters}
totalCount={posts.totalCount}
/>
</header>
<ul class="post-list {postListClass}">
{#each posts.items as post (post.slug)}
<li>
<article>
<header>
<h2>
<a rel="prefetch" href="/blog/{post.slug}">{post.title}</a>
</h2>
</header>
{@html post.preview}
</article>
<ArticleFooter {post} />
</li>
{/each}
</ul>
<footer>
<Paginator
href="blog"
{page}
{pageSize}
{filters}
totalCount={posts.totalCount}
/>
</footer>
<ArticlePreviewList {...data} segment="blog" />

View File

@ -1,16 +1,15 @@
import { parseParams } from '$lib/pagination/dropTakeParams'
import type { PageLoad } from './$types'
import type { PostContent } from './../content'
import type { ArticlePreviewAttributes } from '$lib/articleContent/articleContentListing'
import type { PaginationResult } from '$lib/pagination/pagination'
export const load = (async ({ fetch, params }) => {
const { page = 1, pageSize = 7, ...filters } = parseParams(params.params)
const articleResponse = await fetch(
`/blog/articles/${params.params ? params.params : 'index'}.json`
`/articles/segments/blog${params.params ? `/${params.params}` : ''}.json`
).then((r) => r.json())
return {
posts: articleResponse.posts as PaginationResult<PostContent>,
posts: articleResponse.posts as PaginationResult<ArticlePreviewAttributes >,
page: Number(page),
pageSize,
filters,

View File

@ -1,35 +1,9 @@
import { readFile } from 'fs'
import { promisify } from 'util'
import fm from 'front-matter'
import { parseField } from '../../../markdown/parse-markdown'
import { error, json } from '@sveltejs/kit'
import type { PostAttributes } from '../content'
import type { PageServerLoad } from './$types'
import { getArticleContent } from '$lib/articleContent/articleContent'
export const prerender = true
export interface SinglePost {
body: string
}
export const load = (async ({ params: { slug } }) => {
let postSource: string
try {
postSource = await promisify(readFile)(`_posts/blog/${slug}.md`, 'utf-8')
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (e: any) {
if (e.code === 'ENOENT') {
throw error(404, 'Post not found \n' + e.toString())
}
throw e
}
const parsedPost = fm<PostAttributes>(postSource)
const post = parseField<SinglePost>('body')({
...parsedPost.attributes,
body: parsedPost.body,
})
const post = await getArticleContent(slug);
return post
}) satisfies PageServerLoad

View File

@ -1,9 +1,15 @@
<script lang="ts">
import ArticleFooter from '../../../components/blog/ArticleFooter.svelte'
import ArticleFooter from '$lib/components/articles/ArticlePreviewFooter/ArticlePreviewFooter.svelte'
import type { PageData } from './$types'
import { contentClass } from './page.css'
import { contentClass } from '$lib/styles/article/article.css'
import { onMount } from 'svelte'
import { runOnMountScripts } from '$lib/articleContent/onMountScripts'
export let data: PageData
onMount(() => {
runOnMountScripts()
})
</script>
<svelte:head>
@ -12,7 +18,7 @@
<h1>{data.title}</h1>
<div class="content {contentClass}">
<article class="content {contentClass}">
{@html data.body}
</div>
<ArticleFooter post={data} />
</article>
<ArticleFooter article={data} segment="blog" />

View File

@ -0,0 +1,30 @@
<script lang="ts">
import type { PageData } from './$types'
import ArticlePreviewList from '$lib/components/articles/ArticlePreviewList/ArticlePreviewList.svelte'
import { seeAllClass } from '$lib/components/articles/ArticlePreviewList/ArticlePreviewList.css'
export let data: PageData
$: ({ posts, filters } = data)
</script>
<svelte:head>
<title>Broadcasts @michalvankodev</title>
</svelte:head>
{#if posts.items.length === 0}
<p class="no-posts">You've found void in the space.</p>
{:else}
<h1>
{#if filters.tags}
<em>{filters.tags}</em>
{/if}
Broadcasts
</h1>
{#if filters.tags}
<div class={seeAllClass}>
<a href="/broadcasts">See all broadcasts</a>
</div>
{/if}
{/if}
<ArticlePreviewList {...data} segment="broadcasts" />

View File

@ -0,0 +1,18 @@
import { parseParams } from '$lib/pagination/dropTakeParams'
import type { PageLoad } from './$types'
import type { ArticlePreviewAttributes } from '$lib/articleContent/articleContentListing'
import type { PaginationResult } from '$lib/pagination/pagination'
export const load = (async ({ fetch, params }) => {
const { page = 1, pageSize = 7, ...filters } = parseParams(params.params)
const articleResponse = await fetch(
`/articles/segments/broadcasts${params.params ? `/${params.params}` : ''}.json`
).then((r) => r.json())
return {
posts: articleResponse.posts as PaginationResult<ArticlePreviewAttributes>,
page: Number(page),
pageSize,
filters,
}
}) satisfies PageLoad

View File

@ -0,0 +1,9 @@
import type { PageServerLoad } from './$types'
import { getArticleContent } from '$lib/articleContent/articleContent'
export const prerender = true
export const load = (async ({ params: { slug } }) => {
const post = await getArticleContent(slug);
return post
}) satisfies PageServerLoad

View File

@ -0,0 +1,24 @@
<script lang="ts">
import ArticleFooter from '$lib/components/articles/ArticlePreviewFooter/ArticlePreviewFooter.svelte'
import type { PageData } from './$types'
import { contentClass } from '$lib/styles/article/article.css'
import { onMount } from 'svelte'
import { runOnMountScripts } from '$lib/articleContent/onMountScripts'
export let data: PageData
onMount(() => {
runOnMountScripts()
})
</script>
<svelte:head>
<title>{data.title}</title>
</svelte:head>
<h1>{data.title}</h1>
<article class="content {contentClass}">
{@html data.body}
</article>
<ArticleFooter article={data} segment="broadcasts" />

View File

@ -1,5 +1,5 @@
import { getBlogListing } from '$lib/articleContent/articleContentListing'
import { Feed } from 'feed'
import { getBlogListing } from './blog/content'
export async function getFeed() {
const feed = new Feed({

View File

@ -3,7 +3,7 @@ import { promisify } from 'util'
import fm from 'front-matter'
// TODO Switch marked for unified
import marked from 'marked'
import { parseField } from '../../markdown/parse-markdown'
import { parseField } from '$lib/markdown/parse-markdown'
import type { PageServerLoad } from './$types'
export const prerender = true

View File

@ -1,7 +1,7 @@
<script lang="ts">
import Work from '../../components/portfolio/work.svelte'
import Project from '../../components/portfolio/project.svelte'
import Presentation from '../../components/portfolio/presentation.svelte'
import Work from './components/work.svelte'
import Project from './components/project.svelte'
import Presentation from './components/presentation.svelte'
import type { PageData } from './$types'
import { listClass, listItemClass, nameTagClass } from './page.css'

View File

@ -0,0 +1,39 @@
<section id="personal">
<h3>Personal Information</h3>
<p>I was born on 26th of May in Košice, Slovakia and I still live here.</p>
<h4>Hobbies:</h4>
<p>
I enjoy playing basketball with my friends. I also like to play other team
sports like football and hockey. I also play squash and table tennis. Once
I've won a competition in squash at my university. During summer I love
water skiing and swimming in a nearby lake.
<br />
I am very passionate about music. I've also tried some software for composing
music but I am not really hooked into that yet. From time to time I enjoy playing
board games with my friends.
</p>
<h4>Interests:</h4>
<p>
I like to explore new technologies and I'm passionate about <em
>Open Source movement</em
>,
<em>Internet of Things</em> applications and
<em>Linux desktop evolution</em>.
<br />
I am interested in modern software architecture and
<em>reactive programming</em>.
<br />
I've attended various <strong>tech conferences and hackathons</strong>. I
like them for all of the fascinating ideas that might be invented.
<br />
I've given presentations on various topics related to
<em>web development</em>. You can
<a href="#presentations">take a look at some of them here</a>.
<br />
I enjoy <strong>teaching and explaining</strong> how various technologies
and techniques work to my colleagues for their better understanding.
<br />
I take advantage of <strong>test driven development</strong>.
</p>
</section>
<!--/personal-->

View File

@ -19,6 +19,15 @@ collections:
fields: # The fields for each document, usually in front matter
- { label: 'Layout', name: 'layout', widget: 'hidden', default: 'blog' }
- { label: 'Title', name: 'title', widget: 'string' }
- label: 'Segments'
name: 'segments'
widget: 'select'
multiple: true
options:
- { label: 'Blog', value: 'blog' }
- { label: 'Broadcasts', value: 'broadcasts' }
- { label: 'Cookbook', value: 'cookbook' }
default: ['blog']
- {
label: 'Published',
name: 'published',