Documentation

Exploring the importance of documentation in web development, with a focus on managing website features using Sveltekit's stores feature.

I see documentation as an essential part of design. For design is an iterative process- every cycle being predicated upon an introspective analysis of the previous iteration. This analysis is not possible without some record of what was done, how it was done, why it was done so, in the previous cycle(s). In other words, documentation is how we may converse with the previous versions of our design. This is when I speak of documentation only as a personal dialogue. There is much more to it, when working in teams, across space and/or time. Here I record essential documentation for the three websites I currently manage and maintain.

Stores

Sveltekit’s stores feature is a wonderful utility, very simple to use but extensive in its functionality. For example, it can be used to store theme visibility- light and dark, across the website, which persists across user sessions.

All stores are recorded in ‘$lib/stores’. Stores that need to persist across website and are global in scope are kept in ‘globalstores.ts’

globalstores

import { writable, derived } from 'svelte/store'; //the derived import will help derive breakpoints from a single store of window width.
import { browser } from '$app/environment'; //brower import is needed to calculate window width
const storedThemeMode = browser ? JSON.parse(localStorage.getItem('themeMode') || 'false') : false; //local storage only maintains string, not number or boolean. this converts a boolean to string using json parse
export const themeMode = writable(storedThemeMode)
export function toggleThemeMode(){
	if (browser) {
		themeMode.update((mode) => {
			const newMode = !mode;
			localStorage.setItem('themeMode', JSON.stringify(newMode));
			return newMode;
		});
	}
}
//this function can be imported on any page/component, and toggled

The above method can be used also for offcanvas menu. But for modals, alerts etc. a different method is better. This is so because for modals, we want modularity such that the same component could be used to display different messages, under different conditions.

I store functions for global modals and alerts in the same globalstores file. One global alert use-case is for basis “error” or “success” alerts, There are a couple of steps for this. We need to set up the stores + functions, and the actual component for display.

alert store

import { writable } from 'svelte/store';
const initialAlert = {
	isShown: false,
	message: '', 
} //this stores the initial state for an alert, where it is not visible, and the message field is blank
export const alertStore = writable(initialAlert);
export function showAlert(message:string){
	alertStore.update((state) => ({...state,isShown: true, message}));
}
export function hideAlert(){
	alertStore.update((state) => ({
		...state,
		isShown: false,
		message: '',
	}))
}

In the above we set up the store, and functions to show and hide the alert. In showAlert, we update the state to be visible, and leave the message field open for overwriting. Now let’s set up the component, Alert.svelte:

<!--alert.svelte -->
<script lang="ts">
	import { onMount } from 'svelte'
	import { clickOutsideAction } from '$lib/utils/clickoutside' //this utility is documented separately in the global utilities section
	import { alertStore, hideAlert } from '$lib/stores/globalstores'
	import Close from '$lib/icons/Close.svelte' //basic icon for close button
	import Info from '$lib/icons/Info.svelte' //info icon
	let isShown:boolean, message:string
	const unsubscribe = alertStore.subscribe(value => {
		({ isShown, message } = value);
	});
	function handleCloseClick(){
		hideAlert();
	}
	$: if ( isShown === true ) {
		setTimeout(() => {
			isShown = false
		}, 5000)
	} //this function sets an auto timeout for the alert to close 5 seconds after it is displayed.
	onMount(() => {
		return unsubscribe;
	})
</script>
{#if isShown}
<div class="alert" use:clickOutsideAction on:clickOutside={handleCloseClick}>
	<div class="rta-row between">
		<div class="rta-row">
		<Info/>
		<p>{message}</p>
		</div>
		<Close/>
	</div>
</div>
{/if}

Styling in the above will have to be done separately. This component should be loaded at bottom of markup in the root layout file, following singleton principle.

To use it, imagine a general form submit function, where there could be error state, or success state:

function handleSubmit(){
	//function here
	if (error) {
		showAlert('error!')
	} else {
		showAlert('sucess!')
	}
}

This principle can be used for all kinds of modals, popups, toasts and others.Another use-case for example is a confirmation modal for delete buttons.

other global stores

window width

import { browser } from '$app/environment';
import { writable, derived } from 'svelte/store';
const initialWidth = browser ? window.innerWidth : 1024;
export const windowWidth = writable(initialWidth);
export const breakOne = derived(
	windowWidth,
	($windowWidth) => $windowWidth <= 1023 && $windowWidth > 768
);
export const breakZero = derived(windowWidth, ($windowWidth) => $windowWidth > 1023);
export const breakTwo = derived(windowWidth, ($windowWidth) => $windowWidth <= 768);

All global stores can be imported in root layout and attached to base app shell component:

<script lang="ts">
import { themeMode, breakZero, breakOne, breakTwo } from '$lib/stores/globalstores'
</script>
<div class="appshell"
	class:levelzero={$breakZero}
	class:levelone={$breakOne}
	class:leveltwo={$breakTwo}
	class:light={$themeMode}
	class:dark={!$themeMode}
	>
</div>

With the above, we can set global styling for any component in the global styles file. Examples:

.light
	background: #FFFFFF
	color: #313131
	
.dark
	background: #171717
	color: #FFFFFF
	
.levelzero
	padding-left: 32px
	padding-right: 32px
	
.leveltwo
	padding-left: 16px
	padding-right: 16px

And so on.