improve UI of split modals
This commit is contained in:
Vendored
+30
-4
@@ -864,19 +864,34 @@ body[showing-chat] #chat-page-wrapper {
|
|||||||
scroll-snap-type: x mandatory;
|
scroll-snap-type: x mandatory;
|
||||||
}
|
}
|
||||||
.split-modal > div {
|
.split-modal > div {
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-width: calc(100% - 4rem);
|
min-width: calc(100% - 4rem);
|
||||||
flex: 0;
|
flex: 0;
|
||||||
scroll-snap-align: center;
|
scroll-snap-align: center;
|
||||||
}
|
}
|
||||||
|
.split-modal > div,
|
||||||
|
.split-modal > div > .scroll-area {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
justify-content: safe center;
|
||||||
|
}
|
||||||
|
.split-modal[navigation] > div > .scroll-area {
|
||||||
|
justify-content: start;
|
||||||
|
}
|
||||||
|
.split-modal[navigation] > div {
|
||||||
|
min-width: 100%;
|
||||||
|
}
|
||||||
.split-modal .scroll-area {
|
.split-modal .scroll-area {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
padding: var(--content-padding);
|
padding: var(--content-padding);
|
||||||
}
|
}
|
||||||
|
.split-modal[navigation] > div:nth-child(2) > .flex-row > button {
|
||||||
|
transform: translateX(calc(-1 * var(--content-padding)));
|
||||||
|
}
|
||||||
.split-modal .detail-button-wrapper {
|
.split-modal .detail-button-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: end;
|
justify-content: end;
|
||||||
@@ -896,11 +911,14 @@ body[showing-chat] #chat-page-wrapper {
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: unset;
|
min-width: unset;
|
||||||
}
|
}
|
||||||
.split-modal:not([primitive]) > div:first-child {
|
.split-modal[navigation] > div {
|
||||||
|
min-width: unset;
|
||||||
|
}
|
||||||
|
.split-modal[navigation] > div:first-child {
|
||||||
flex: 0;
|
flex: 0;
|
||||||
min-width: 20rem;
|
min-width: 20rem;
|
||||||
}
|
}
|
||||||
.split-modal[primitive] > div {
|
.split-modal:not([navigation]) > div {
|
||||||
width: 50%;
|
width: 50%;
|
||||||
min-width: 50%;
|
min-width: 50%;
|
||||||
}
|
}
|
||||||
@@ -908,3 +926,11 @@ body[showing-chat] #chat-page-wrapper {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.split-modal[navigation]:not([page-open]) > div:nth-child(2) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.split-modal[navigation][page-open] > div:first-child {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Vendored
+41
-14
@@ -5025,7 +5025,8 @@
|
|||||||
fileVersionLabel: "Version",
|
fileVersionLabel: "Version",
|
||||||
searchLabel: "Search",
|
searchLabel: "Search",
|
||||||
waitingLabel: "Waiting...",
|
waitingLabel: "Waiting...",
|
||||||
restoreConnection: "Restore connection"
|
restoreConnection: "Restore connection",
|
||||||
|
noPageSelected: "No page selected"
|
||||||
},
|
},
|
||||||
regional: {
|
regional: {
|
||||||
weekdays: {
|
weekdays: {
|
||||||
@@ -5237,7 +5238,8 @@
|
|||||||
fileVersionLabel: "Version",
|
fileVersionLabel: "Version",
|
||||||
searchLabel: "Suche",
|
searchLabel: "Suche",
|
||||||
waitingLabel: "Warten...",
|
waitingLabel: "Warten...",
|
||||||
restoreConnection: "Verbindung wiederherstellen"
|
restoreConnection: "Verbindung wiederherstellen",
|
||||||
|
noPageSelected: "Keine Seite ausgew\xE4hlt"
|
||||||
},
|
},
|
||||||
regional: {
|
regional: {
|
||||||
weekdays: {
|
weekdays: {
|
||||||
@@ -5430,7 +5432,8 @@
|
|||||||
fileVersionLabel: "Versi\xF3n",
|
fileVersionLabel: "Versi\xF3n",
|
||||||
searchLabel: "Buscar",
|
searchLabel: "Buscar",
|
||||||
waitingLabel: "Esperando...",
|
waitingLabel: "Esperando...",
|
||||||
restoreConnection: "Conectar de nuevo"
|
restoreConnection: "Conectar de nuevo",
|
||||||
|
noPageSelected: "No p\xE1gina seleccionada"
|
||||||
},
|
},
|
||||||
regional: {
|
regional: {
|
||||||
weekdays: {
|
weekdays: {
|
||||||
@@ -6350,9 +6353,7 @@
|
|||||||
this.username = new State("");
|
this.username = new State("");
|
||||||
this.usernameInput = new State("");
|
this.usernameInput = new State("");
|
||||||
this.isShowingSettingsModal = new State(false);
|
this.isShowingSettingsModal = new State(false);
|
||||||
this.selectedModalPage = new State(
|
this.selectedModalPage = new State(void 0);
|
||||||
0 /* Appearance */
|
|
||||||
);
|
|
||||||
this.requiresReload = new State(false);
|
this.requiresReload = new State(false);
|
||||||
this.firstDayOfWeek = new State("0");
|
this.firstDayOfWeek = new State("0");
|
||||||
this.language = new State(
|
this.language = new State(
|
||||||
@@ -6428,21 +6429,40 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
// src/View/Components/splitModal.tsx
|
// src/View/Components/splitModal.tsx
|
||||||
function SplitModal(leftView, rightView, extendedStyle = false, navigationState) {
|
function SplitModal(coreViewModel2, leftView, rightView, extendedStyle = false, navigationState) {
|
||||||
|
function closePage() {
|
||||||
|
navigationState.value = void 0;
|
||||||
|
}
|
||||||
|
const hasPageOpen = new State(false);
|
||||||
|
navigationState?.subscribe(
|
||||||
|
(newValue) => hasPageOpen.value = newValue != void 0
|
||||||
|
);
|
||||||
const view = /* @__PURE__ */ createElement(
|
const view = /* @__PURE__ */ createElement(
|
||||||
"div",
|
"div",
|
||||||
{
|
{
|
||||||
class: "split-modal",
|
class: "split-modal",
|
||||||
"toggle:extended": extendedStyle,
|
"toggle:extended": extendedStyle,
|
||||||
"toggle:primitive": navigationState == void 0
|
"toggle:navigation": navigationState != void 0,
|
||||||
|
"toggle:page-open": hasPageOpen
|
||||||
},
|
},
|
||||||
/* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("div", { class: "scroll-area", "children:set": leftView })),
|
/* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("div", { class: "scroll-area", "children:set": leftView })),
|
||||||
/* @__PURE__ */ createElement("div", { class: "scroll-area", "children:set": rightView })
|
/* @__PURE__ */ createElement("div", { class: "scroll-area slide-up" }, /* @__PURE__ */ createElement(
|
||||||
|
"div",
|
||||||
|
{
|
||||||
|
class: "flex-row width-100 mobile-only",
|
||||||
|
"toggle:hidden": navigationState == void 0
|
||||||
|
},
|
||||||
|
/* @__PURE__ */ createElement(
|
||||||
|
"button",
|
||||||
|
{
|
||||||
|
class: "ghost square",
|
||||||
|
"aria-label": coreViewModel2.translations.general.backButton,
|
||||||
|
"on:click": closePage
|
||||||
|
},
|
||||||
|
/* @__PURE__ */ createElement("span", { class: "icon" }, "arrow_back")
|
||||||
|
)
|
||||||
|
), /* @__PURE__ */ createElement("div", { "children:set": rightView }))
|
||||||
);
|
);
|
||||||
function scrollToDetails() {
|
|
||||||
view.scrollLeft = view.scrollWidth;
|
|
||||||
}
|
|
||||||
navigationState?.subscribe(scrollToDetails);
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6527,6 +6547,7 @@
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
return /* @__PURE__ */ createElement("div", { class: "modal", "toggle:open": storageViewModel2.isShowingStorageModal }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("main", { class: "padding-0" }, SplitModal(
|
return /* @__PURE__ */ createElement("div", { class: "modal", "toggle:open": storageViewModel2.isShowingStorageModal }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("main", { class: "padding-0" }, SplitModal(
|
||||||
|
coreViewModel2,
|
||||||
new State(DirectoryItemList(storageViewModel2)),
|
new State(DirectoryItemList(storageViewModel2)),
|
||||||
detailView,
|
detailView,
|
||||||
true
|
true
|
||||||
@@ -6819,6 +6840,11 @@
|
|||||||
[settingsViewModel2.selectedModalPage],
|
[settingsViewModel2.selectedModalPage],
|
||||||
() => {
|
() => {
|
||||||
switch (settingsViewModel2.selectedModalPage.value) {
|
switch (settingsViewModel2.selectedModalPage.value) {
|
||||||
|
case void 0: {
|
||||||
|
return PlaceholderView(
|
||||||
|
coreViewModel2.translations.general.noPageSelected
|
||||||
|
);
|
||||||
|
}
|
||||||
case 0 /* Appearance */:
|
case 0 /* Appearance */:
|
||||||
return SettingsAppearancePane(
|
return SettingsAppearancePane(
|
||||||
coreViewModel2,
|
coreViewModel2,
|
||||||
@@ -6841,6 +6867,7 @@
|
|||||||
"toggle:open": settingsViewModel2.isShowingSettingsModal
|
"toggle:open": settingsViewModel2.isShowingSettingsModal
|
||||||
},
|
},
|
||||||
/* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("main", { class: "padding-0" }, SplitModal(
|
/* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("main", { class: "padding-0" }, SplitModal(
|
||||||
|
coreViewModel2,
|
||||||
new State(
|
new State(
|
||||||
SettingsLeftPane(coreViewModel2, settingsViewModel2)
|
SettingsLeftPane(coreViewModel2, settingsViewModel2)
|
||||||
),
|
),
|
||||||
@@ -6851,7 +6878,7 @@
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
function SettingsLeftPane(coreViewModel2, settingsViewModel2) {
|
function SettingsLeftPane(coreViewModel2, settingsViewModel2) {
|
||||||
return /* @__PURE__ */ createElement("div", { class: "flex-column gap" }, SettingsPaneButton(
|
return /* @__PURE__ */ createElement("div", { class: "flex-column gap slide-up" }, /* @__PURE__ */ createElement("h2", null, coreViewModel2.translations.homePage.settingsButton), SettingsPaneButton(
|
||||||
settingsViewModel2,
|
settingsViewModel2,
|
||||||
0 /* Appearance */,
|
0 /* Appearance */,
|
||||||
coreViewModel2.translations.settings.pages.appearance
|
coreViewModel2.translations.settings.pages.appearance
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1128,7 +1128,7 @@ main {
|
|||||||
@media (min-width: 640px) {
|
@media (min-width: 640px) {
|
||||||
/* basic */
|
/* basic */
|
||||||
.mobile-only {
|
.mobile-only {
|
||||||
display: none;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* border, outline, etc */
|
/* border, outline, etc */
|
||||||
|
|||||||
@@ -15,9 +15,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.split-modal > div {
|
.split-modal > div {
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-width: calc(100% - 4rem);
|
min-width: calc(100% - 4rem);
|
||||||
flex: 0;
|
flex: 0;
|
||||||
@@ -25,6 +22,25 @@
|
|||||||
scroll-snap-align: center;
|
scroll-snap-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.split-modal > div,
|
||||||
|
.split-modal > div > .scroll-area {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
align-items: stretch;
|
||||||
|
justify-content: safe center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.split-modal[navigation] > div > .scroll-area{
|
||||||
|
justify-content: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.split-modal[navigation] > div {
|
||||||
|
min-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.split-modal .scroll-area {
|
.split-modal .scroll-area {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -33,6 +49,10 @@
|
|||||||
padding: var(--content-padding);
|
padding: var(--content-padding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.split-modal[navigation] > div:nth-child(2) > .flex-row > button {
|
||||||
|
transform: translateX(calc(-1 * var(--content-padding)));
|
||||||
|
}
|
||||||
|
|
||||||
.split-modal .detail-button-wrapper {
|
.split-modal .detail-button-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: end;
|
justify-content: end;
|
||||||
@@ -58,12 +78,16 @@
|
|||||||
min-width: unset;
|
min-width: unset;
|
||||||
}
|
}
|
||||||
|
|
||||||
.split-modal:not([primitive]) > div:first-child {
|
.split-modal[navigation] > div {
|
||||||
|
min-width: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.split-modal[navigation] > div:first-child {
|
||||||
flex: 0;
|
flex: 0;
|
||||||
min-width: 20rem;
|
min-width: 20rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.split-modal[primitive] > div {
|
.split-modal:not([navigation]) > div {
|
||||||
width: 50%;
|
width: 50%;
|
||||||
min-width: 50%;
|
min-width: 50%;
|
||||||
}
|
}
|
||||||
@@ -72,3 +96,13 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.split-modal[navigation]:not([page-open]) > div:nth-child(2) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.split-modal[navigation][page-open] > div:first-child {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,31 +1,53 @@
|
|||||||
|
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
|
||||||
import "./splitModal.css";
|
import "./splitModal.css";
|
||||||
|
|
||||||
import * as React from "bloatless-react";
|
import * as React from "bloatless-react";
|
||||||
|
|
||||||
export function SplitModal(
|
export function SplitModal<T>(
|
||||||
|
coreViewModel: CoreViewModel,
|
||||||
leftView: React.State<Element>,
|
leftView: React.State<Element>,
|
||||||
rightView: React.State<Element>,
|
rightView: React.State<Element>,
|
||||||
extendedStyle: boolean = false,
|
extendedStyle: boolean = false,
|
||||||
navigationState?: React.State<any>,
|
navigationState?: React.State<T | undefined>,
|
||||||
) {
|
) {
|
||||||
|
function closePage() {
|
||||||
|
navigationState.value = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasPageOpen = new React.State<boolean>(false);
|
||||||
|
navigationState?.subscribe(
|
||||||
|
(newValue) => (hasPageOpen.value = newValue != undefined),
|
||||||
|
);
|
||||||
|
|
||||||
const view = (
|
const view = (
|
||||||
<div
|
<div
|
||||||
class="split-modal"
|
class="split-modal"
|
||||||
toggle:extended={extendedStyle}
|
toggle:extended={extendedStyle}
|
||||||
toggle:primitive={navigationState == undefined}
|
toggle:navigation={navigationState != undefined}
|
||||||
|
toggle:page-open={hasPageOpen}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<div class="scroll-area" children:set={leftView}></div>
|
<div class="scroll-area" children:set={leftView}></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="scroll-area" children:set={rightView}></div>
|
<div class="scroll-area slide-up">
|
||||||
|
<div
|
||||||
|
class="flex-row width-100 mobile-only"
|
||||||
|
toggle:hidden={navigationState == undefined}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="ghost square"
|
||||||
|
aria-label={
|
||||||
|
coreViewModel.translations.general.backButton
|
||||||
|
}
|
||||||
|
on:click={closePage}
|
||||||
|
>
|
||||||
|
<span class="icon">arrow_back</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div children:set={rightView}></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
function scrollToDetails() {
|
|
||||||
view.scrollLeft = view.scrollWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
navigationState?.subscribe(scrollToDetails);
|
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import CoreViewModel from "../../ViewModel/Global/coreViewModel";
|
|||||||
import { Languages, ThemeSettings } from "../../Model/Global/settingsModel";
|
import { Languages, ThemeSettings } from "../../Model/Global/settingsModel";
|
||||||
import { OptionButtonList } from "../Components/optionButtonList";
|
import { OptionButtonList } from "../Components/optionButtonList";
|
||||||
import { stringify } from "../../Model/Utility/utility";
|
import { stringify } from "../../Model/Utility/utility";
|
||||||
|
import { PlaceholderView } from "../Components/placeholderView";
|
||||||
|
|
||||||
export function SettingsModal(
|
export function SettingsModal(
|
||||||
coreViewModel: CoreViewModel,
|
coreViewModel: CoreViewModel,
|
||||||
@@ -20,6 +21,11 @@ export function SettingsModal(
|
|||||||
[settingsViewModel.selectedModalPage],
|
[settingsViewModel.selectedModalPage],
|
||||||
() => {
|
() => {
|
||||||
switch (settingsViewModel.selectedModalPage.value) {
|
switch (settingsViewModel.selectedModalPage.value) {
|
||||||
|
case undefined: {
|
||||||
|
return PlaceholderView(
|
||||||
|
coreViewModel.translations.general.noPageSelected,
|
||||||
|
);
|
||||||
|
}
|
||||||
case SettingsModalPages.Appearance:
|
case SettingsModalPages.Appearance:
|
||||||
return SettingsAppearancePane(
|
return SettingsAppearancePane(
|
||||||
coreViewModel,
|
coreViewModel,
|
||||||
@@ -44,6 +50,7 @@ export function SettingsModal(
|
|||||||
<div>
|
<div>
|
||||||
<main class="padding-0">
|
<main class="padding-0">
|
||||||
{SplitModal(
|
{SplitModal(
|
||||||
|
coreViewModel,
|
||||||
new React.State(
|
new React.State(
|
||||||
SettingsLeftPane(coreViewModel, settingsViewModel),
|
SettingsLeftPane(coreViewModel, settingsViewModel),
|
||||||
),
|
),
|
||||||
@@ -66,7 +73,8 @@ function SettingsLeftPane(
|
|||||||
settingsViewModel: SettingsViewModel,
|
settingsViewModel: SettingsViewModel,
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
<div class="flex-column gap">
|
<div class="flex-column gap slide-up">
|
||||||
|
<h2>{coreViewModel.translations.homePage.settingsButton}</h2>
|
||||||
{SettingsPaneButton(
|
{SettingsPaneButton(
|
||||||
settingsViewModel,
|
settingsViewModel,
|
||||||
SettingsModalPages.Appearance,
|
SettingsModalPages.Appearance,
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ export function StorageModal(
|
|||||||
<div>
|
<div>
|
||||||
<main class="padding-0">
|
<main class="padding-0">
|
||||||
{SplitModal(
|
{SplitModal(
|
||||||
|
coreViewModel,
|
||||||
new React.State(DirectoryItemList(storageViewModel)),
|
new React.State(DirectoryItemList(storageViewModel)),
|
||||||
detailView,
|
detailView,
|
||||||
true,
|
true,
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ const englishTranslations = {
|
|||||||
waitingLabel: "Waiting...",
|
waitingLabel: "Waiting...",
|
||||||
|
|
||||||
restoreConnection: "Restore connection",
|
restoreConnection: "Restore connection",
|
||||||
|
|
||||||
|
noPageSelected: "No page selected",
|
||||||
},
|
},
|
||||||
|
|
||||||
regional: {
|
regional: {
|
||||||
@@ -328,6 +330,8 @@ export const allTranslations: {
|
|||||||
waitingLabel: "Warten...",
|
waitingLabel: "Warten...",
|
||||||
|
|
||||||
restoreConnection: "Verbindung wiederherstellen",
|
restoreConnection: "Verbindung wiederherstellen",
|
||||||
|
|
||||||
|
noPageSelected: "Keine Seite ausgewählt",
|
||||||
},
|
},
|
||||||
|
|
||||||
regional: {
|
regional: {
|
||||||
@@ -597,6 +601,8 @@ export const allTranslations: {
|
|||||||
waitingLabel: "Esperando...",
|
waitingLabel: "Esperando...",
|
||||||
|
|
||||||
restoreConnection: "Conectar de nuevo",
|
restoreConnection: "Conectar de nuevo",
|
||||||
|
|
||||||
|
noPageSelected: "No página seleccionada",
|
||||||
},
|
},
|
||||||
|
|
||||||
regional: {
|
regional: {
|
||||||
|
|||||||
@@ -8,9 +8,8 @@ export default class SettingsViewModel {
|
|||||||
username: React.State<string> = new React.State("");
|
username: React.State<string> = new React.State("");
|
||||||
usernameInput: React.State<string> = new React.State("");
|
usernameInput: React.State<string> = new React.State("");
|
||||||
isShowingSettingsModal: React.State<boolean> = new React.State(false);
|
isShowingSettingsModal: React.State<boolean> = new React.State(false);
|
||||||
selectedModalPage: React.State<SettingsModalPages> = new React.State(
|
selectedModalPage: React.State<SettingsModalPages | undefined> =
|
||||||
SettingsModalPages.Appearance,
|
new React.State(undefined);
|
||||||
);
|
|
||||||
requiresReload = new React.State<boolean>(false);
|
requiresReload = new React.State<boolean>(false);
|
||||||
|
|
||||||
firstDayOfWeek: React.State<string> = new React.State("0");
|
firstDayOfWeek: React.State<string> = new React.State("0");
|
||||||
|
|||||||
Reference in New Issue
Block a user