improve dropdowns
This commit is contained in:
parent
a8dd49f730
commit
fb6b0f0ed8
10 changed files with 148 additions and 114 deletions
|
|
@ -6,7 +6,7 @@
|
||||||
<div class="page-grid__toolbar">
|
<div class="page-grid__toolbar">
|
||||||
<div class="page-grid__toolbar-utilities">
|
<div class="page-grid__toolbar-utilities">
|
||||||
<a href="settings">
|
<a href="settings">
|
||||||
<button class="button--secondary" style="margin-left: 0.5rem;" type="button">
|
<button class="button--secondary" type="button">
|
||||||
Portal Settings
|
Portal Settings
|
||||||
</button>
|
</button>
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -15,6 +15,20 @@
|
||||||
initial-value="{{ filter | json }}"
|
initial-value="{{ filter | json }}"
|
||||||
></filter-menu>
|
></filter-menu>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="page-grid__toolbar-user">
|
||||||
|
<basic-dropdown alignment="right">
|
||||||
|
<span slot="button-contents" aria-label="Account menu" title="Account menu">
|
||||||
|
<i aria-hidden="true" class="ti ti-user"></i>
|
||||||
|
</span>
|
||||||
|
<menu class="basic-dropdown__menu" slot="popover">
|
||||||
|
<li>
|
||||||
|
<a href="{{ settings.root_path }}/auth/logout" role="button">
|
||||||
|
Log out
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</menu>
|
||||||
|
</basic-dropdown>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="page-grid__sidebar">
|
<div class="page-grid__sidebar">
|
||||||
<div style="padding: 1rem;">
|
<div style="padding: 1rem;">
|
||||||
|
|
|
||||||
|
|
@ -8,21 +8,26 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</h1>
|
</h1>
|
||||||
<basic-dropdown button-class="button--secondary button--small" button-aria-label="Workspace Menu">
|
<basic-dropdown button-class="button--secondary button--small" button-aria-label="Workspace Menu">
|
||||||
<span slot="button-contents">...</span>
|
<span slot="button-contents"><i class="ti ti-dots" aria-hidden="true"></i></span>
|
||||||
<menu slot="popover" class="basic-dropdown__menu">
|
<menu slot="popover" class="basic-dropdown__menu">
|
||||||
<li>
|
<li>
|
||||||
<button
|
<a
|
||||||
popovertarget="sql-conn-dialog"
|
href="{{ navigator.get_root_path() }}/w/{{ workspace.id.simple() }}/service-credentials"
|
||||||
popovertargetaction="toggle"
|
role="button"
|
||||||
type="button"
|
|
||||||
>
|
>
|
||||||
PostgreSQL connection
|
PostgreSQL Credentials
|
||||||
</button>
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
href="{{ navigator.get_root_path() }}/"
|
||||||
|
role="button"
|
||||||
|
>
|
||||||
|
All Workspaces
|
||||||
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</menu>
|
</menu>
|
||||||
</basic-dropdown>
|
</basic-dropdown>
|
||||||
<dialog class="dialog" id="sql-conn-dialog" popover="auto">
|
|
||||||
</dialog>
|
|
||||||
</div>
|
</div>
|
||||||
<section class="workspace-nav__section">
|
<section class="workspace-nav__section">
|
||||||
<div class="workspace-nav__heading">
|
<div class="workspace-nav__heading">
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@
|
||||||
&:popover-open {
|
&:popover-open {
|
||||||
@include globals.popover;
|
@include globals.popover;
|
||||||
|
|
||||||
left: anchor(left);
|
|
||||||
padding: 0;
|
padding: 0;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
position-anchor: --anchor-button;
|
position-anchor: --anchor-button;
|
||||||
|
|
@ -29,9 +28,11 @@
|
||||||
background: #0001;
|
background: #0001;
|
||||||
}
|
}
|
||||||
|
|
||||||
& > button {
|
& > button, & > [role="button"] {
|
||||||
@include globals.reset-button;
|
@include globals.reset-button;
|
||||||
|
@include globals.reset-anchor;
|
||||||
|
|
||||||
|
display: block;
|
||||||
padding: 8px 16px;
|
padding: 8px 16px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -126,6 +126,11 @@ $hover-lightness-scale-factor: -5%;
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@mixin reset-anchor {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
@mixin rounded-sm {
|
@mixin rounded-sm {
|
||||||
border-radius: $border-radius-rounded-sm;
|
border-radius: $border-radius-rounded-sm;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -94,8 +94,19 @@ button, input[type="submit"] {
|
||||||
&__toolbar-utilities {
|
&__toolbar-utilities {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
grid-area: utilities;
|
grid-area: utilities;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
|
padding: 0 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__toolbar-user {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
grid-area: user;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding: 0 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__sidebar {
|
&__sidebar {
|
||||||
|
|
@ -112,12 +123,6 @@ button, input[type="submit"] {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.toolbar__utilities {
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-start;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toolbar-item {
|
.toolbar-item {
|
||||||
flex: 0;
|
flex: 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -325,14 +325,6 @@ $table-border-color: #ccc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.toolbar-item {
|
|
||||||
padding: 0.5rem;
|
|
||||||
|
|
||||||
&__button {
|
|
||||||
@include globals.button-secondary;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.toolbar-popover {
|
.toolbar-popover {
|
||||||
&:popover-open {
|
&:popover-open {
|
||||||
@include globals.rounded;
|
@include globals.rounded;
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
props: {
|
props: {
|
||||||
button_aria_label: { attribute: "button-aria-label" },
|
button_aria_label: { attribute: "button-aria-label" },
|
||||||
button_class: { attribute: "button-class" },
|
button_class: { attribute: "button-class" },
|
||||||
|
alignment: { attribute: "alignment" },
|
||||||
},
|
},
|
||||||
tag: "basic-dropdown",
|
tag: "basic-dropdown",
|
||||||
}}
|
}}
|
||||||
|
|
@ -10,13 +11,42 @@
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
type Props = {
|
type Props = {
|
||||||
|
alignment?: string;
|
||||||
button_aria_label?: string;
|
button_aria_label?: string;
|
||||||
button_class?: string;
|
button_class?: string;
|
||||||
|
on_toggle?(ev: ToggleEvent): void;
|
||||||
};
|
};
|
||||||
|
|
||||||
let { button_aria_label, button_class = "button--secondary" }: Props =
|
let {
|
||||||
$props();
|
alignment,
|
||||||
|
button_aria_label,
|
||||||
|
button_class = "button--secondary",
|
||||||
|
on_toggle,
|
||||||
|
}: Props = $props();
|
||||||
let popover_element: HTMLElement | undefined = $state();
|
let popover_element: HTMLElement | undefined = $state();
|
||||||
|
// Hacky workaround because as of September 2025 implicit anchor association
|
||||||
|
// is still pretty broken, at least in Firefox.
|
||||||
|
let anchor_name = $state(`--anchor-${Math.floor(Math.random() * 1000000)}`);
|
||||||
|
|
||||||
|
let popover_left = $derived(
|
||||||
|
alignment?.toLocaleLowerCase("en-US") === "right"
|
||||||
|
? "unset"
|
||||||
|
: "anchor(left)",
|
||||||
|
);
|
||||||
|
let popover_right = $derived(
|
||||||
|
alignment?.toLocaleLowerCase("en-US") === "right"
|
||||||
|
? "anchor(right)"
|
||||||
|
: "unset",
|
||||||
|
);
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
if (on_toggle) {
|
||||||
|
popover_element?.addEventListener("toggle", on_toggle);
|
||||||
|
return () => {
|
||||||
|
popover_element?.removeEventListener("toggle", on_toggle);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
|
|
@ -24,8 +54,9 @@
|
||||||
class={["basic-dropdown__button", button_class]}
|
class={["basic-dropdown__button", button_class]}
|
||||||
id="dropdown-button"
|
id="dropdown-button"
|
||||||
onclick={() => {
|
onclick={() => {
|
||||||
popover_element.showPopover();
|
popover_element?.showPopover();
|
||||||
}}
|
}}
|
||||||
|
style:anchor-name={anchor_name}
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<slot name="button-contents"></slot>
|
<slot name="button-contents"></slot>
|
||||||
|
|
@ -34,6 +65,9 @@
|
||||||
aria-labelledby="dropdown-button"
|
aria-labelledby="dropdown-button"
|
||||||
bind:this={popover_element}
|
bind:this={popover_element}
|
||||||
class="basic-dropdown__popover"
|
class="basic-dropdown__popover"
|
||||||
|
style:left={popover_left}
|
||||||
|
style:position-anchor={anchor_name}
|
||||||
|
style:right={popover_right}
|
||||||
popover="auto"
|
popover="auto"
|
||||||
>
|
>
|
||||||
<slot name="popover"></slot>
|
<slot name="popover"></slot>
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ incompatible with the current presentation configuration.-->
|
||||||
tag: (typeof all_presentation_tags)[number],
|
tag: (typeof all_presentation_tags)[number],
|
||||||
): Presentation {
|
): Presentation {
|
||||||
if (tag === "Dropdown") {
|
if (tag === "Dropdown") {
|
||||||
return { t: "Dropdown", c: { allow_custom: true } };
|
return { t: "Dropdown", c: { allow_custom: true, options: [] } };
|
||||||
}
|
}
|
||||||
if (tag === "Text") {
|
if (tag === "Text") {
|
||||||
return { t: "Text", c: { input_mode: { t: "SingleLine", c: {} } } };
|
return { t: "Text", c: { input_mode: { t: "SingleLine", c: {} } } };
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import BasicDropdown from "./basic-dropdown.webc.svelte";
|
||||||
import { type FieldInfo } from "./field.svelte";
|
import { type FieldInfo } from "./field.svelte";
|
||||||
import FieldDetails from "./field-details.svelte";
|
import FieldDetails from "./field-details.svelte";
|
||||||
|
|
||||||
|
|
@ -12,35 +13,12 @@
|
||||||
const original_label_value = field.field.table_label;
|
const original_label_value = field.field.table_label;
|
||||||
|
|
||||||
let type_indicator_element = $state<HTMLButtonElement | undefined>();
|
let type_indicator_element = $state<HTMLButtonElement | undefined>();
|
||||||
let popover_element = $state<HTMLDivElement | undefined>();
|
|
||||||
let name_value = $state(field.field.name);
|
let name_value = $state(field.field.name);
|
||||||
let label_value = $state(field.field.table_label ?? "");
|
let label_value = $state(field.field.table_label ?? "");
|
||||||
// Hacky workaround because as of September 2025 implicit anchor association
|
|
||||||
// is still pretty broken, at least in Firefox.
|
|
||||||
let anchor_name = $state(`--anchor-${Math.floor(Math.random() * 1000000)}`);
|
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
field.field.table_label = label_value === "" ? undefined : label_value;
|
field.field.table_label = label_value === "" ? undefined : label_value;
|
||||||
});
|
});
|
||||||
|
|
||||||
$effect(() => {
|
|
||||||
popover_element?.addEventListener("toggle", handle_popover_toggle);
|
|
||||||
return () => {
|
|
||||||
popover_element?.removeEventListener("toggle", handle_popover_toggle);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
function handle_type_indicator_element_click() {
|
|
||||||
popover_element?.togglePopover();
|
|
||||||
}
|
|
||||||
|
|
||||||
function handle_popover_toggle(ev: ToggleEvent) {
|
|
||||||
if (ev.newState === "closed") {
|
|
||||||
type_indicator_element?.focus();
|
|
||||||
field.field.table_label = original_label_value;
|
|
||||||
label_value = original_label_value ?? "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
|
@ -53,12 +31,18 @@
|
||||||
{field.field.table_label ?? field.field.name}
|
{field.field.table_label ?? field.field.name}
|
||||||
</div>
|
</div>
|
||||||
<div class="field-header__menu-container">
|
<div class="field-header__menu-container">
|
||||||
<button
|
<BasicDropdown
|
||||||
bind:this={type_indicator_element}
|
alignment="right"
|
||||||
class="field-header__type-indicator"
|
button_class="field-header__type-indicator"
|
||||||
onclick={handle_type_indicator_element_click}
|
on_toggle={(ev) => {
|
||||||
style:anchor-name={anchor_name}
|
if (ev.newState === "closed") {
|
||||||
|
type_indicator_element?.focus();
|
||||||
|
field.field.table_label = original_label_value;
|
||||||
|
label_value = original_label_value ?? "";
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
|
<span slot="button-contents">
|
||||||
{#if field.field.presentation.t === "Dropdown"}
|
{#if field.field.presentation.t === "Dropdown"}
|
||||||
<i class="ti ti-pointer"></i>
|
<i class="ti ti-pointer"></i>
|
||||||
{:else if field.field.presentation.t === "Text"}
|
{:else if field.field.presentation.t === "Text"}
|
||||||
|
|
@ -68,13 +52,8 @@
|
||||||
{:else if field.field.presentation.t === "Uuid"}
|
{:else if field.field.presentation.t === "Uuid"}
|
||||||
<i class="ti ti-id"></i>
|
<i class="ti ti-id"></i>
|
||||||
{/if}
|
{/if}
|
||||||
</button>
|
</span>
|
||||||
<div
|
<div slot="popover" style:padding="16px">
|
||||||
bind:this={popover_element}
|
|
||||||
class="field-header__popover"
|
|
||||||
popover="auto"
|
|
||||||
style:position-anchor={anchor_name}
|
|
||||||
>
|
|
||||||
<form method="post" action="update-field">
|
<form method="post" action="update-field">
|
||||||
<FieldDetails
|
<FieldDetails
|
||||||
bind:name_value
|
bind:name_value
|
||||||
|
|
@ -86,5 +65,6 @@
|
||||||
<button class="button--primary" type="submit">Save</button>
|
<button class="button--primary" type="submit">Save</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
</BasicDropdown>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -32,10 +32,9 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="toolbar__utilities">
|
<div class="toolbar-item">
|
||||||
<div class="toolbar-item">
|
|
||||||
<button
|
<button
|
||||||
class="toolbar-item__button"
|
class="button--secondary"
|
||||||
onclick={handle_toolbar_button_click}
|
onclick={handle_toolbar_button_click}
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
|
|
@ -61,5 +60,4 @@
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue