Skip to content

Commit

Permalink
🐞 [Website] Add some debugging UI (#78)
Browse files Browse the repository at this point in the history
  • Loading branch information
beefchimi authored Jan 27, 2024
1 parent 655a200 commit 272c601
Show file tree
Hide file tree
Showing 33 changed files with 916 additions and 443 deletions.
5 changes: 5 additions & 0 deletions .changeset/blue-jank-crime.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"earwurm": minor
---

Remove timed auto-suspend in favour of exposing `.suspend() / .resume()` methods on `Earuwrm`.
5 changes: 5 additions & 0 deletions .changeset/thick-oranges-exercise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"earwurm": minor
---

New `play` event available on `Earwurm` instance.
4 changes: 2 additions & 2 deletions app/website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"type": "module",
"engines": {
"node": ">=20.10.0",
"pnpm": ">=8.14.0"
"pnpm": ">=8.15.0"
},
"scripts": {
"clean": "rm -rf dist && rm -rf *.tsbuildinfo",
Expand All @@ -32,7 +32,7 @@
},
"devDependencies": {
"@earwurm/types": "workspace:*",
"@rushstack/eslint-patch": "^1.7.0",
"@rushstack/eslint-patch": "^1.7.2",
"@tsconfig/node20": "^20.1.2",
"@vitejs/plugin-vue": "^5.0.3",
"@vue/eslint-config-prettier": "^9.0.0",
Expand Down
9 changes: 7 additions & 2 deletions app/website/src/components/StackLabel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ import {classNames} from '@/helpers';
export interface StackLabelProps {
label: string;
populated?: boolean;
truncate?: boolean;
}
defineProps<StackLabelProps>();
</script>

<template>
<div :class="classNames('StackLabel', {populated})">
<p class="Text">{{ label }}</p>
<p :class="classNames('Text', {truncate})">{{ label }}</p>
</div>
</template>

Expand All @@ -21,6 +22,7 @@ defineProps<StackLabelProps>();
place-items: center;
place-content: center;
padding: 0.8rem;
flex: 0 0 auto;
min-width: var(--row-height);
height: var(--row-height);
color: var(--color-primary);
Expand All @@ -37,8 +39,11 @@ defineProps<StackLabelProps>();
}
.Text {
font-size: 1.4rem;
}
.truncate {
@apply truncate;
@apply flex-fix-width;
font-size: 1.4rem;
}
</style>
2 changes: 1 addition & 1 deletion app/website/src/hooks/useSupported.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {computed} from 'vue';
import {useMounted} from './useMounted';

// Adapted from Vue Use: https://vueuse.org/
export function useSupported(callback: () => unknown) {
export function useSupported(callback: () => boolean) {
const isMounted = useMounted();

return computed(() => {
Expand Down
211 changes: 211 additions & 0 deletions app/website/src/sections/ManagerDebug.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
<script setup lang="ts">
import {computed, type ComponentPublicInstance} from 'vue';
import {useDebugManager, useEarwurmStore} from '@/store';
import {IconAction, StackLabel} from '@/components';
const {manager} = useEarwurmStore();
const {
activeStacks,
currentState,
stateHistory,
errorHistory,
unlockHistory,
playHistory,
} = useDebugManager();
const running = computed(() => currentState.value === 'running');
function togglePlayback() {
if (running.value) {
manager.suspend();
} else {
manager.resume();
}
}
function scrollEnd(element: Element | ComponentPublicInstance | null) {
if (element instanceof Element) {
element.scroll({left: 12345, behavior: 'smooth'});
}
}
</script>

<template>
<section class="ManagerDebug collapsed-border-grid">
<div class="collapsed-border-row">
<StackLabel label="Stacks" populated />

<ul
:ref="(el) => scrollEnd(el)"
class="DebugList collapsed-border-row pattern-halftone"
>
<li v-for="stack in activeStacks" :key="stack" class="DebugItem">
<StackLabel :label="stack" />
</li>
</ul>
</div>

<div class="collapsed-border-row">
<StackLabel label="State" populated />

<ul
:ref="(el) => scrollEnd(el)"
class="DebugList collapsed-border-row pattern-halftone"
>
<li
v-for="(state, index) in stateHistory"
:key="`${state}-${index}`"
class="DebugItem"
>
<StackLabel :label="state" />
</li>
</ul>
</div>

<div class="collapsed-border-row">
<StackLabel label="Errors" populated />

<ul
:ref="(el) => scrollEnd(el)"
class="DebugList collapsed-border-row pattern-halftone"
>
<li
v-for="(error, index) in errorHistory"
:key="[...error, index].join(' | ')"
class="DebugItem"
>
<StackLabel :label="error.join(' | ')" />
</li>
</ul>
</div>

<div class="collapsed-border-row">
<StackLabel label="Unlocked" populated />

<ul
:ref="(el) => scrollEnd(el)"
class="DebugList collapsed-border-row pattern-halftone"
>
<li
v-for="(status, index) in unlockHistory"
:key="`Unlocked-${status}-${index}`"
class="DebugItem"
>
<StackLabel :label="status.toString()" />
</li>
</ul>
</div>

<div class="collapsed-border-row">
<StackLabel label="Playing" populated />

<ul
:ref="(el) => scrollEnd(el)"
class="DebugList collapsed-border-row pattern-halftone"
>
<li
v-for="(status, index) in playHistory"
:key="`Playing-${status}-${index}`"
class="DebugItem"
>
<StackLabel :label="status.toString()" />
</li>
</ul>
</div>

<div class="collapsed-border-row">
<IconAction
icon="unmuted"
icon-pressed="muted"
:label="running ? 'Suspend' : 'Resume'"
:a11y="`${running ? 'Suspend' : 'Resume'} the Earwurm`"
:pressed="running"
pressed-style
@action="togglePlayback"
/>
</div>
</section>
</template>

<style scoped>
.ManagerDebug {
@apply flex-fix-width;
position: relative;
/*
* Overlaid border required so that our DebugList
* can scroll behind the border lines.
*/
&::before {
@apply interaction-disable;
@apply position-cover;
z-index: 2;
content: '';
display: block;
box-shadow: inset 0 0 0 var(--app-border-width) var(--color-primary);
}
> .collapsed-border-row {
position: relative;
z-index: 1;
}
> .collapsed-border-row:last-child {
z-index: 3;
}
}
.DebugList {
counter-reset: debug-counter;
flex: 1 1 auto;
box-shadow: inset 0 0 0 var(--app-border-width) var(--color-primary);
overflow-x: scroll;
}
.DebugItem {
counter-increment: debug-counter;
position: relative;
&:first-child {
margin-left: auto;
}
&::before {
content: counter(debug-counter);
position: absolute;
top: 50%;
margin-top: calc(1.6em / 2 * -1);
left: calc(var(--app-border-width) * 2);
display: grid;
place-items: center;
place-content: center;
width: 1.6em;
height: 1.6em;
font-size: 1rem;
color: var(--color-primary);
box-shadow: inset 0 0 0 var(--app-border-width) var(--color-primary);
}
&::after {
@apply interaction-disable;
content: '';
display: block;
position: absolute;
inset: 0;
opacity: 0;
background-color: var(--color-primary);
transition: opacity var(--duration-slow) var(--easing-cubic);
}
& > div {
padding-left: 2rem;
}
}
@starting-style {
.DebugItem::after {
opacity: 1;
}
}
</style>
2 changes: 1 addition & 1 deletion app/website/src/sections/StackControls.vue
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const preparing = computed(() => hasStack.value && !loaded.value);
<template>
<article :id="`Stack-${id}`" class="StackControls collapsed-border-grid">
<div class="collapsed-border-row">
<StackLabel :label="id" :populated="hasStack && loaded" />
<StackLabel :label="id" :populated="hasStack && loaded" truncate />

<div v-if="hasStack" class="PopulatedBar collapsed-border-row">
<div class="VolumeStackWrapper collapsed-border-row">
Expand Down
11 changes: 10 additions & 1 deletion app/website/src/sections/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,13 @@ import ManagerControls from './ManagerControls.vue';
import SoundControls from './SoundControls.vue';
import StackControls from './StackControls.vue';

export {AppHeader, AppFooter, ManagerControls, SoundControls, StackControls};
import ManagerDebug from './ManagerDebug.vue';

export {
AppHeader,
AppFooter,
ManagerControls,
SoundControls,
StackControls,
ManagerDebug,
};
3 changes: 3 additions & 0 deletions app/website/src/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ export {useThemeStore} from './useThemeStore';

export {useStack} from './useStack';
export {useSound} from './useSound';

export {useDebugStore} from './useDebugStore';
export {useDebugManager} from './useDebugManager';
59 changes: 59 additions & 0 deletions app/website/src/store/useDebugManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import {computed, ref} from 'vue';
import {type ManagerEventMap} from 'earwurm';

import {useEarwurmStore} from './useEarwurmStore';

type ErrorResponse = Parameters<ManagerEventMap['error']>[0];

const MAX_HISTORY_LENGTH = 44;

// TODO: Consider enabling a auto-suspension option.
// import {clamp, timeMeasurement} from '@earwurm/utilities';
// const safeAutoSuspend = clamp(0, autoSuspend, timeMeasurement.msPerMin);

const {manager, activeStacks} = useEarwurmStore();

const stateHistoryRef = ref([manager.state]);
const errorHistoryRef = ref<ErrorResponse[]>([]);
const unlockHistoryRef = ref([manager.unlocked]);
const playHistoryRef = ref([manager.playing]);

function updateUnlockHistory() {
const currentLength = unlockHistoryRef.value.length;

if (manager.unlocked === unlockHistoryRef.value[currentLength - 1]) {
return;
}

const newHistory = [...unlockHistoryRef.value, manager.unlocked];
unlockHistoryRef.value = newHistory.slice(MAX_HISTORY_LENGTH * -1);
}

manager.on('state', (current) => {
const newStateHistory = [...stateHistoryRef.value, current];
stateHistoryRef.value = newStateHistory.slice(MAX_HISTORY_LENGTH * -1);

updateUnlockHistory();
});

manager.on('play', (active) => {
const newPlayHistory = [...playHistoryRef.value, active];
playHistoryRef.value = newPlayHistory.slice(MAX_HISTORY_LENGTH * -1);
});

manager.on('error', (response) => {
errorHistoryRef.value = [...errorHistoryRef.value, response];
});

export function useDebugManager() {
return {
activeStacks,
currentState: computed(
() => stateHistoryRef.value[stateHistoryRef.value.length - 1],
),
stateHistory: computed(() => stateHistoryRef.value),
errorHistory: computed(() => errorHistoryRef.value),
unlockHistory: computed(() => unlockHistoryRef.value),
playHistory: computed(() => playHistoryRef.value),
};
}
11 changes: 11 additions & 0 deletions app/website/src/store/useDebugStore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {computed} from 'vue';

function getSearchParams() {
const rawParams = window.location.search || '';
return new URLSearchParams(rawParams);
}

export function useDebugStore() {
const params = getSearchParams();
return computed(() => params.has('mode', 'debug'));
}
Loading

0 comments on commit 272c601

Please sign in to comment.