mirror of
https://github.com/ae-utbm/sith.git
synced 2025-06-17 16:45:22 +00:00
Replace tab macro with new tab web component
This commit is contained in:
parent
2dd4fd5c71
commit
c904e41ea3
@ -7,7 +7,6 @@ export class Tab extends HTMLElement {
|
||||
static observedAttributes = ["title", "active"];
|
||||
private description = "";
|
||||
private inner = "";
|
||||
private initialized = false;
|
||||
private active = false;
|
||||
|
||||
attributeChangedCallback(name: string, _oldValue?: string, newValue?: string) {
|
||||
@ -22,33 +21,30 @@ export class Tab extends HTMLElement {
|
||||
if (name === "title") {
|
||||
this.description = newValue;
|
||||
}
|
||||
|
||||
this.render();
|
||||
this.dispatchEvent(new CustomEvent("ui-tab-updated", { bubbles: true }));
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.initialized) {
|
||||
return;
|
||||
}
|
||||
const active = this.active ? "active" : "";
|
||||
const tabContent = this.getContentHtml();
|
||||
const content = html`
|
||||
getButtonTemplate() {
|
||||
return html`
|
||||
<button
|
||||
role="tab"
|
||||
?aria-selected=${active}
|
||||
class="tab-header clickable ${active}"
|
||||
?aria-selected=${this.active}
|
||||
class="tab-header clickable ${this.active ? "active" : ""}"
|
||||
@click="${() => this.setActive(true)}"
|
||||
>
|
||||
${this.description}
|
||||
</button>
|
||||
`;
|
||||
}
|
||||
getContentTemplate() {
|
||||
return html`
|
||||
<section
|
||||
class="tab-content"
|
||||
?hidden=${!active}
|
||||
class="tab-section"
|
||||
?hidden=${!this.active}
|
||||
>
|
||||
${unsafeHTML(tabContent)}
|
||||
${unsafeHTML(this.getContentHtml())}
|
||||
</section>
|
||||
`;
|
||||
render(content, this);
|
||||
}
|
||||
|
||||
setActive(value: boolean) {
|
||||
@ -62,12 +58,10 @@ export class Tab extends HTMLElement {
|
||||
connectedCallback() {
|
||||
this.inner = this.innerHTML;
|
||||
this.innerHTML = "";
|
||||
this.initialized = true;
|
||||
this.render();
|
||||
}
|
||||
|
||||
getContentHtml() {
|
||||
const content = this.getElementsByClassName("tab-content")[0];
|
||||
const content = this.getElementsByClassName("tab-section")[0];
|
||||
if (content !== undefined) {
|
||||
return content.innerHTML;
|
||||
}
|
||||
@ -75,19 +69,23 @@ export class Tab extends HTMLElement {
|
||||
}
|
||||
|
||||
setContentHtml(value: string) {
|
||||
const content = this.getElementsByClassName("tab-content")[0];
|
||||
const content = this.getElementsByClassName("tab-section")[0];
|
||||
if (content !== undefined) {
|
||||
content.innerHTML = value;
|
||||
}
|
||||
this.inner = value;
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
|
||||
@registerComponent("ui-tab-group")
|
||||
export class TabGroup extends HTMLElement {
|
||||
private node: HTMLDivElement;
|
||||
|
||||
connectedCallback() {
|
||||
this.classList.add("tabs", "shadow");
|
||||
this.node = document.createElement("div");
|
||||
this.node.classList.add("tabs", "shadow");
|
||||
this.appendChild(this.node);
|
||||
|
||||
this.addEventListener("ui-tab-activated", (event: CustomEvent) => {
|
||||
const target = event.detail as Tab;
|
||||
for (const tab of this.getElementsByTagName("ui-tab") as HTMLCollectionOf<Tab>) {
|
||||
@ -96,5 +94,27 @@ export class TabGroup extends HTMLElement {
|
||||
}
|
||||
}
|
||||
});
|
||||
this.addEventListener("ui-tab-updated", () => {
|
||||
this.render();
|
||||
});
|
||||
|
||||
this.render();
|
||||
}
|
||||
|
||||
render() {
|
||||
const tabs = Array.prototype.slice.call(
|
||||
this.getElementsByTagName("ui-tab"),
|
||||
) as Tab[];
|
||||
render(
|
||||
html`
|
||||
<div class="tab-headers">
|
||||
${tabs.map((tab) => tab.getButtonTemplate())}
|
||||
</div>
|
||||
<div class="tab-content">
|
||||
${tabs.map((tab) => tab.getContentTemplate())}
|
||||
</div>
|
||||
`,
|
||||
this.node,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
53
core/static/core/components/tabs.scss
Normal file
53
core/static/core/components/tabs.scss
Normal file
@ -0,0 +1,53 @@
|
||||
@import "core/static/core/colors";
|
||||
|
||||
ui-tab-group {
|
||||
*[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tabs {
|
||||
border-radius: 5px;
|
||||
|
||||
.tab-headers {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
background-color: $primary-neutral-light-color;
|
||||
padding: 3px 12px 12px;
|
||||
column-gap: 20px;
|
||||
border-top-left-radius: 5px;
|
||||
border-top-right-radius: 5px;
|
||||
|
||||
.tab-header {
|
||||
border: none;
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
font-size: 120%;
|
||||
background-color: unset;
|
||||
position: relative;
|
||||
|
||||
&:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
border-bottom: 4px solid darken($primary-neutral-light-color, 10%);
|
||||
border-radius: 2px;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
&:hover:after {
|
||||
border-bottom-color: darken($primary-neutral-light-color, 20%);
|
||||
}
|
||||
|
||||
&.active:after {
|
||||
border-bottom-color: $primary-dark-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
section {
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
}
|
@ -352,52 +352,6 @@ body {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tabs {
|
||||
border-radius: 5px;
|
||||
|
||||
.tab-headers {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
background-color: $primary-neutral-light-color;
|
||||
padding: 3px 12px 12px;
|
||||
column-gap: 20px;
|
||||
border-top-left-radius: 5px;
|
||||
border-top-right-radius: 5px;
|
||||
|
||||
.tab-header {
|
||||
border: none;
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
font-size: 120%;
|
||||
background-color: unset;
|
||||
position: relative;
|
||||
|
||||
&:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
border-bottom: 4px solid darken($primary-neutral-light-color, 10%);
|
||||
border-radius: 2px;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
&:hover:after {
|
||||
border-bottom-color: darken($primary-neutral-light-color, 20%);
|
||||
}
|
||||
|
||||
&.active:after {
|
||||
border-bottom-color: $primary-dark-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
section {
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.tool_bar {
|
||||
overflow: auto;
|
||||
padding: 4px;
|
||||
|
@ -245,65 +245,3 @@
|
||||
<button type="button" onclick="checkbox_{{form_id}}(true);">{% trans %}Select All{% endtrans %}</button>
|
||||
<button type="button" onclick="checkbox_{{form_id}}(false);">{% trans %}Unselect All{% endtrans %}</button>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro tabs(tab_list, attrs = "") %}
|
||||
{# Tab component
|
||||
|
||||
Parameters:
|
||||
tab_list: list[tuple[str, str]] The list of tabs to display.
|
||||
Each element of the list is a tuple which first element
|
||||
is the title of the tab and the second element its content
|
||||
attrs: str Additional attributes to put on the enclosing div
|
||||
|
||||
Example:
|
||||
A basic usage would be as follow :
|
||||
|
||||
{{ tabs([("title 1", "content 1"), ("title 2", "content 2")]) }}
|
||||
|
||||
If you want to display more complex logic, you can define macros
|
||||
and use those macros in parameters :
|
||||
|
||||
{{ tabs([("title", my_macro())]) }}
|
||||
|
||||
It's also possible to get and set the currently selected tab using Alpine.
|
||||
Here, the title of the currently selected tab will be displayed.
|
||||
Moreover, on page load, the tab will be opened on "tab 2".
|
||||
|
||||
<div x-data="{current_tab: 'tab 2'}">
|
||||
<p x-text="current_tab"></p>
|
||||
{{ tabs([("tab 1", "Hello"), ("tab 2", "World")], "x-model=current_tab") }}
|
||||
</div>
|
||||
|
||||
If you want to have translated tab titles, you can enclose the macro call
|
||||
in a with block :
|
||||
|
||||
{% with title=_("title"), content=_("Content") %}
|
||||
{{ tabs([(tab1, content)]) }}
|
||||
{% endwith %}
|
||||
#}
|
||||
<div
|
||||
class="tabs shadow"
|
||||
x-data="{selected: '{{ tab_list[0][0] }}'}"
|
||||
x-modelable="selected"
|
||||
{{ attrs }}
|
||||
>
|
||||
<div class="tab-headers">
|
||||
{% for title, _ in tab_list %}
|
||||
<button
|
||||
class="tab-header clickable"
|
||||
:class="{active: selected === '{{ title }}'}"
|
||||
@click="selected = '{{ title }}'"
|
||||
>
|
||||
{{ title }}
|
||||
</button>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="tab-content">
|
||||
{% for title, content in tab_list %}
|
||||
<section x-show="selected === '{{ title }}'">
|
||||
{{ content }}
|
||||
</section>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
@ -12,6 +12,7 @@
|
||||
So we give them here.
|
||||
If the aforementioned bug is resolved, you can remove this. #}
|
||||
{% block additional_js %}
|
||||
<script type="module" src="{{ static('bundled/core/components/tabs-index.ts') }}"></script>
|
||||
<script type="module" src="{{ static("bundled/core/components/ajax-select-index.ts") }}"></script>
|
||||
<script
|
||||
type="module"
|
||||
@ -19,6 +20,7 @@
|
||||
></script>
|
||||
{% endblock %}
|
||||
{% block additional_css %}
|
||||
<link rel="stylesheet" href="{{ static("core/components/tabs.scss") }}">
|
||||
<link rel="stylesheet" href="{{ static("bundled/core/components/ajax-select-index.css") }}">
|
||||
<link rel="stylesheet" href="{{ static("core/components/ajax-select.scss") }}">
|
||||
<link rel="stylesheet" href="{{ static("subscription/css/subscription.scss") }}">
|
||||
@ -34,12 +36,12 @@
|
||||
|
||||
{% block content %}
|
||||
<h3>{% trans %}New subscription{% endtrans %}</h3>
|
||||
<div id="subscription-form">
|
||||
{% with title1=_("Existing member"), title2=_("New member") %}
|
||||
{{ tabs([
|
||||
(title1, form_fragment(existing_user_form, existing_user_post_url)),
|
||||
(title2, form_fragment(new_user_form, new_user_post_url)),
|
||||
]) }}
|
||||
{% endwith %}
|
||||
</div>
|
||||
<ui-tab-group id="subscription-form">
|
||||
<ui-tab title="{% trans %}Existing member{% endtrans %}" active>
|
||||
{{ form_fragment(existing_user_form, existing_user_post_url) }}
|
||||
</ui-tab>
|
||||
<ui-tab title="{% trans %}New member{% endtrans %}">
|
||||
{{ form_fragment(new_user_form, new_user_post_url) }}
|
||||
</ui-tab>
|
||||
</ui-tab-group>
|
||||
{% endblock %}
|
||||
|
Loading…
x
Reference in New Issue
Block a user