Skip to content

Instantly share code, notes, and snippets.

View dimfeld's full-sized avatar

Daniel Imfeld dimfeld

View GitHub Profile
@dimfeld
dimfeld / Tooltip.svelte
Created November 19, 2020 00:13
Layercake Tooltip
<script>
import { getContext } from 'svelte';
export let evt = undefined;
export let offset = 35;
export let headerFn = undefined;
export let nestedAccessors = false;
export let dimensions;
let { custom } = getContext('LayerCake');
</script>

The "each Leaflet object as a Svelte component" thing wasn't the first I tried. My first attempt manages the state manually with a process similar to what I described here: https://imfeld.dev/writing/leaflet_with_svelte#syncing-local-state-to-the-map-through-reactive-statements. Essentially I had some code blocks that keep track of which objects I had created in Leaflet, and manually reconciled that with the declarative state from the reactive statements, adding or removing markers/lines/etc. I had a code block like this for each type of object that the app used.

// A Map containing all the markers that we have created.
let markers = new Map();
let allLocations = {...};

// Create the markers.
for (let [id, data] of Object.entries(allLocations)) {
  let marker = L.marker(data.location, { icon: data.icon });
@dimfeld
dimfeld / just.d.ts
Last active October 28, 2020 02:38
Type Definitions for some just-* packages
// See https://github.com/angus-c/just for the functions themselves.
declare module 'just-capitalize' {
function capitalize(value: string): string;
export = capitalize;
}
declare module 'just-clamp' {
function clamp(min: number, value: number, max: number): number;
export = clamp;
@dimfeld
dimfeld / dropdown.svelte
Last active September 30, 2020 02:31
Very simplified version of nested dropdown tracking.
<!-- This is missing a bunch of the code that interacts with tippy to position the element, but
hopefully it makes sense -->
<script>
// The popup tracker makes sure that "outside click" handling doesn't trigger when a click occurs
// in a child dropdown, and the child dropdown's popup is fixed.
function makePopupTracker(parent) {
let contained: HTMLElement[] = [];
return {
contains(target) {
return contained.some((e) => e.contains(target));
@dimfeld
dimfeld / Dropdown.svelte
Created July 6, 2020 23:55
Dropdown Code
<script>
import tippy from 'tippy.js';
import 'tippy.js/animations/shift-away.css';
import 'tippy.js/dist/tippy.css';
import { createEventDispatcher, tick } from 'svelte';
import { scale } from 'svelte/transition';
import { cubicIn, cubicOut } from 'svelte/easing';
import Icon from './Icon.svelte';
import Button from './Button.svelte';
import { faChevronDown } from '@fortawesome/pro-solid-svg-icons/faChevronDown';
@dimfeld
dimfeld / immerStore.ts
Last active June 25, 2020 15:54
Immer Store
import { writable, Readable } from 'svelte/store';
import { produce, enableAllPlugins } from 'immer';
enableAllPlugins();
export interface ImmerStore<T> {
update: (updateFn: (draft: T) => T | void) => T;
subscribe: Readable<T>['subscribe'];
}
@dimfeld
dimfeld / Babel Configs
Last active June 5, 2020 02:10
Babel Config Sample
const babelServerConfig = {
extensions: ['.js', '.mjs', '.html', '.ts'],
babelHelpers: 'bundled',
exclude: ['node_modules/@babel/**'],
presets: [
[
'@babel/preset-env',
{
modules: false,
targets: { node: 12 },
@dimfeld
dimfeld / mostVisibleElement.ts
Created May 28, 2020 19:25
Svelte IntersectionObserver action example
/**
* This is intended to be used with the svelte `use` syntax. It examines all
* child elements of the element that match `selector`, and calls the callback
* when the child element with the highest percentage overlap with the visible
* part of the container changes.
* <div use:mostVisibleElement={{ cb: setActive }}><section><section></div>
*/
export default function mostVisibleElement(
container: Element,
{ selector, cb }
export default function (
Component: typeof SvelteComponent,
events?: { [svelteEvent: string]: string }
) {
return class {
$element: Element[];
initialProps: { [key: string]: any };
component: SvelteComponent;
constructor($element) {
'ngInject';
<div class="px-2 flex flex-col">
<!-- Selected: adds bg-gray-200, removes bg-gray-100 -->
<!-- First row: Removes mt-1 -->
<div class="bg-gray-200 rounded-md px-2">
<span>Content</span>
<!-- Selected: adds bg-gray-100, removes bg-gray-200 -->
<span class="ml-auto bg-gray-100">5</span>
</div>