Add breadcrumb trail widget (#884)
This commit is contained in:
parent
f46f113b93
commit
52117d642c
|
|
@ -56,6 +56,12 @@ impl<F: Fn(&MessageDiscriminant) -> Vec<KeysGroup>> MessageHandler<LayoutMessage
|
||||||
|
|
||||||
#[remain::sorted]
|
#[remain::sorted]
|
||||||
match &mut widget_holder.widget {
|
match &mut widget_holder.widget {
|
||||||
|
Widget::BreadcrumbTrailButtons(breadcrumb_trail_buttons) => {
|
||||||
|
let update_value = value.as_u64().expect("BreadcrumbTrailButtons update was not of type: u64");
|
||||||
|
|
||||||
|
let callback_message = (breadcrumb_trail_buttons.on_update.callback)(&update_value);
|
||||||
|
responses.push_back(callback_message);
|
||||||
|
}
|
||||||
Widget::CheckboxInput(checkbox_input) => {
|
Widget::CheckboxInput(checkbox_input) => {
|
||||||
let update_value = value.as_bool().expect("CheckboxInput update was not of type: bool");
|
let update_value = value.as_bool().expect("CheckboxInput update was not of type: bool");
|
||||||
checkbox_input.checked = update_value;
|
checkbox_input.checked = update_value;
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ impl Layout {
|
||||||
for widget_holder in &mut widget_layout.iter_mut() {
|
for widget_holder in &mut widget_layout.iter_mut() {
|
||||||
// Handle all the widgets that have tooltips
|
// Handle all the widgets that have tooltips
|
||||||
let mut tooltip_shortcut = match &mut widget_holder.widget {
|
let mut tooltip_shortcut = match &mut widget_holder.widget {
|
||||||
|
Widget::BreadcrumbTrailButtons(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)),
|
||||||
Widget::CheckboxInput(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)),
|
Widget::CheckboxInput(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)),
|
||||||
Widget::ColorInput(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)),
|
Widget::ColorInput(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)),
|
||||||
Widget::DropdownInput(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)),
|
Widget::DropdownInput(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)),
|
||||||
|
|
@ -295,6 +296,7 @@ impl<T> Default for WidgetCallback<T> {
|
||||||
#[remain::sorted]
|
#[remain::sorted]
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum Widget {
|
pub enum Widget {
|
||||||
|
BreadcrumbTrailButtons(BreadcrumbTrailButtons),
|
||||||
CheckboxInput(CheckboxInput),
|
CheckboxInput(CheckboxInput),
|
||||||
ColorInput(ColorInput),
|
ColorInput(ColorInput),
|
||||||
DropdownInput(DropdownInput),
|
DropdownInput(DropdownInput),
|
||||||
|
|
|
||||||
|
|
@ -90,3 +90,22 @@ pub struct TextButton {
|
||||||
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
||||||
pub on_update: WidgetCallback<TextButton>,
|
pub on_update: WidgetCallback<TextButton>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Serialize, Deserialize, Derivative, Default)]
|
||||||
|
#[derivative(Debug, PartialEq)]
|
||||||
|
#[serde(rename_all(serialize = "camelCase", deserialize = "camelCase"))]
|
||||||
|
pub struct BreadcrumbTrailButtons {
|
||||||
|
pub labels: Vec<String>,
|
||||||
|
|
||||||
|
pub disabled: bool,
|
||||||
|
|
||||||
|
pub tooltip: String,
|
||||||
|
|
||||||
|
#[serde(skip)]
|
||||||
|
pub tooltip_shortcut: Option<ActionKeys>,
|
||||||
|
|
||||||
|
// Callbacks
|
||||||
|
#[serde(skip)]
|
||||||
|
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
||||||
|
pub on_update: WidgetCallback<u64>,
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@
|
||||||
<SwatchPairInput v-if="component.props.kind === 'SwatchPairInput'" v-bind="component.props" />
|
<SwatchPairInput v-if="component.props.kind === 'SwatchPairInput'" v-bind="component.props" />
|
||||||
<TextAreaInput v-if="component.props.kind === 'TextAreaInput'" v-bind="component.props" @commitText="(value: string) => updateLayout(component.widgetId, value)" />
|
<TextAreaInput v-if="component.props.kind === 'TextAreaInput'" v-bind="component.props" @commitText="(value: string) => updateLayout(component.widgetId, value)" />
|
||||||
<TextButton v-if="component.props.kind === 'TextButton'" v-bind="component.props" :action="() => updateLayout(component.widgetId, undefined)" :sharpRightCorners="nextIsSuffix" />
|
<TextButton v-if="component.props.kind === 'TextButton'" v-bind="component.props" :action="() => updateLayout(component.widgetId, undefined)" :sharpRightCorners="nextIsSuffix" />
|
||||||
|
<BreadcrumbTrailButtons v-if="component.props.kind === 'BreadcrumbTrailButtons'" v-bind="component.props" :action="(index: number) => updateLayout(component.widgetId, index)" />
|
||||||
<TextInput
|
<TextInput
|
||||||
v-if="component.props.kind === 'TextInput'"
|
v-if="component.props.kind === 'TextInput'"
|
||||||
v-bind="component.props"
|
v-bind="component.props"
|
||||||
|
|
@ -104,6 +105,7 @@ import type { Widget } from "@/wasm-communication/messages";
|
||||||
import { isWidgetColumn, isWidgetRow, type WidgetColumn, type WidgetRow } from "@/wasm-communication/messages";
|
import { isWidgetColumn, isWidgetRow, type WidgetColumn, type WidgetRow } from "@/wasm-communication/messages";
|
||||||
|
|
||||||
import PivotAssist from "@/components/widgets/assists/PivotAssist.vue";
|
import PivotAssist from "@/components/widgets/assists/PivotAssist.vue";
|
||||||
|
import BreadcrumbTrailButtons from "@/components/widgets/buttons/BreadcrumbTrailButtons.vue";
|
||||||
import IconButton from "@/components/widgets/buttons/IconButton.vue";
|
import IconButton from "@/components/widgets/buttons/IconButton.vue";
|
||||||
import ParameterExposeButton from "@/components/widgets/buttons/ParameterExposeButton.vue";
|
import ParameterExposeButton from "@/components/widgets/buttons/ParameterExposeButton.vue";
|
||||||
import PopoverButton from "@/components/widgets/buttons/PopoverButton.vue";
|
import PopoverButton from "@/components/widgets/buttons/PopoverButton.vue";
|
||||||
|
|
@ -168,6 +170,7 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
BreadcrumbTrailButtons,
|
||||||
CheckboxInput,
|
CheckboxInput,
|
||||||
ColorInput,
|
ColorInput,
|
||||||
DropdownInput,
|
DropdownInput,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
<template>
|
||||||
|
<LayoutRow class="breadcrumb-trail-buttons" :title="tooltip">
|
||||||
|
<TextButton
|
||||||
|
v-for="(label, index) in labels"
|
||||||
|
:key="index"
|
||||||
|
:label="label"
|
||||||
|
:emphasized="index === labels.length - 1"
|
||||||
|
:disabled="disabled"
|
||||||
|
:action="() => !disabled && index !== labels.length - 1 && action(index)"
|
||||||
|
/>
|
||||||
|
</LayoutRow>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.breadcrumb-trail-buttons {
|
||||||
|
.text-button {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&:not(:first-of-type) {
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: -4px;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 12px 0 12px 4px;
|
||||||
|
border-color: var(--button-background-color) var(--button-background-color) var(--button-background-color) transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:last-of-type) {
|
||||||
|
border-top-right-radius: 0;
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: -4px;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 12px 0 12px 4px;
|
||||||
|
border-color: transparent transparent transparent var(--button-background-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-of-type {
|
||||||
|
// Make this non-functional button not change color on hover
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, type PropType } from "vue";
|
||||||
|
|
||||||
|
import LayoutRow from "@/components/layout/LayoutRow.vue";
|
||||||
|
import TextButton from "@/components/widgets/buttons/TextButton.vue";
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
labels: { type: Array as PropType<string[]>, required: true },
|
||||||
|
disabled: { type: Boolean as PropType<boolean>, default: false },
|
||||||
|
tooltip: { type: String as PropType<string | undefined>, required: false },
|
||||||
|
|
||||||
|
// Callbacks
|
||||||
|
action: { type: Function as PropType<(index: number) => void>, required: true },
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
LayoutRow,
|
||||||
|
TextButton,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
@ -27,29 +27,31 @@
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
background: var(--color-5-dullgray);
|
background: var(--button-background-color);
|
||||||
color: var(--color-e-nearwhite);
|
color: var(--button-text-color);
|
||||||
|
--button-background-color: var(--color-5-dullgray);
|
||||||
|
--button-text-color: var(--color-e-nearwhite);
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: var(--color-6-lowergray);
|
--button-background-color: var(--color-6-lowergray);
|
||||||
color: var(--color-f-white);
|
--button-text-color: var(--color-f-white);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.disabled {
|
&.disabled {
|
||||||
background: var(--color-4-dimgray);
|
--button-background-color: var(--color-4-dimgray);
|
||||||
color: var(--color-8-uppergray);
|
--button-text-color: var(--color-8-uppergray);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.emphasized {
|
&.emphasized {
|
||||||
background: var(--color-e-nearwhite);
|
--button-background-color: var(--color-e-nearwhite);
|
||||||
color: var(--color-2-mildblack);
|
--button-text-color: var(--color-2-mildblack);
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: var(--color-f-white);
|
--button-background-color: var(--color-f-white);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.disabled {
|
&.disabled {
|
||||||
background: var(--color-8-uppergray);
|
--button-background-color: var(--color-8-uppergray);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -64,7 +66,6 @@
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, type PropType } from "vue";
|
import { defineComponent, type PropType } from "vue";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1058,6 +1058,15 @@ export type TextButtonWidget = {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export class BreadcrumbTrailButtons extends WidgetProps {
|
||||||
|
labels!: string;
|
||||||
|
|
||||||
|
disabled!: boolean;
|
||||||
|
|
||||||
|
@Transform(({ value }: { value: string }) => value || undefined)
|
||||||
|
tooltip!: string | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
export class TextInput extends WidgetProps {
|
export class TextInput extends WidgetProps {
|
||||||
value!: string;
|
value!: string;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue