Skip to content

Commit

Permalink
✨ Type Changes
Browse files Browse the repository at this point in the history
  • Loading branch information
nwrenger committed Jan 31, 2024
1 parent fedb971 commit 879e2e9
Show file tree
Hide file tree
Showing 7 changed files with 226 additions and 237 deletions.
2 changes: 1 addition & 1 deletion src/lib/stores.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ import type { Views } from './types';
import { localStorageStore } from '@skeletonlabs/skeleton';

export let gridController = writable<GridController>();
export let views = localStorageStore<Views>('views', { views: [], current: 0 });
export let views = localStorageStore<Views>('views', { pages: [], current: 0 });
81 changes: 50 additions & 31 deletions src/lib/types.ts
Original file line number Diff line number Diff line change
@@ -1,56 +1,75 @@
export type Option<T> = T | null;

export enum GuiType {
Header = 'header',
BodyText = 'body-text',
Buttons = 'buttons',
Alert = 'alert'
Header = 0,
BodyText,
Buttons,
Alert
}

export enum GuiAlign {
Left = 'left',
Right = 'right',
Top = 'top',
Bottom = 'bottom',
Center = 'center'
export enum Align {
Left = 0,
Right,
Top,
Bottom,
Center
}

export enum EventType {
View = 'view',
Function = 'function'
export function alignToString(align: Align | string): string {
switch (align) {
case Align.Left:
return 'Left';
case Align.Right:
return 'Right';
case Align.Top:
return 'Top';
case Align.Bottom:
return 'Bottom';
case Align.Center:
return 'Center';
default:
throw new Error('Invalid Align value');
}
}

export type Option<T> = T | null;
export type IdArray<T> = { rows: T[]; id: string }[];
export type EventData<T extends EventType> = T extends EventType.View ? number : string;
export type Event =
| {
View: number;
}
| {
Function: string;
};

export interface Views {
views: IdArray<Item>;
pages: Page[];
current: number;
}

export interface Item {
export interface Page {
id: string;
page: View[];
}

export interface View {
id: string;
type: GuiType;
name: string;
type: GuiType;
moveable: boolean;
x: number;
y: number;
w: number;
h: number;
data: { textValue: Option<string | AlignedText>; actions: Option<Option<Actions>[]> };
data: Data;
}

export interface AlignedText {
horizontal: GuiAlign;
vertical: GuiAlign;
text: string;
export interface Data {
text_value: Option<String>;
horizontal: Option<Align>;
vertical: Option<Align>;
actions: Option<Option<Action>[]>;
}

export interface Actions {
textValue: string | undefined;
export interface Action {
text_value: String;
event: Event;
}

export interface Event {
type: EventType;
data: EventData<EventType> | undefined;
}
6 changes: 3 additions & 3 deletions src/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Item } from './types';
import type { View } from './types';

export function keys<T extends object>(obj: T) {
return Object.keys(obj) as Array<keyof T>;
Expand Down Expand Up @@ -39,7 +39,7 @@ export function areObjectsEqual(obj1: any, obj2: any): boolean {
return true;
}

export function isItemColliding(item: Item, otherItem: Item) {
export function isItemColliding(item: View, otherItem: View) {
return (
item.id !== otherItem.id &&
item.x <= otherItem.x + otherItem.w - 1 &&
Expand All @@ -49,7 +49,7 @@ export function isItemColliding(item: Item, otherItem: Item) {
);
}

export function areItemsColliding(item: Item, items: Item[]) {
export function areItemsColliding(item: View, items: View[]) {
for (const item2 of items) {
if (isItemColliding(item, item2)) return true;
}
Expand Down
4 changes: 2 additions & 2 deletions src/routes/builder/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
<meta name="description" content="Website's specific UI-Builder" />
</svelte:head>

<h2 class="h2 m-2">{$views.views.length != 0 ? `View ${$views.current + 1}` : 'No Views!'}</h2>
<h2 class="h2 m-2">{$views.pages.length != 0 ? `View ${$views.current + 1}` : 'No Views!'}</h2>
<div
class="card p-4 m-2 {$views.views.length != 0
class="card p-4 m-2 {$views.pages.length != 0
? 'variant-ghost-primary'
: 'variant-ghost'} overflow-hidden"
>
Expand Down
90 changes: 38 additions & 52 deletions src/routes/builder/EditModal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// Stores
import { getModalStore, type ModalSettings } from '@skeletonlabs/skeleton';
import { views } from '$lib/stores';
import { EventType, GuiAlign, GuiType, type Item } from '$lib/types';
import { Align, alignToString, GuiType, type View, type Action } from '$lib/types';
// Props
/** Exposes parent props to this component. */
Expand All @@ -14,12 +14,15 @@
const cBase = 'card p-4 w-modal shadow-xl space-y-4';
const cHeader = 'text-2xl font-bold';
let item: Item = $modalStore[0]?.meta.toChange;
let view: View = $modalStore[0]?.meta.toChange;
// apply reactivity on close
modalStore.subscribe((modals: ModalSettings[]) => {
if (!modals.length) $views = $views;
});
// select shenanigans
let ev = new Array(view.data.actions?.length).fill('view');
</script>

<!-- @component This is an Edit Modal for the Items. -->
Expand All @@ -28,101 +31,86 @@
<div class={cBase}>
<header class={cHeader}>Edit</header>

{#if item.data.textValue != null}
{#if typeof item.data.textValue == 'string'}
{#if view.data.text_value != null}
{#if typeof view.data.text_value == 'string'}
<label class="label">
<span>Edit Text</span>
<input
class="input"
type="text"
placeholder="Text Value and/or Variable using {'{'}var_name{'}'}"
bind:value={item.data.textValue}
maxlength="70"
/>
</label>
{:else if typeof item.data.textValue == 'object'}
<label class="label">
<span>Edit Text</span>
<input
class="input"
type="text"
placeholder="Text Value and/or Variable using {'{'}var_name{'}'}"
bind:value={item.data.textValue.text}
bind:value={view.data.text_value}
maxlength="70"
/>
</label>
{/if}
{#if view.data.horizontal != null && view.data.vertical != null}
<label class="label">
<span>Horizontal Align</span>
<select class="select" bind:value={item.data.textValue.horizontal}>
{#each Object.values(GuiAlign).filter((value) => typeof value === 'string') as align}
<option value={align}>{align.charAt(0).toUpperCase() + align.slice(1)}</option>
<select class="select" bind:value={view.data.horizontal}>
{#each Object.values(Align).filter((value) => typeof value === 'number') as align}
<option value={align}>{alignToString(align)}</option>
{/each}
</select>
</label>
<label class="label">
<span>Vertical Align</span>
<select class="select" bind:value={item.data.textValue.vertical}>
{#each Object.values(GuiAlign).filter((value) => typeof value === 'string') as align}
<option value={align}>{align.charAt(0).toUpperCase() + align.slice(1)}</option>
<select class="select" bind:value={view.data.vertical}>
{#each Object.values(Align).filter((value) => typeof value === 'number') as align}
<option value={align}>{alignToString(align)}</option>
{/each}
</select>
</label>
{:else}
<aside class="alert variant-ghost">
<div class="alert-message">
<h3 class="h3">Critical Error!</h3>
<p>
Wrong provided Type found! Please re-add the item. If the issue persists, feel free to
open an issue on GitHub!
</p>
</div>
</aside>
{/if}
{/if}

{#if item.data.actions != null}
{#each item.data.actions as action, i}
{#if view.data.actions != null}
{#each view.data.actions as action, i}
{#if action != null}
<label class="label">
<span>Action {i + 1}</span>
<input
class="input"
type="text"
disabled={item.type == GuiType.Alert}
disabled={view.type == GuiType.Alert}
placeholder="Text Value and/or Variable using {'{'}var_name{'}'}"
bind:value={action.textValue}
bind:value={action.text_value}
maxlength="40"
/>
<div class="input-group input-group-divider grid-cols-[1fr_auto]">
{#if action?.event.type === EventType.View}
{#if 'View' in action.event}
<input
type="number"
placeholder="Number of View (leave blank for Closing the App)"
bind:value={action.event.data}
bind:value={action.event.View}
maxlength="10"
/>
{:else}
<input
type="text"
placeholder="Function Name with () for Params"
bind:value={action.event.data}
bind:value={action.event.Function}
maxlength="40"
/>
{/if}
<select
bind:value={action.event.type}
bind:value={ev[i]}
on:change={() => {
if (action) action.event.data = undefined;
if (ev[i] === 'view') {
if (action) action.event = { View: 1 };
} else if (ev[i] === 'function') {
if (action) action.event = { Function: '' };
}
}}
>
<option value={EventType.View}>View</option>
<option value={EventType.Function}>Function</option>
<option value={'view'}>View</option>
<option value={'function'}>Function</option>
</select>
</div>
<button
class="btn variant-filled"
on:click={() => (action = null)}
disabled={item.type == GuiType.Alert}
disabled={view.type == GuiType.Alert}
><i class="fa-solid fa-minus mr-2"></i>Remove Action</button
>
</label>
Expand All @@ -131,14 +119,12 @@
<div>Action {i + 1}</div>
<button
class="btn variant-filled"
on:click={() =>
(action = {
textValue: '(Edit Text)',
event: {
type: EventType.View,
data: ''
}
})}><i class="fa-solid fa-plus mr-2"></i> Add Action</button
on:click={() => {
action = {
text_value: '',
event: { View: 1 }
};
}}><i class="fa-solid fa-plus mr-2"></i> Add Action</button
>
</label>
{/if}
Expand Down
Loading

0 comments on commit 879e2e9

Please sign in to comment.