Compare commits

...

10 Commits

Author SHA1 Message Date
Sage Vaillancourt adbdec31cc Bump up h2 font-size. 2022-09-09 07:18:16 -04:00
Sage Vaillancourt 80be787180 Serif blog font.
Other CSS tweaks, including header margin-bottoms.
2022-09-08 16:59:55 -04:00
Sage Vaillancourt d97433279b Add more to what-is-kafka.md
A few appearance tweaks. Mostly for headings.
2022-09-08 00:30:56 -04:00
Sage Vaillancourt b2107c5d12 A couple CSS tweaks and general clean-up. 2022-09-06 16:52:33 -04:00
Sage Vaillancourt f4db844b7c Better big-photo display 2022-09-03 23:09:26 -04:00
Sage Vaillancourt ce0fc46e0f A couple visual fixes.
Add GitLab link back to nav bar.
2022-09-03 23:03:11 -04:00
Sage Vaillancourt 531b913404 A couple visual fixes 2022-09-03 13:34:59 -04:00
Sage Vaillancourt c19413a723 Add missing static images. 2022-09-02 15:40:31 -04:00
Sage Vaillancourt 199a38a6f2 Add blog generation from Markdown.
Also tweak README, and homepage title font.
2022-09-02 15:40:07 -04:00
Sage Vaillancourt 691a8a72eb Enable static building 2022-09-02 11:41:38 -04:00
18 changed files with 474 additions and 104 deletions

View File

@ -1,22 +1,10 @@
# create-svelte
# Kafka Dance Site
Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte).
## Creating a project
If you're seeing this, you've probably already done this step. Congrats!
```bash
# create a new project in the current directory
npm create svelte@latest
# create a new project in my-app
npm create svelte@latest my-app
```
Powered by Svelte!
## Developing
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
Once you've downloaded the project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
```bash
npm run dev
@ -27,12 +15,12 @@ npm run dev -- --open
## Building
To create a production version of your app:
To build out the production version:
```bash
npm run build
```
You can preview the production build with `npm run preview`.
This is currently configured to build as a completely static app.
> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.
You can preview the production build with `npm run preview`.

113
package-lock.json generated
View File

@ -11,6 +11,7 @@
"@sveltejs/adapter-auto": "next",
"@sveltejs/adapter-static": "^1.0.0-next.41",
"@sveltejs/kit": "next",
"mdsvex": "^0.10.6",
"svelte": "^3.44.0",
"svelte-check": "^2.7.1",
"typescript": "^4.7.4",
@ -293,6 +294,12 @@
"@types/node": "*"
}
},
"node_modules/@types/unist": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz",
"integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==",
"dev": true
},
"node_modules/@vercel/nft": {
"version": "0.22.0",
"resolved": "https://registry.npmjs.org/@vercel/nft/-/nft-0.22.0.tgz",
@ -1339,6 +1346,21 @@
"semver": "bin/semver.js"
}
},
"node_modules/mdsvex": {
"version": "0.10.6",
"resolved": "https://registry.npmjs.org/mdsvex/-/mdsvex-0.10.6.tgz",
"integrity": "sha512-aGRDY0r5jx9+OOgFdyB9Xm3EBr9OUmcrTDPWLB7a7g8VPRxzPy4MOBmcVYgz7ErhAJ7bZ/coUoj6aHio3x/2mA==",
"dev": true,
"dependencies": {
"@types/unist": "^2.0.3",
"prism-svelte": "^0.4.7",
"prismjs": "^1.17.1",
"vfile-message": "^2.0.4"
},
"peerDependencies": {
"svelte": "3.x"
}
},
"node_modules/merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@ -1644,6 +1666,21 @@
"node": "^10 || ^12 || >=14"
}
},
"node_modules/prism-svelte": {
"version": "0.4.7",
"resolved": "https://registry.npmjs.org/prism-svelte/-/prism-svelte-0.4.7.tgz",
"integrity": "sha512-yABh19CYbM24V7aS7TuPYRNMqthxwbvx6FF/Rw920YbyBWO3tnyPIqRMgHuSVsLmuHkkBS1Akyof463FVdkeDQ==",
"dev": true
},
"node_modules/prismjs": {
"version": "1.29.0",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz",
"integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==",
"dev": true,
"engines": {
"node": ">=6"
}
},
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@ -2201,12 +2238,39 @@
"node": ">=12.18"
}
},
"node_modules/unist-util-stringify-position": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz",
"integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==",
"dev": true,
"dependencies": {
"@types/unist": "^2.0.2"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"dev": true
},
"node_modules/vfile-message": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz",
"integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==",
"dev": true,
"dependencies": {
"@types/unist": "^2.0.0",
"unist-util-stringify-position": "^2.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/vite": {
"version": "3.1.0-beta.1",
"resolved": "https://registry.npmjs.org/vite/-/vite-3.1.0-beta.1.tgz",
@ -2525,6 +2589,12 @@
"@types/node": "*"
}
},
"@types/unist": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz",
"integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==",
"dev": true
},
"@vercel/nft": {
"version": "0.22.0",
"resolved": "https://registry.npmjs.org/@vercel/nft/-/nft-0.22.0.tgz",
@ -3220,6 +3290,18 @@
}
}
},
"mdsvex": {
"version": "0.10.6",
"resolved": "https://registry.npmjs.org/mdsvex/-/mdsvex-0.10.6.tgz",
"integrity": "sha512-aGRDY0r5jx9+OOgFdyB9Xm3EBr9OUmcrTDPWLB7a7g8VPRxzPy4MOBmcVYgz7ErhAJ7bZ/coUoj6aHio3x/2mA==",
"dev": true,
"requires": {
"@types/unist": "^2.0.3",
"prism-svelte": "^0.4.7",
"prismjs": "^1.17.1",
"vfile-message": "^2.0.4"
}
},
"merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@ -3424,6 +3506,18 @@
"source-map-js": "^1.0.2"
}
},
"prism-svelte": {
"version": "0.4.7",
"resolved": "https://registry.npmjs.org/prism-svelte/-/prism-svelte-0.4.7.tgz",
"integrity": "sha512-yABh19CYbM24V7aS7TuPYRNMqthxwbvx6FF/Rw920YbyBWO3tnyPIqRMgHuSVsLmuHkkBS1Akyof463FVdkeDQ==",
"dev": true
},
"prismjs": {
"version": "1.29.0",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz",
"integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==",
"dev": true
},
"queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@ -3786,12 +3880,31 @@
"integrity": "sha512-c8HsD3IbwmjjbLvoZuRI26TZic+TSEe8FPMLLOkN1AfYRhdjnKBU6yL+IwcSCbdZiX4e5t0lfMDLDCqj4Sq70g==",
"dev": true
},
"unist-util-stringify-position": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz",
"integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==",
"dev": true,
"requires": {
"@types/unist": "^2.0.2"
}
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"dev": true
},
"vfile-message": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz",
"integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==",
"dev": true,
"requires": {
"@types/unist": "^2.0.0",
"unist-util-stringify-position": "^2.0.0"
}
},
"vite": {
"version": "3.1.0-beta.1",
"resolved": "https://registry.npmjs.org/vite/-/vite-3.1.0-beta.1.tgz",

View File

@ -13,6 +13,7 @@
"@sveltejs/adapter-auto": "next",
"@sveltejs/adapter-static": "^1.0.0-next.41",
"@sveltejs/kit": "next",
"mdsvex": "^0.10.6",
"svelte": "^3.44.0",
"svelte-check": "^2.7.1",
"typescript": "^4.7.4",

View File

@ -1,4 +1,4 @@
@import url('https://fonts.googleapis.com/css2?family=Fira+Sans&family=Montserrat:wght@500&family=Roboto&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Fira+Sans&family=Inter:wght@600;800&family=Montserrat:wght@500&family=Roboto&family=Source+Serif+Pro&display=swap');
:root {
font-family: 'Fira Sans', Arial, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu,
@ -18,12 +18,6 @@
--column-margin-top: 4rem;
}
.root-div {
height: 100vh;
display: flex;
flex-direction: column;
}
select, button, input {
font-family: Roboto, Arial, -apple-system, BlinkMacSystemFont, 'Segoe UI', Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
font-size: 90%;
@ -176,8 +170,8 @@ h1 {
}
h1 .fun {
/*font-family: sans-serif;*/
font-weight: 600;
font-family: 'Inter', sans-serif;
font-weight: 700;
color: var(--accent-color);
}
@ -189,12 +183,18 @@ p {
}
h3 {
font-family: 'Montserrat', sans-serif;
margin-top: 0;
font-size: 1.2rem;
margin-bottom: 0;
}
h4 {
font-size: 1.1rem;
margin-bottom: 0;
}
p {
line-height: 1.5;
font-size: 1.3rem;
}
a {
@ -211,20 +211,35 @@ h1, h2 {
}
h2 {
font-size: 1.2rem;
font-size: 2rem;
margin-bottom: 0;
}
pre {
font-size: 16px;
font-family: var(--font-mono);
background-color: rgba(255, 255, 255, 0.45);
border-radius: 3px;
box-shadow: 2px 2px 6px rgb(255 255 255 / 25%);
padding: 0.5em;
overflow-x: auto;
color: var(--text-color);
}
code {
font-size: 16px;
font-family: var(--font-mono);
}
/*
.token.property {
color: #486eff;
}
.token.string {
color: #dc1daf;
}
.token.number {
color: #60250c;
}
*/
.bracket {
color: #a0adb9;
}
@ -255,9 +270,15 @@ button:focus:not(:focus-visible) {
@media (min-width: 720px) {
h1 {
font-size: 5rem;
font-size: 6rem;
}
h2 {
font-size: 2rem;
}
}
@media (max-width: 719px) {
.wide-only {
display: none;
}
}

View File

@ -7,6 +7,6 @@
%sveltekit.head%
</head>
<body>
<div class="root-div">%sveltekit.body%</div>
%sveltekit.body%
</body>
</html>

View File

@ -1,9 +1,8 @@
<script>
import { page } from '$app/stores';
const routes = [
{ path: '/', name: 'Home' },
{ path: '/download', name: 'Download' },
//{ path: '/about', name: 'About' }
{ path: '/blog', name: 'Blog' },
]
</script>
@ -11,16 +10,21 @@
<div>
</div>
<div>
<ul data-sveltekit-prefetch>
<li class:active={$page.url.pathname === '/'}>
<a href='/'>Home</a>
</li>
{#each routes as route}
<li class:active={$page.url.pathname === route.path}>
<li class:active={$page.url.pathname.startsWith(route.path)}>
<a href={route.path}>{route.name}</a>
</li>
{/each}
</ul>
</div>
<div style="display: flex; align-items: center;">
<a title="Kafka Dance GitLab" href="https://gitlab.com/kafka-dance">
<img alt="GitLab Logo" style="height: 20px;"
<img alt="GitLab Logo" style="height: 18px; width: auto;"
class="white-glow"
src="/gitlab-logo-white.svg">
</a>
@ -46,7 +50,7 @@
}
li {
content: '';
padding: 0 2em;
padding: 0 1em;
white-space: nowrap;
}
li a {
@ -55,4 +59,9 @@
li.active::before {
content: '> '
}
@media (min-width: 480px) {
li {
padding: 0 2em;
}
}
</style>

1
src/routes/+layout.js Normal file
View File

@ -0,0 +1 @@
export const prerender = true

View File

@ -1,6 +1,4 @@
<script>
export const prerender = true
import '../app.css'
import Header from '$lib/header/Header.svelte'
</script>
@ -19,11 +17,9 @@
flex-direction: column;
padding: 1rem 1rem 0;
width: 100%;
/*
max-width: 1024px;
*/
margin: 0 auto;
box-sizing: border-box;
align-items: center;
}
footer {

View File

@ -1,6 +1,5 @@
<script>
import logo from '$lib/kd-full-logo.png';
import Todo from "$lib/Todo.svelte";
const id = 'a59038fa-5098-4e7a-836b-f62342ac445b'
const id2 = '1b581662-2f49-4307-af93-fcd97a1dbd8e'
@ -31,12 +30,6 @@ JSON.parse(`{
"purchaseId": "${id}"
}`)
], 3)
let realTimeIndex = 0
const randomizeRealTime = () => setTimeout(() => {
realTimeIndex = (realTimeIndex + 1) % fakeObjects.length
randomizeRealTime()
}, 1500)
randomizeRealTime()
let line = 0
let oneShotText = JSON.stringify(fakeObjects[0])
@ -72,19 +65,15 @@ JSON.parse(`{
}
}
$: filteredObject = stringy(fakeObjects.filter(filterFunc)[0]) || 'No results found.'.padEnd(50)
const nextFilterText = () => setTimeout(() => {
filterTextIndex = (filterTextIndex + 1) % filterTexts.length
nextFilterText()
}, 2800)
nextFilterText()
let realTimeIndex = 0
if (typeof window !== 'undefined') {
window.setInterval(() => realTimeIndex = (realTimeIndex + 1) % fakeObjects.length, 1500)
window.setInterval(() => filterTextIndex = (filterTextIndex + 1) % filterTexts.length, 2800)
}
</script>
<div class="logo-json-box">
<!--
<img src="/json.png" alt="With Kafka Dance, browsing Kafka data is easy" />
-->
</div>
<div class="content">
<div class="eye-catch">
<h1>Data should be <span class="fun">Fun</span></h1>
@ -92,10 +81,6 @@ JSON.parse(`{
<div class="button-container">
<a href="/download"><button class="colored">Download Now</button></a>
</div>
<Todo>
Push 'What is Kafka Dance?' down further, but come up with a visual indicator that there's
more to read. Something like this, but better:
</Todo>
</div>
<div class="column">
@ -112,12 +97,12 @@ JSON.parse(`{
<div class="data-display">
<div class="data-display-section">
<h3>Search your message history</h3>
<pre style={`color: ${oneShotColor}`};>{oneShotText}</pre>
<pre style={`color: ${oneShotColor}`};><code>{oneShotText}</code></pre>
</div>
<div class="data-display-section real-time-display">
<h3>Or monitor in real time</h3>
<pre>{JSON.stringify(fakeObjects[realTimeIndex], null, 2)}</pre>
<pre><code>{JSON.stringify(fakeObjects[realTimeIndex], null, 2)}</code></pre>
</div>
</div>
</div>
@ -126,17 +111,34 @@ JSON.parse(`{
<h2>Flexible search</h2>
<h3>Powered by Javascript</h3>
<div class="data-display">
<div class="data-display-section">
<pre style="width: 90%; margin-top: 0; padding-bottom: 0.5em; border-bottom: solid #fbc; border-radius: 0; border-width: 1px;"><span style="color: #533;">=&gt;</span> {filterTexts[filterTextIndex]}</pre>
<pre>{filteredObject}</pre>
<div class="data-display-section standalone-data-display">
<pre><code><span style="color: #533;" class="wide-only">=&gt; </span>{filterTexts[filterTextIndex]}</code></pre>
<hr>
<pre><code>{filteredObject}</code></pre>
</div>
</div>
</div>
</div>
<style>
h1 {
padding-top: 1em;
h3 {
margin-top: 0;
}
.standalone-data-display pre {
width: 90%;
margin-top: 0;
}
.data-display-section hr {
margin-top: -0.5em;
border-radius: 0;
border-top-style: none;
border-right-style: none;
border-left-style: none;
border-bottom-style: solid;
border-bottom-width: 1px;
border-bottom-color: #fbc;
}
.with-kafka-dance span {
@ -147,8 +149,6 @@ JSON.parse(`{
flex-wrap: nowrap;
}
.data-display-section h3 {
}
.data-display-section {
padding: 1em 1em 0;
border-radius: 4px;
@ -199,7 +199,7 @@ JSON.parse(`{
}
.eye-catch {
margin-bottom: 1em;
margin: 1em;
}
.eye-catch h2 {
@ -223,10 +223,8 @@ JSON.parse(`{
img.big-photo {
display: inline-block;
/*max-width: 40vw;*/
/*max-height: 50vw;*/
margin-top: 2em;
max-width: 60vw;
max-width: 90vw;
height: auto;
}
@ -240,13 +238,6 @@ JSON.parse(`{
margin-top: 6em;
}
.logo-json-box {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
.data-display {
display: flex;
flex-wrap: wrap;
@ -271,7 +262,8 @@ JSON.parse(`{
flex-direction: row;
}
img.big-photo {
width: 70vw;
max-width: 70vw;
max-height: 70vh;
}
.continue-reading {

View File

@ -0,0 +1,28 @@
import { json } from '@sveltejs/kit'
const fetchMarkdownPosts = async () => {
const allPostFiles = import.meta.glob('/src/routes/blog/*.md')
const iterablePostFiles = Object.entries(allPostFiles)
return Promise.all(
iterablePostFiles.map(async ([path, resolver]) => {
const { metadata } = await resolver()
const postPath = path.slice(11, -3)
return {
meta: metadata,
path: postPath,
}
})
)
}
export const GET = async () => {
const allPosts = await fetchMarkdownPosts()
const sortedPosts = allPosts.sort((a, b) => {
return new Date(b.meta.date) - new Date(a.meta.date)
})
return json(sortedPosts)
}

4
src/routes/blog/+page.js Normal file
View File

@ -0,0 +1,4 @@
export async function load ({ fetch }) {
const response = await fetch('/api/posts')
return await response.json()
}

View File

@ -0,0 +1,68 @@
<script>
export let data = {}
$: dataList = Object.values(data)
</script>
<h1>Blog</h1>
<div class="content">
{#each dataList as datum}
<a href={datum.path}>
<div class="with-image">
<div class="blog-entry">
<div class="metadata">
<h2>{datum.meta.title}</h2>
<p>{datum.meta.date}</p>
</div>
<p class="description">{datum.meta.description}</p>
</div>
<img src={datum.meta.headerImage} alt={datum.meta.headerImageAlt}>
</div>
</a>
{/each}
</div>
<style>
.with-image {
display: flex;
flex-direction: column;
background-color: rgba(0, 0, 0, 0.03);
padding: 1em;
transition: background-color 300ms;
}
.with-image:hover {
background-color: rgba(0, 0, 0, 0.08);
}
.with-image img {
max-width: 90%;
}
.blog-entry {
display: flex;
flex-direction: column;
}
.metadata {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.metadata * {
margin: 0;
}
.content {
flex-grow: 1;
display: flex;
flex-direction: column;
align-items: center;
}
a {
text-decoration: none;
}
@media (min-width: 720px) {
.blog-entry {
max-width: 70vw;
}
}
</style>

View File

@ -0,0 +1,9 @@
export async function load({ params }){
const post = await import(/* @vite-ignore */ `../${params.post}.md`)
const content = post.default
return {
content,
metadata: post.metadata,
}
}

View File

@ -0,0 +1,66 @@
<script>
export let data
</script>
<svelte:head>
<style>
/*
* Done within <head> because elements within svelte:component
* are otherwise not styled
*/
.content p, .content h2, .content h3, .content h4 {
font-family: 'Source Serif Pro', serif;
}
.content h3 {
font-size: 1.3rem;
}
</style>
</svelte:head>
<div class="title-with-image">
<h1>{data.metadata.title}</h1>
<img src={data.metadata.headerImage} alt={data.metadata.headerImageAlt}/>
</div>
<div class="content">
<svelte:component this={data.content} />
</div>
<style>
h1 {
margin-bottom: 0;
}
.content {
max-width: 90vw;
display: flex;
flex-direction: column;
flex-wrap: wrap;
}
.title-with-image {
display: flex;
flex-direction: column;
flex-wrap: wrap;
align-items: center;
justify-content: center;
}
.title-with-image h1 {
font-size: 5rem;
}
.title-with-image img {
margin: 0 2em 0;
}
.title-with-image img {
max-width: 80vw;
}
@media (min-width: 720px) {
.content {
flex-wrap: nowrap;
max-width: calc(min(700px, 100%));
}
.title-with-image img {
max-width: 30vw;
}
}
</style>

View File

@ -0,0 +1,69 @@
---
title: What is Kafka?
date: "2022-09-02"
description: "A brief description of the increasingly-popular event system, Apache Kafka."
headerImage: "/kafka-logo.png"
headerImageAlt: "Kafka's logo"
---
Initially built by LinkedIn, Apache Kafka is a distributed event store and stream processing platform. But, in more
practical terms, what does it _do?_
## Basics of Kafka
The core principles of Kafka are very simple. There are three key components: producers, consumers, and the kafka cluster.
### Producers
Producers are responsible for creating new messages for your Kafka system. Every time an event occurs that the system
should know about, a producer will generate a message describing this event.
For example, a bookstore may have an application that _produces_ a message every time someone buys a new book:
```json
{
"action": "purchase",
"title": "The Metamorphosis",
"price": 9.99,
"buyerId": "84694fc7",
"storeNum": "FL-231"
}
```
The rest of the system decides what exactly to _do_ with this new information. Those parts of the system are called
**Consumers**.
### Consumers
Whenever a message is produced in the Kafka system, a consumer can act in response to that new information.
Returning to the previous example: this particular bookstore may have a service that informs authors and publishers
every time one of their books has been purchased. This service may work as a consumer. Then, every time a book is
purchased, the service _consumes_ the new message, and alerts the creators however it sees fit.
One of the main benefits of this structure is an inherent loose coupling. Producers do not care how consumers work. If a
consumer wants to send a text, rent a billboard, or order an ice cream, the producer simply is not interested. This
allows each part of the system to focus on its own piece of the domain, each staying smaller and more self-contained.
### Kafka Cluster
The Kafka cluster, in short is what facilitates the connection between producers and consumers. An indefinite number of
producers and consumers can connect to the cluster, and the cluster itself can be powered by many servers.
The cluster decides exactly which messages need to go where, and a key part of this process is its use of **Topics**.
### Topics
"Topics" are Kafka's way of dividing up messages into different categories. A simple topic for our bookstore might be
`book_purchases`, or `coffee_orders` (for the requisite café inside). So, when a book is sold, our producer would push a
new message into the `book_purchases` topic. And of course, when someone orders a delicious fancy latte, a message is
instead put into the `coffee_orders` topic.
Importantly, consumers do not blindly receive every message produced in the system. Instead, they subscribe to
individual topics. Our author-notification service might subscribe just to the `book_purchases` topic, not being
very interested in messages from `coffee_orders`.
Thus, every time the Kafka cluster receives a newly-produced message with a given topic, it only forwards it along to
consumers that have intentionally subscribed.
TODO: Wrap it up.

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><path d="M0 0h100v100H0z" fill="none"/><path d="M99.82 56.61 94.21 39.4 83.13 5.25a1.92 1.92 0 0 0-3.63 0L68.41 39.38H31.58L20.5 5.25a1.92 1.92 0 0 0-3.63 0L5.8 39.38.2 56.61a3.82 3.82 0 0 0 1.38 4.26L50 96.06l48.42-35.18a3.83 3.83 0 0 0 1.4-4.26" fill="#ec6d2e" style="fill:#fff"/><path d="m50 96 18.42-56.63H31.6z" fill="#9c9b9b" style="fill:#fff"/><path d="M50 96 31.58 39.37H5.8z" fill="#c6c6c5" style="fill:#fff"/><path d="M5.79 39.39.19 56.61a3.82 3.82 0 0 0 1.38 4.26L50 96.06z" fill="#ececec" style="fill:#fff"/><path d="M5.8 39.39h25.8L20.5 5.27a1.92 1.92 0 0 0-3.63 0z" fill="#9c9b9b" style="fill:#fff"/><path d="m50 96 18.42-56.63h25.8z" fill="#c6c6c5" style="fill:#fff"/><path d="m94.21 39.39 5.6 17.22a3.82 3.82 0 0 1-1.38 4.26L50 96l44.2-56.64z" fill="#ececec" style="fill:#fff"/><path d="M94.22 39.39h-25.8L79.5 5.27a1.92 1.92 0 0 1 3.63 0z" fill="#9c9b9b" style="fill:#fff"/></svg>

After

Width:  |  Height:  |  Size: 959 B

BIN
static/kafka-logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

@ -1,19 +1,23 @@
import * as staticAdapter from '@sveltejs/adapter-static';
import adapter from '@sveltejs/adapter-auto';
const a = adapter()
const s = staticAdapter.default({
pages: 'build',
assets: 'build',
fallback: null,
precompress: false
})
import adapter from '@sveltejs/adapter-static';
import { mdsvex } from "mdsvex";
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
adapter: a,
}
adapter: adapter({
pages: 'build',
assets: 'build',
fallback: null,
precompress: false
}),
},
extensions: ['.svelte', '.svx', '.md'],
preprocess: [
mdsvex({
extensions: ['.svx', '.md']
})
],
};
export default config;