Initial commit

This commit is contained in:
Shav Kinderlehrer 2023-09-18 23:39:09 -04:00
commit f52a1ed7fd
23 changed files with 2142 additions and 0 deletions

88
.gitignore vendored Normal file
View File

@ -0,0 +1,88 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
# Created by https://www.toptal.com/developers/gitignore/api/macos,windows,linux
# Edit at https://www.toptal.com/developers/gitignore?templates=macos,windows,linux
### Linux ###
*~
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
# .nfs files are created when an open file is removed but is still being accessed
.nfs*
### macOS ###
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### macOS Patch ###
# iCloud generated files
*.icloud
### Windows ###
# Windows thumbnail cache files
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db
# Dump file
*.stackdump
# Folder config file
[Dd]esktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp
# Windows shortcuts
*.lnk
# End of https://www.toptal.com/developers/gitignore/api/macos,windows,linux

2
.npmrc Normal file
View File

@ -0,0 +1,2 @@
engine-strict=true
resolution-mode=highest

38
README.md Normal file
View File

@ -0,0 +1,38 @@
# create-svelte
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
```
## Developing
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
```bash
npm run dev
# or start the server and open the app in a new browser tab
npm run dev -- --open
```
## Building
To create a production version of your app:
```bash
npm run build
```
You can preview the production build with `npm run preview`.
> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.

28
package.json Normal file
View File

@ -0,0 +1,28 @@
{
"name": "blog",
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
},
"devDependencies": {
"@sveltejs/adapter-auto": "^2.0.0",
"@sveltejs/kit": "^1.20.4",
"svelte": "^4.0.5",
"svelte-check": "^3.4.3",
"tslib": "^2.4.1",
"typescript": "^5.0.0",
"vite": "^4.4.2"
},
"type": "module",
"dependencies": {
"firebase": "^10.4.0",
"highlight.js": "^11.8.0",
"marked": "^9.0.2",
"marked-highlight": "^2.0.6"
}
}

12
src/app.d.ts vendored Normal file
View File

@ -0,0 +1,12 @@
// See https://kit.svelte.dev/docs/types#app
// for information about these interfaces
declare global {
namespace App {
// interface Error {}
// interface Locals {}
// interface PageData {}
// interface Platform {}
}
}
export {};

22
src/app.html Normal file
View File

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width" />
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link
href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:ital,wght@0,400;0,700;1,400;1,700&family=Poppins:ital,wght@0,400;0,700;1,400;1,700&display=swap"
rel="stylesheet">
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">
<div style="display: contents">%sveltekit.body%</div>
</body>
</html>

1
src/lib/index.ts Normal file
View File

@ -0,0 +1 @@
// place files you want to import through the `$lib` alias in this folder.

10
src/lib/util/article.ts Normal file
View File

@ -0,0 +1,10 @@
interface Article {
data: string,
date: string,
meta: string,
search: string,
slug: string,
title: string,
}
export type { Article }

51
src/lib/util/firebase.ts Normal file
View File

@ -0,0 +1,51 @@
import { initializeApp } from "firebase/app";
import { getFirestore, collection, query, orderBy, getDocs, where } from "firebase/firestore/lite";
import type { Article } from "$lib/util/article";
const firebaseConfig = {
apiKey: "AIzaSyATAGDs9oPN5EWK82c3J__raiRWGLjHlvY",
authDomain: "light-bl.firebaseapp.com",
projectId: "light-bl",
storageBucket: "light-bl.appspot.com",
messagingSenderId: "954661173771",
appId: "1:954661173771:web:f3da7b4a8a77236db0650e",
measurementId: "G-9YVXH0HC8Q"
};
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
async function getAllArticles(): Promise<Article[]> {
const articlesRef = collection(db, "articles");
const q = query(articlesRef, orderBy("date", "desc"));
const snapshot = await getDocs(q);
const results: Article[] = [];
snapshot.forEach(doc => {
results.push(doc.data() as Article);
});
return results;
}
async function getArticleBySlug(slug: string): Promise<Article> {
const articlesRef = collection(db, "articles");
const q = query(articlesRef, where("slug", "==", slug));
const snapshot = await getDocs(q);
const results: Article[] = [];
snapshot.forEach(doc => {
results.push(doc.data() as Article);
});
if (results.length != 1) {
throw new Error(`article ${slug} not found.`);
}
return results[0];
}
export { getAllArticles, getArticleBySlug };

0
src/lib/util/store.ts Normal file
View File

View File

@ -0,0 +1,5 @@
<script lang="ts">
import "./app.css";
</script>
<slot />

55
src/routes/+page.svelte Normal file
View File

@ -0,0 +1,55 @@
<script lang="ts">
import type { PageData } from "./$types";
export let data: PageData;
</script>
<main>
<div id="title">
<h1>trinket blog</h1>
<h2 class="sub">dev writing about anything under the sun</h2>
</div>
<div id="articles">
<ul>
{#each data.articles as article, i}
<li class={i % 2 == 0 ? "even" : "odd"}>
<a href="/articles/{article.slug}">{article.date} ~> {article.title}</a
>
</li>
{/each}
</ul>
</div>
</main>
<style>
#title {
text-align: center;
}
#articles {
display: flex;
justify-content: center;
}
.even {
}
.odd {
background: #f2f2f2;
}
ul {
list-style-type: none;
padding: 0;
}
li {
margin: 0.5em;
padding: 0 0.2em;
}
li:hover {
background: #dbdbdb;
}
</style>

12
src/routes/+page.ts Normal file
View File

@ -0,0 +1,12 @@
import type { PageLoad } from "./$types"
import type { Article } from "$lib/util/article";
import { getAllArticles } from "$lib/util/firebase";
export const load: PageLoad = async ({ params }) => {
const articles: Article[] = await getAllArticles();
return {
articles: articles,
}
}

15
src/routes/app.css Normal file
View File

@ -0,0 +1,15 @@
* {
font-family: 'Poppins', sans-serif;
}
pre, code, span {
font-family: 'JetBrains Mono', monospace !important;
}
img {
max-width: 80%;
}
.sub {
color: #aaa;
}

View File

@ -0,0 +1,39 @@
<script lang="ts">
import type { PageData } from "./$types";
export let data: PageData;
</script>
<main>
<div id="header">
{#if data.prev}
<a href="/articles/{data.prev.slug}">&lt;&lt;</a>
{/if}
<a href="/">home</a>
{#if data.next}
<a href="/articles/{data.next.slug}">&gt;&gt;</a>
{/if}
</div>
<hr />
<slot />
<hr />
<div id="footer">
{#if data.prev}
<a href="/articles/{data.prev.slug}">&lt;&lt;</a>
{/if}
<a href="/">home</a>
{#if data.next}
<a href="/articles/{data.next.slug}">&gt;&gt;</a>
{/if}
</div>
</main>
<style>
main {
padding-left: 3em;
}
</style>

View File

@ -0,0 +1,40 @@
import type { PageLoad } from "./$types"
import type { Article } from "$lib/util/article";
import { error } from "@sveltejs/kit";
import { getAllArticles } from "$lib/util/firebase";
export const load: PageLoad = async ({ params }) => {
const articles: Article[] = await getAllArticles();
let article: Article | null = null;
for (let i = 0; i < articles.length; i++) {
if (articles[i].slug == params.slug) {
article = articles[i];
}
}
if (!article) {
throw error(404, "article not found.");
}
let index = 0;
for (let i = 0; i < articles.length; i++) {
if (articles[i].slug == article.slug) {
index = i;
}
}
let next = articles[index + 1];
let prev = articles[index - 1];
return {
articles: articles as Article[],
article: article as Article,
slug: params.slug,
next: next,
prev: prev,
}
}

View File

@ -0,0 +1,46 @@
<script lang="ts">
import type { PageData } from "./$types";
import { Marked } from "marked";
import { markedHighlight } from "marked-highlight";
import hljs from "highlight.js";
import 'highlight.js/styles/base16/one-light.css';
const marked = new Marked(
markedHighlight({
async: false,
langPrefix: "hljs language-",
highlight(code, lang) {
const language = hljs.getLanguage(lang) ? lang : "plaintext";
return hljs.highlight(code, { language }).value;
},
})
);
export let data: PageData;
let index = 0;
for (let i = 0; i < data.articles.length; i++) {
if (data.articles[i].slug == data.article.slug) {
index = i;
}
}
let render: string | Promise<string>;
$: render = marked.parse(data.article.data);
</script>
<main>
<p class="sub">{data.article.date}</p>
<h1>{data.article.title}</h1>
<p class="sub">{data.article.meta}</p>
<hr />
{@html render}
</main>
<style>
main {
max-width: 60em;
}
</style>

View File

@ -0,0 +1,40 @@
import type { PageLoad } from "./$types"
import type { Article } from "$lib/util/article";
import { error } from "@sveltejs/kit";
import { getAllArticles } from "$lib/util/firebase";
export const load: PageLoad = async ({ params }) => {
const articles: Article[] = await getAllArticles();
let article: Article | null = null;
for (let i = 0; i < articles.length; i++) {
if (articles[i].slug == params.slug) {
article = articles[i];
}
}
if (!article) {
throw error(404, "article not found.");
}
let index = 0;
for (let i = 0; i < articles.length; i++) {
if (articles[i].slug == article.slug) {
index = i;
}
}
let next = articles[index + 1];
let prev = articles[index - 1];
return {
articles: articles as Article[],
article: article as Article,
slug: params.slug,
next: next,
prev: prev,
}
}

BIN
static/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

18
svelte.config.js Normal file
View File

@ -0,0 +1,18 @@
import adapter from '@sveltejs/adapter-auto';
import { vitePreprocess } from '@sveltejs/kit/vite';
/** @type {import('@sveltejs/kit').Config} */
const config = {
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
// for more information about preprocessors
preprocess: vitePreprocess(),
kit: {
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
// If your environment is not supported or you settled on a specific environment, switch out the adapter.
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
adapter: adapter()
}
};
export default config;

17
tsconfig.json Normal file
View File

@ -0,0 +1,17 @@
{
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true
}
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
//
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
// from the referenced tsconfig.json - TypeScript does not merge them in
}

6
vite.config.ts Normal file
View File

@ -0,0 +1,6 @@
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [sveltekit()]
});

1597
yarn.lock Normal file

File diff suppressed because it is too large Load Diff