Skip to content

Commit

Permalink
feat(ui): introduce collapsible section - WF-47
Browse files Browse the repository at this point in the history
closes #506
  • Loading branch information
madeindjs committed Oct 19, 2024
1 parent d82f245 commit 61b52ef
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 56 deletions.
31 changes: 11 additions & 20 deletions src/ui/src/components/core/layout/CoreColumn.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,17 @@
<div v-if="!isCollapsed" class="titleContainer">
<h3 v-if="fields.title.value">{{ fields.title.value }}</h3>
</div>
<div
<button
v-if="isCollapsible"
role="button"
class="collapser"
@click="toggleCollapsed"
>
<IconGen
class="collapserArrow"
icon-key="collapseArrow"
></IconGen>
</div>
</button>
</div>
<div v-if="isCollapsed && fields.title.value" class="collapsedTitle">
<div class="transformed">
Expand All @@ -31,6 +32,7 @@
</div>
<BaseContainer
class="container"
:aria-expanded="isCollapsible ? 'true' : null"
:content-h-align="fields.contentHAlign.value"
:content-v-align="fields.contentVAlign.value"
:content-padding="fields.contentPadding.value"
Expand All @@ -49,6 +51,10 @@ import {
cssClasses,
separatorColor,
} from "@/renderer/sharedStyleFields";
import {
startCollapsed,
isCollapsible as isCollapsibleField,
} from "@/renderer/sharedFields";
const description =
"A layout component that organises its child components in columns. Must be inside a Column Container component.";
Expand Down Expand Up @@ -83,25 +89,9 @@ export default {
},
category: FieldCategory.Style,
},
isCollapsible: {
name: "Collapsible",
default: "no",
type: FieldType.Text,
options: {
yes: "Yes",
no: "No",
},
category: FieldCategory.Style,
},
isCollapsible: isCollapsibleField,
startCollapsed: {
name: "Start collapsed",
type: FieldType.Text,
category: FieldCategory.Style,
default: "no",
options: {
yes: "Yes",
no: "No",
},
...startCollapsed,
desc: "Only applied when the column is collapsible.",
},
separatorColor,
Expand Down Expand Up @@ -230,6 +220,7 @@ watch(
}
.CoreColumn > .header > .collapser {
border: none;
order: 2;
flex: 0 0 32px;
border-radius: 16px;
Expand Down
59 changes: 55 additions & 4 deletions src/ui/src/components/core/layout/CoreSection.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,26 @@
<template>
<section class="CoreSection">
<h3 v-if="fields.title.value">{{ fields.title.value }}</h3>
<section
class="CoreSection"
:class="{ 'CoreSection--collapsible': isCollapsible }"
>
<div
v-if="fields.title.value || isCollapsible"
class="CoreSection__title"
:class="{ 'CoreSection__title--collapsible': isCollapsible }"
>
<h3>{{ fields.title.value }}</h3>
<button
v-if="isCollapsible"
role="button"
class="CoreSection__title__collapser"
>
<i class="material-symbols-outlined"> keep </i>
</button>
</div>
<BaseContainer
:content-h-align="fields.contentHAlign.value"
:content-padding="fields.contentPadding.value"
:aria-expanded="isCollapsible ? 'true' : null"
>
<slot></slot>
</BaseContainer>
Expand All @@ -26,6 +43,10 @@ import {
contentHAlign,
contentPadding,
} from "@/renderer/sharedStyleFields";
import {
isCollapsible as isCollapsibleField,
startCollapsed,
} from "@/renderer/sharedFields";
const description =
"A container component that divides the layout into sections, with an optional title.";
Expand All @@ -43,6 +64,8 @@ export default {
desc: "Leave blank to hide.",
type: FieldType.Text,
},
isCollapsible: isCollapsibleField,
startCollapsed,
accentColor,
primaryTextColor,
secondaryTextColor,
Expand All @@ -64,11 +87,19 @@ export default {
};
</script>
<script setup lang="ts">
import { inject } from "vue";
import { computed, inject, ref } from "vue";
import injectionKeys from "@/injectionKeys";
import BaseContainer from "../base/BaseContainer.vue";
const fields = inject(injectionKeys.evaluatedFields);
const isCollapsible = computed(() => fields.isCollapsible.value === "yes");
const isCollapsed = ref<boolean>(fields.startCollapsed.value);
const ariaExpanded = computed(() => {
if (!isCollapsible.value) return null;
return String(isCollapsed.value);
});
</script>

<style scoped>
Expand All @@ -80,7 +111,27 @@ const fields = inject(injectionKeys.evaluatedFields);
background-color: var(--containerBackgroundColor);
}
h3 {
.CoreSection__title {
margin: 16px 16px 0 16px;
display: grid;
grid-template-columns: 1fr auto;
}
.CoreSection__title__collapser {
border: none;
order: 2;
flex: 0 0 32px;
border-radius: 16px;
padding: 4px;
background: var(--separatorColor);
display: flex;
align-items: center;
justify-content: center;
stroke: var(--primaryTextColor);
}
.CoreSection__title__collapser {
transition: all 0.5s ease-in-out;
transform: rotate(0deg);
}
</style>
24 changes: 24 additions & 0 deletions src/ui/src/renderer/sharedFields.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import {
FieldType,
FieldCategory,
WriterComponentDefinitionField,
} from "@/writerTypes";

const yesNoOptions = { yes: "Yes", no: "No" };

export const isCollapsible: WriterComponentDefinitionField = {
name: "Collapsible",
default: "no",
type: FieldType.Text,
options: yesNoOptions,
category: FieldCategory.Style,
};

export const startCollapsed: WriterComponentDefinitionField = {
name: "Start collapsed",
type: FieldType.Text,
category: FieldCategory.Style,
default: "no",
options: yesNoOptions,
desc: "Only applied when the component is collapsible.",
};
36 changes: 20 additions & 16 deletions src/ui/src/renderer/sharedStyleFields.ts
Original file line number Diff line number Diff line change
@@ -1,106 +1,110 @@
import { FieldCategory, FieldType } from "@/writerTypes";
import {
FieldCategory,
FieldType,
WriterComponentDefinitionField,
} from "@/writerTypes";

export const accentColor = {
export const accentColor: WriterComponentDefinitionField = {
name: "Accent",
type: FieldType.Color,
category: FieldCategory.Style,
applyStyleVariable: true,
};

export const primaryTextColor = {
export const primaryTextColor: WriterComponentDefinitionField = {
name: "Primary text",
type: FieldType.Color,
category: FieldCategory.Style,
applyStyleVariable: true,
};

export const secondaryTextColor = {
export const secondaryTextColor: WriterComponentDefinitionField = {
name: "Secondary text",
type: FieldType.Color,
category: FieldCategory.Style,
applyStyleVariable: true,
};

export const emptinessColor = {
export const emptinessColor: WriterComponentDefinitionField = {
name: "Emptiness",
desc: "Page background color",
type: FieldType.Color,
category: FieldCategory.Style,
applyStyleVariable: true,
};

export const containerBackgroundColor = {
export const containerBackgroundColor: WriterComponentDefinitionField = {
name: "Container background",
type: FieldType.Color,
category: FieldCategory.Style,
applyStyleVariable: true,
};

export const containerShadow = {
export const containerShadow: WriterComponentDefinitionField = {
name: "Container shadow",
type: FieldType.Shadow,
category: FieldCategory.Style,
applyStyleVariable: true,
};

export const separatorColor = {
export const separatorColor: WriterComponentDefinitionField = {
name: "Separator",
type: FieldType.Color,
category: FieldCategory.Style,
applyStyleVariable: true,
};

export const buttonColor = {
export const buttonColor: WriterComponentDefinitionField = {
name: "Button",
type: FieldType.Color,
category: FieldCategory.Style,
applyStyleVariable: true,
};

export const buttonTextColor = {
export const buttonTextColor: WriterComponentDefinitionField = {
name: "Button text",
type: FieldType.Color,
category: FieldCategory.Style,
applyStyleVariable: true,
};

export const buttonShadow = {
export const buttonShadow: WriterComponentDefinitionField = {
name: "Button shadow",
type: FieldType.Shadow,
category: FieldCategory.Style,
applyStyleVariable: true,
};

export const cssClasses = {
export const cssClasses: WriterComponentDefinitionField = {
name: "Custom CSS classes",
type: FieldType.Text,
category: FieldCategory.Style,
desc: "CSS classes, separated by spaces. You can define classes in custom stylesheets.",
};

export const contentWidth = {
export const contentWidth: WriterComponentDefinitionField = {
name: "Content width",
type: FieldType.Width,
default: "100%",
category: FieldCategory.Style,
desc: "Configure content width using CSS units, e.g. 100px, 50%, 10vw, etc.",
};

export const contentHAlign = {
export const contentHAlign: WriterComponentDefinitionField = {
name: "Content alignment (H)",
type: FieldType.HAlign,
default: "unset",
category: FieldCategory.Style,
};

export const contentVAlign = {
export const contentVAlign: WriterComponentDefinitionField = {
name: "Content alignment (V)",
type: FieldType.VAlign,
default: "unset",
category: FieldCategory.Style,
};

export const contentPadding = {
export const contentPadding: WriterComponentDefinitionField = {
name: "Padding",
type: FieldType.Padding,
default: "0",
Expand Down
39 changes: 23 additions & 16 deletions src/ui/src/writerTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,28 @@ export type InstancePath = InstancePathItem[];
* Defines component structure and behaviour. Included in Component templates.
*/

export type WriterComponentDefinitionField = {
/** Display name */
name: string;
/** Initial value */
init?: string;
/** Description */
desc?: string;
/** Value used if the field is empty, e.g. "(No text)" */
default?: string;
/** Which control (text, textarea, etc) to use if not the default for the type */
control?: FieldControl;
options?:
| Record<string, string>
| ((wf?: Core, componentId?: ComponentId) => Record<string, string>); // List of values to be provided as autocomplete options
/** Data type for the field */
type: FieldType;
/** Category (Layout, Content, etc) */
category?: FieldCategory;
/** Use the value of this field as a CSS variable */
applyStyleVariable?: boolean;
};

export type WriterComponentDefinition = {
name: string; // Display name for the component
description: string; // Short description
Expand All @@ -67,22 +89,7 @@ export type WriterComponentDefinition = {
slot?: string; // In which slot component should render whgen "*" is used it will render in all slots
fields?: Record<
string, // Id for the field
{
name: string; // Display name
init?: string; // Initial value
desc?: string; // Description
default?: string; // Value used if the field is empty, e.g. "(No text)"
control?: FieldControl; // Which control (text, textarea, etc) to use if not the default for the type
options?:
| Record<string, string>
| ((
wf?: Core,
componentId?: ComponentId,
) => Record<string, string>); // List of values to be provided as autocomplete options
type: FieldType; // Data type for the field
category?: FieldCategory; // Category (Layout, Content, etc)
applyStyleVariable?: boolean; // Use the value of this field as a CSS variable
}
WriterComponentDefinitionField
>;
events?: Record<
string, // Event type
Expand Down

0 comments on commit 61b52ef

Please sign in to comment.