Skip to content

Instantly share code, notes, and snippets.

View johannschopplich's full-sized avatar

Johann Schopplich johannschopplich

View GitHub Profile
@johannschopplich
johannschopplich / nginx.conf
Last active June 21, 2023 09:30
Custom nginx caching headers for Ploi.io for Kirby CMS
# assets and media
location ~* \.(?:css(\.map)?|js(\.map)?|jpe?g|png|gif|heic|webp|svgz?|mp3|m4a|aac|ogg|wav|mp4|mov|webm|mpe?g|avi|ogv|wmv|woff2?)$ {
try_files $uri $uri/ /index.php?$query_string;
add_header Cache-Control "public, max-age=31536000, immutable";
access_log off;
}
@johannschopplich
johannschopplich / better-scroller.client.ts
Created June 7, 2023 17:19
Nuxt plugin for `vue-router-better-scroller` with with Suspense route resolution
import { createRouterScroller } from 'vue-router-better-scroller'
interface ScrollPositionCoordinates {
behavior?: ScrollOptions['behavior']
left?: number
top?: number
}
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(
@johannschopplich
johannschopplich / password.ts
Last active May 3, 2023 21:40
Password strength meter calculation
const SPECIAL_CHAR_RE = /[^A-Za-z0-9]/g
const LOWERCASE_RE = /[a-z]/g
const UPPERCASE_RE = /[A-Z]/g
const NUMBER_RE = /[0-9]/g
const SCORE_MAP = ['risky', 'guessable', 'weak', 'safe', 'secure'] as const
export function getPasswordStrength(input: string | number) {
const score = typeof input === 'string' ? getPasswordScore(input) : input
return SCORE_MAP[score]
@johannschopplich
johannschopplich / index.ts
Created April 20, 2023 09:58
Rust-like result type in TypeScript
/**
* First, create a type helper that represents
* the Result that we'll get from our safe function
*/
type Result<T> =
| {
ok: true;
value: T;
}
| {
@johannschopplich
johannschopplich / AppIcon.vue
Created February 24, 2023 13:41
Auto-import icons from `assets` in Nuxt
<template>
<span
v-if="icon"
:class="[
'children-[svg]:h-full children-[svg]:w-full',
defaultStyles && 'inline-block h-[1em] w-[1em] align-middle',
]"
v-html="icon"
/>
</template>
@johannschopplich
johannschopplich / form-data-utils.ts
Created December 12, 2022 21:23
Serialize FormData to object with support for Blobs
import { FormData as _FormData } from 'formdata-polyfill/esm.min.js'
export async function formDataToObject(formData: FormData) {
const obj: Record<string, any> = {}
for (const [key, value] of formData.entries()) {
if (value instanceof Blob) {
obj[key] = {
__type: 'blob',
...(await serializeBlob(value)),
@johannschopplich
johannschopplich / fetch.ts
Last active October 20, 2022 06:50
Fetch data with typed response from Zog schema
// Create a schema for a post
const Post = z.object({
slug: z.string(),
content: z.string(),
});
// Create a schema for a post collection
const Posts = z.array(Post);
// Fetch a post by slug with the correct typed response
@johannschopplich
johannschopplich / storage.ts
Last active September 5, 2022 18:08
IndexedDB storage wrapper for VueUse
import { useStorageAsync } from "@vueuse/core";
import { get, set, del } from "idb-keyval";
export const STORAGE_KEY_PREFIX = "app.session.";
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function useIdbStorage<T = any>(key: string, initialValue: T) {
return useStorageAsync(`${STORAGE_KEY_PREFIX}${key}`, initialValue, {
async getItem(key: string) {
return (await get<string>(key)) ?? null;
@johannschopplich
johannschopplich / queries.css
Last active December 16, 2020 14:53
Media queries for differentiating mouse and touch-based screens
@media (hover: none) and (pointer: coarse) {
/* Touchscreens */
}
@media (hover: none) and (pointer: fine) {
/* Stylus */
}
@media (hover: hover) and (pointer: coarse) {
/* Controllers */
}
@media (hover: hover) and (pointer: fine) {
@johannschopplich
johannschopplich / index.js
Last active December 3, 2020 16:46
Kirby 3.5 accordion block by @distantnative
panel.plugin("distantnative/block-accordion", {
blocks: {
accordion: {
methods: {
addRow() {
this.content.rows.push({ summary: "", detail: "" });
this.update({ rows: this.content.rows });
},
removeRow(index) {
this.content.rows.splice(index, 1);