Skip to content

Instantly share code, notes, and snippets.

@d4rekanguok
Last active January 31, 2022 14:14
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save d4rekanguok/c210b0ba1fbace015fd5db932fccf5cc to your computer and use it in GitHub Desktop.
Save d4rekanguok/c210b0ba1fbace015fd5db932fccf5cc to your computer and use it in GitHub Desktop.
A svelte component you can drop into your svelte kit app to view a list of all your components (poor man's Storybook)
// updated to add props editting, rendering component inside iframe & allowing resizing viewer
<script context="module">
const modules = import.meta.globEager('/src/sections/*.svelte')
const componentNames = Object.keys(modules)
</script>
<script lang="ts">
import cx from 'clsx'
import { browser } from '$app/env'
import { afterUpdate, onMount } from 'svelte'
let current = componentNames[0]
let Component
let props = {}
let viewerEl: HTMLIFrameElement
let viewerWidth = null
let allowCustomWidth = false
let viewerWidthPreset = [360, 480, 720, 800, 1200]
$: loadComponent(current)
const loadComponent = async (current) => {
try {
// const res = await modules[current]()
Component = modules[current].default
props = modules[current].defaultProps || {}
} catch (err) {
console.error(err)
}
}
const setCurrentByName = (name) => () => {
current = name
}
const onPropsChange = (e) => {
const value = e.target.propContent.value
props = JSON.parse(value)
}
const setViewerWidth = (w: number) => () => {
viewerWidth = w
}
const setAllowCustomWidth = () => {
allowCustomWidth = !allowCustomWidth
}
let renderedComponent
onMount(() => {
const styles = Array.from(document.head.querySelectorAll('style')).map((node) =>
node.cloneNode(true)
)
viewerEl.contentWindow.document.head.append(...styles)
})
afterUpdate(() => {
if (!Component) return
renderedComponent?.$destroy?.()
renderedComponent = new Component({
target: viewerEl.contentWindow.document.body,
props,
})
})
</script>
<div data-grid="container" class="h-screen">
<div data-grid="a" class="p-4">
<h1 class="mb-4 text-xl">Components</h1>
<ul>
{#each componentNames as name (name)}
<li
class={cx({
'opacity-40': name === current,
})}
>
<button on:click={setCurrentByName(name)}>
{name.split('/src/sections/')[1] || ''}
</button>
</li>
{/each}
</ul>
</div>
<div data-grid="b" class="p-4">
<h1 class="mb-4 text-xl">Props</h1>
{#if browser && props}
<form on:submit|preventDefault={onPropsChange}>
<textarea
name="propContent"
rows={10}
class="w-full p-2 border border-blue-200 font-mono"
>{JSON.stringify(props, null, 2)}</textarea
>
<button type="submit" class="bg-blue-500 text-white px-4 py-2">Update</button>
</form>
{:else}
No defaultProps found
{/if}
</div>
<div
data-grid="c"
class={cx(
'mx-8 mt-8 self-stretch flex-1 flex flex-col items-center px-2 overflow-hidden',
'bg-gray-100 border-1 border-gray-300 rounded-tl-4xl rounded-tr-4xl'
)}
>
<div class="h-12 top-0 sticky bg-gray-100 z-50 w-full flex items-center justify-center">
<menu class="inline-flex">
<button class="px-2 py-1" on:click={setViewerWidth(null)}>Full</button>
{#each viewerWidthPreset as w (w)}
<button
on:click={setViewerWidth(w)}
class={cx('px-2 py-1', {
'bg-blue-500 text-white': w === viewerWidth,
})}>{w}</button
>
{/each}
<button class="px-2 py-1" on:click={setAllowCustomWidth}>Custom</button>
{#if allowCustomWidth}
<input type="number" bind:value={viewerWidth} />
{/if}
</menu>
</div>
<iframe
title="viewer"
class="border-1 border-gray-300 h-full rounded-tl rounded-tr"
bind:this={viewerEl}
style={`width: ${viewerWidth ? viewerWidth + 'px' : `100%`};`}
/>
</div>
</div>
<style>
div[data-grid='container'] {
display: grid;
grid-template-columns: 1fr 4fr;
grid-template-rows: 1fr 1fr;
grid-template-areas:
'a c'
'b c';
}
div[data-grid='a'] {
grid-area: a;
}
div[data-grid='b'] {
grid-area: b;
}
div[data-grid='c'] {
grid-area: c;
}
</style>
@leejoramo-d51
Copy link

Very nice!

@d4rekanguok
Copy link
Author

Hi! If you're interested in this gist, I've fleshed it out a bit more & turned it into a npm package: https://github.com/d4rekanguok/talenote Give it a try & let me know what you think!

@leejoramo-d51
Copy link

Thanks for the update on your package

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment