start home page and settings
This commit is contained in:
Vendored
+15
-119
@@ -1,130 +1,26 @@
|
|||||||
/* src/styles.css */
|
/* src/View/homePage.css */
|
||||||
[unread] {
|
#home-page > div {
|
||||||
border-left: 10px solid var(--text-warning);
|
|
||||||
}
|
|
||||||
:root {
|
|
||||||
--split-thread-height: 8rem;
|
|
||||||
--split-thread-width: 20rem;
|
|
||||||
}
|
|
||||||
.object-entry-wide {
|
|
||||||
width: 320px;
|
|
||||||
min-width: 320px;
|
|
||||||
}
|
|
||||||
#message-tab {
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
.chat-object-view {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
[showingobjects] header {
|
|
||||||
border-bottom: 1px solid var(--border);
|
|
||||||
}
|
|
||||||
[showingobjects] footer {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
[showingobjects] .chat-object-view {
|
|
||||||
display: flex;
|
|
||||||
top: var(--header-height);
|
|
||||||
}
|
|
||||||
[showingobjects] .thread-view {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
[showingobjects][chatvisible] .chat-object-view {
|
|
||||||
right: var(--split-thread-width);
|
|
||||||
border-right: 1px solid var(--border);
|
|
||||||
}
|
|
||||||
[showingobjects][chatvisible] .thread-view {
|
|
||||||
top: var(--header-height);
|
|
||||||
padding-top: var(--content-padding);
|
|
||||||
}
|
|
||||||
[showingobjects][chatvisible] :is(.thread-view, footer) {
|
|
||||||
display: flex;
|
|
||||||
right: 0px;
|
|
||||||
left: unset;
|
|
||||||
width: var(--split-thread-width);
|
|
||||||
}
|
|
||||||
main:has([showingobjects][chatopen]) {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
main:has([showingobjects][chatopen]) #settings-tab {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
@media (max-width: 640px) {
|
|
||||||
[showingobjects][chatvisible][chatopen] .chat-object-view {
|
|
||||||
width: 100%;
|
|
||||||
bottom: calc(var(--split-thread-height) + var(--control-height));
|
|
||||||
border-right: none;
|
|
||||||
border-bottom: 1px solid var(--border);
|
|
||||||
}
|
|
||||||
[showingobjects][chatvisible][chatopen] .thread-view {
|
|
||||||
top: unset;
|
|
||||||
bottom: calc(var(--control-height) + var(--safe-area-bottom));
|
|
||||||
width: 100%;
|
|
||||||
height: var(--split-thread-height);
|
|
||||||
padding: 0px;
|
|
||||||
}
|
|
||||||
[showingobjects][chatvisible][chatopen] footer {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:root {
|
|
||||||
--day-view-width: 400px;
|
|
||||||
}
|
|
||||||
.calendar-wrapper {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
width: 100%;
|
gap: var(--large-gap);
|
||||||
height: 100%;
|
|
||||||
}
|
}
|
||||||
.calendar-wrapper .month-grid {
|
#home-page > div > div {
|
||||||
border-bottom: 1px solid var(--border);
|
display: flex;
|
||||||
}
|
flex-direction: column;
|
||||||
.calendar-wrapper > * {
|
justify-content: start;
|
||||||
|
gap: var(--gap-between-tiles);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
.day-miniature[today] h3 {
|
#home-page #overview-section {
|
||||||
color: var(--primary);
|
max-width: var(--max-input-width);
|
||||||
}
|
}
|
||||||
.day-miniature:has(> div:not(:empty)):not([selected]) {
|
@media (min-width: 1000px) {
|
||||||
border: var(--gap-between-tiles) solid var(--text-warning);
|
#home-page > div {
|
||||||
}
|
|
||||||
@media (min-width: 750px) {
|
|
||||||
.calendar-wrapper:not([chatvisible] *) {
|
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
gap: 8rem;
|
||||||
}
|
}
|
||||||
.calendar-wrapper:not([chatvisible] *) .month-grid {
|
#home-page #overview-section {
|
||||||
border-bottom: none;
|
width: var(--max-input-width);
|
||||||
border-right: 1px solid var(--border);
|
|
||||||
}
|
|
||||||
.calendar-wrapper:not([chatvisible] *) .day-view {
|
|
||||||
max-width: var(--day-view-width);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (min-width: 1200px) {
|
|
||||||
.calendar-wrapper {
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
.calendar-wrapper .month-grid {
|
|
||||||
border-bottom: none;
|
|
||||||
border-right: 1px solid var(--border);
|
|
||||||
}
|
|
||||||
.calendar-wrapper .day-view {
|
|
||||||
max-width: var(--day-view-width);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (max-width: 600px) or ((min-width: 750px) and (max-width: 1100px)) {
|
|
||||||
.day-miniature {
|
|
||||||
padding: 0px !important;
|
|
||||||
align-items: center !important;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
.day-miniature h3 {
|
|
||||||
font-size: 1rem;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
.day-miniature > div {
|
|
||||||
display: none;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+164
-170
@@ -1,150 +1,4 @@
|
|||||||
(() => {
|
(() => {
|
||||||
// node_modules/bloatless-react/index.ts
|
|
||||||
var State = class {
|
|
||||||
_value;
|
|
||||||
_bindings = /* @__PURE__ */ new Set();
|
|
||||||
// init
|
|
||||||
constructor(initialValue) {
|
|
||||||
this._value = initialValue;
|
|
||||||
}
|
|
||||||
// value
|
|
||||||
get value() {
|
|
||||||
return this._value;
|
|
||||||
}
|
|
||||||
set value(newValue) {
|
|
||||||
if (this._value == newValue) return;
|
|
||||||
this._value = newValue;
|
|
||||||
this.callSubscriptions();
|
|
||||||
}
|
|
||||||
// subscriptions
|
|
||||||
callSubscriptions() {
|
|
||||||
this._bindings.forEach((fn) => fn(this._value));
|
|
||||||
}
|
|
||||||
subscribe(fn) {
|
|
||||||
this._bindings.add(fn);
|
|
||||||
fn(this._value);
|
|
||||||
}
|
|
||||||
subscribeSilent(fn) {
|
|
||||||
this._bindings.add(fn);
|
|
||||||
}
|
|
||||||
// stringify
|
|
||||||
toString() {
|
|
||||||
return JSON.stringify(this._value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
function persistState(localStorageKey, state) {
|
|
||||||
state.subscribe(() => {
|
|
||||||
const stringifiedValue = state.toString();
|
|
||||||
localStorage.setItem(localStorageKey, stringifiedValue);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
function restoreState(localStorageKey, initialStateValue) {
|
|
||||||
const storedString = localStorage.getItem(localStorageKey) ?? JSON.stringify(initialStateValue);
|
|
||||||
const convertedValue = JSON.parse(storedString);
|
|
||||||
const state = new State(convertedValue);
|
|
||||||
persistState(localStorageKey, state);
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
function createElement(tagName, attributes = {}, ...children) {
|
|
||||||
const element = document.createElement(tagName);
|
|
||||||
if (attributes != null)
|
|
||||||
Object.entries(attributes).forEach((entry) => {
|
|
||||||
const [attributename, value] = entry;
|
|
||||||
const [directiveKey, directiveValue] = attributename.split(":");
|
|
||||||
switch (directiveKey) {
|
|
||||||
case "on": {
|
|
||||||
switch (directiveValue) {
|
|
||||||
case "enter": {
|
|
||||||
element.addEventListener("keydown", (e) => {
|
|
||||||
if (e.key != "Enter") return;
|
|
||||||
value();
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
element.addEventListener(directiveValue, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "subscribe": {
|
|
||||||
const state = value;
|
|
||||||
state.subscribe(
|
|
||||||
(newValue) => element[directiveValue] = newValue
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "bind": {
|
|
||||||
const state = value;
|
|
||||||
state.subscribe(
|
|
||||||
(newValue) => element[directiveValue] = newValue
|
|
||||||
);
|
|
||||||
element.addEventListener(
|
|
||||||
"input",
|
|
||||||
() => state.value = element[directiveValue]
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "toggle": {
|
|
||||||
if (value.subscribe) {
|
|
||||||
const state = value;
|
|
||||||
state.subscribe(
|
|
||||||
(newValue) => element.toggleAttribute(directiveValue, newValue)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
element.toggleAttribute(directiveValue, value);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "set": {
|
|
||||||
const state = value;
|
|
||||||
state.subscribe(
|
|
||||||
(newValue) => element.setAttribute(directiveValue, newValue)
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "children": {
|
|
||||||
switch (directiveValue) {
|
|
||||||
case "set": {
|
|
||||||
const state = value;
|
|
||||||
state.subscribe((newValue) => {
|
|
||||||
element.innerHTML = "";
|
|
||||||
element.append(...[newValue].flat());
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "append":
|
|
||||||
case "appendandscroll":
|
|
||||||
case "prepend": {
|
|
||||||
element.style.scrollBehavior = "smooth";
|
|
||||||
try {
|
|
||||||
const [listState, toElement] = value;
|
|
||||||
listState.handleAddition((newItem) => {
|
|
||||||
const child = toElement(newItem);
|
|
||||||
listState.handleRemoval(
|
|
||||||
newItem,
|
|
||||||
() => child.remove()
|
|
||||||
);
|
|
||||||
if (directiveValue == "append") {
|
|
||||||
element.append(child);
|
|
||||||
} else if (directiveValue == "prepend") {
|
|
||||||
element.prepend(child);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch {
|
|
||||||
throw `error: cannot process subscribe:children directive because StateItemConverter is not defined. Usage: "subscribe:children={[list, converter]}"; you can find a more detailed example in the documentation`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
element.setAttribute(attributename, value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
children.filter((x) => x).forEach((child) => element.append(child));
|
|
||||||
return element;
|
|
||||||
}
|
|
||||||
|
|
||||||
// node_modules/udn-frontend/index.ts
|
// node_modules/udn-frontend/index.ts
|
||||||
var UDNFrontend = class {
|
var UDNFrontend = class {
|
||||||
ws;
|
ws;
|
||||||
@@ -257,7 +111,7 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// src/utility.ts
|
// src/Model/Utility/utility.ts
|
||||||
function stringify(data) {
|
function stringify(data) {
|
||||||
return JSON.stringify(data);
|
return JSON.stringify(data);
|
||||||
}
|
}
|
||||||
@@ -308,30 +162,164 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// src/View/maintenance.tsx
|
// node_modules/bloatless-react/index.ts
|
||||||
var addressInput = restoreState("maintenance-address", "");
|
function createElement(tagName, attributes = {}, ...children) {
|
||||||
var connectedAddress = new State("");
|
const element = document.createElement(tagName);
|
||||||
var isConnected = new State(false);
|
if (attributes != null)
|
||||||
var connectionModel = new ConnectionModel({
|
Object.entries(attributes).forEach((entry) => {
|
||||||
connectionChangeHandler() {
|
const [attributename, value] = entry;
|
||||||
isConnected.value = connectionModel.isConnected;
|
const [directiveKey, directiveValue] = attributename.split(":");
|
||||||
connectedAddress.value = connectionModel.address ?? "---";
|
switch (directiveKey) {
|
||||||
},
|
case "on": {
|
||||||
messageHandler(data) {
|
switch (directiveValue) {
|
||||||
console.log(data);
|
case "enter": {
|
||||||
}
|
element.addEventListener("keydown", (e) => {
|
||||||
});
|
if (e.key != "Enter") return;
|
||||||
function connect() {
|
value();
|
||||||
connectionModel.connect(addressInput.value);
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
element.addEventListener(directiveValue, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "subscribe": {
|
||||||
|
const state = value;
|
||||||
|
state.subscribe(
|
||||||
|
(newValue) => element[directiveValue] = newValue
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "bind": {
|
||||||
|
const state = value;
|
||||||
|
state.subscribe(
|
||||||
|
(newValue) => element[directiveValue] = newValue
|
||||||
|
);
|
||||||
|
element.addEventListener(
|
||||||
|
"input",
|
||||||
|
() => state.value = element[directiveValue]
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "toggle": {
|
||||||
|
if (value.subscribe) {
|
||||||
|
const state = value;
|
||||||
|
state.subscribe(
|
||||||
|
(newValue) => element.toggleAttribute(directiveValue, newValue)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
element.toggleAttribute(directiveValue, value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "set": {
|
||||||
|
const state = value;
|
||||||
|
state.subscribe(
|
||||||
|
(newValue) => element.setAttribute(directiveValue, newValue)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "children": {
|
||||||
|
switch (directiveValue) {
|
||||||
|
case "set": {
|
||||||
|
const state = value;
|
||||||
|
state.subscribe((newValue) => {
|
||||||
|
element.innerHTML = "";
|
||||||
|
element.append(...[newValue].flat());
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "append":
|
||||||
|
case "appendandscroll":
|
||||||
|
case "prepend": {
|
||||||
|
element.style.scrollBehavior = "smooth";
|
||||||
|
try {
|
||||||
|
const [listState, toElement] = value;
|
||||||
|
listState.handleAddition((newItem) => {
|
||||||
|
const child = toElement(newItem);
|
||||||
|
listState.handleRemoval(
|
||||||
|
newItem,
|
||||||
|
() => child.remove()
|
||||||
|
);
|
||||||
|
if (directiveValue == "append") {
|
||||||
|
element.append(child);
|
||||||
|
} else if (directiveValue == "prepend") {
|
||||||
|
element.prepend(child);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
throw `error: cannot process subscribe:children directive because StateItemConverter is not defined. Usage: "subscribe:children={[list, converter]}"; you can find a more detailed example in the documentation`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
element.setAttribute(attributename, value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
children.filter((x) => x).forEach((child) => element.append(child));
|
||||||
|
return element;
|
||||||
}
|
}
|
||||||
function disconnect() {
|
|
||||||
connectionModel.disconnect();
|
|
||||||
}
|
|
||||||
document.querySelector("main").append(
|
|
||||||
/* @__PURE__ */ createElement("div", { class: "flex-column" }, /* @__PURE__ */ createElement("input", { "bind:value": addressInput }), /* @__PURE__ */ createElement("button", { "on:click": connect, "toggle:disabled": isConnected }, "Connect"), /* @__PURE__ */ createElement("button", { "on:click": disconnect }, "Disconnect"), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("span", { "subscribe:innerText": connectedAddress }))
|
|
||||||
);
|
|
||||||
|
|
||||||
// src/typeSafety.ts
|
// src/View/translations.ts
|
||||||
|
var englishTranslations = {
|
||||||
|
general: {
|
||||||
|
closeButton: "close"
|
||||||
|
},
|
||||||
|
homePage: {
|
||||||
|
appName: "Comms",
|
||||||
|
///
|
||||||
|
overviewHeadline: "Overview",
|
||||||
|
statusHeadline: "Status",
|
||||||
|
settingsButton: "Settings",
|
||||||
|
///
|
||||||
|
chatsHeadline: "Chats",
|
||||||
|
addChatAudioLabel: "name of new chat",
|
||||||
|
addChatPlaceholder: "Add chat",
|
||||||
|
addChatButton: "Add chat"
|
||||||
|
},
|
||||||
|
settings: {
|
||||||
|
settingsHeadline: "Settings"
|
||||||
|
///
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var allTranslations = {
|
||||||
|
en: englishTranslations
|
||||||
|
};
|
||||||
|
var language = navigator.language.substring(0, 2);
|
||||||
|
var translations = allTranslations[language] || allTranslations.en;
|
||||||
|
|
||||||
|
// src/View/homePage.tsx
|
||||||
|
function HomePage() {
|
||||||
|
return /* @__PURE__ */ createElement("article", { id: "home-page" }, /* @__PURE__ */ createElement("header", null, /* @__PURE__ */ createElement("span", null, translations.homePage.appName)), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("div", { id: "overview-section" }, /* @__PURE__ */ createElement("h2", null, translations.homePage.overviewHeadline), /* @__PURE__ */ createElement("div", { class: "tile flex-no" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "cell_tower"), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("h3", null, translations.homePage.statusHeadline))), /* @__PURE__ */ createElement("button", { class: "tile flex-no" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "settings"), /* @__PURE__ */ createElement("div", null, translations.homePage.settingsButton))), /* @__PURE__ */ createElement("div", { id: "chat-section" }, /* @__PURE__ */ createElement("h2", null, translations.homePage.chatsHeadline), /* @__PURE__ */ createElement("div", { class: "flex-row width-input" }, /* @__PURE__ */ createElement(
|
||||||
|
"input",
|
||||||
|
{
|
||||||
|
placeholder: translations.homePage.addChatPlaceholder,
|
||||||
|
"aria-label": translations.homePage.addChatAudioLabel
|
||||||
|
}
|
||||||
|
), /* @__PURE__ */ createElement(
|
||||||
|
"button",
|
||||||
|
{
|
||||||
|
class: "primary",
|
||||||
|
"aria-label": translations.homePage.addChatButton
|
||||||
|
},
|
||||||
|
/* @__PURE__ */ createElement("span", { class: "icon" }, "add")
|
||||||
|
)))));
|
||||||
|
}
|
||||||
|
|
||||||
|
// src/View/mainPage.tsx
|
||||||
|
function MainPage() {
|
||||||
|
return /* @__PURE__ */ createElement("article", { id: "home-page" }, /* @__PURE__ */ createElement("header", null, /* @__PURE__ */ createElement("span", null, translations.homePage.appName)), /* @__PURE__ */ createElement("div", null));
|
||||||
|
}
|
||||||
|
|
||||||
|
// src/View/setingsModal.tsx
|
||||||
|
function SetttingsModal() {
|
||||||
|
return /* @__PURE__ */ createElement("div", { class: "modal" }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("main", null, /* @__PURE__ */ createElement("h2", null, translations.settings.settingsHeadline)), /* @__PURE__ */ createElement("button", null, translations.general.closeButton, /* @__PURE__ */ createElement("span", { class: "icon" }, "close"))));
|
||||||
|
}
|
||||||
|
|
||||||
|
// src/Model/Utility/typeSafety.ts
|
||||||
var DATA_VERSION = "v2";
|
var DATA_VERSION = "v2";
|
||||||
|
|
||||||
// src/Model/storageModel.ts
|
// src/Model/storageModel.ts
|
||||||
@@ -421,5 +409,11 @@
|
|||||||
|
|
||||||
// src/index.tsx
|
// src/index.tsx
|
||||||
var storageModel = new StorageModel();
|
var storageModel = new StorageModel();
|
||||||
console.log(storageModel.list("z"));
|
var connectionModel = new ConnectionModel({
|
||||||
|
connectionChangeHandler() {
|
||||||
|
},
|
||||||
|
messageHandler(data) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
document.querySelector("main").append(HomePage(), MainPage(), SetttingsModal());
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
import StorageModel, { storageKeys } from "./storageModel";
|
import StorageModel, { storageKeys } from "./storageModel";
|
||||||
|
|
||||||
import { checkIsValidObject } from "../typeSafety";
|
import { checkIsValidObject } from "./Utility/typeSafety";
|
||||||
import { createTimestamp } from "../utility";
|
import { createTimestamp } from "./Utility/utility";
|
||||||
import { v4 } from "uuid";
|
import { v4 } from "uuid";
|
||||||
|
|
||||||
export class ChatModel {
|
export class ChatModel {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import UDNFrontend, { Message } from "udn-frontend";
|
import UDNFrontend, { Message } from "udn-frontend";
|
||||||
|
|
||||||
import { ChatMessage } from "./chatModel";
|
import { ChatMessage } from "./chatModel";
|
||||||
import { stringify } from "../utility";
|
import { stringify } from "./Utility/utility";
|
||||||
|
|
||||||
export default class ConnectionModel {
|
export default class ConnectionModel {
|
||||||
// basic
|
// basic
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
// this file is responsible for reading and writing persistent data; all storage shall be handled by this file.
|
// this file is responsible for reading and writing persistent data; all storage shall be handled by this file.
|
||||||
|
|
||||||
import { parse, stringify } from "../utility";
|
import { parse, stringify } from "./Utility/utility";
|
||||||
|
|
||||||
import { DATA_VERSION } from "../typeSafety";
|
import { DATA_VERSION } from "./Utility/typeSafety";
|
||||||
|
|
||||||
export default class StorageModel {
|
export default class StorageModel {
|
||||||
storageEntryTree: StorageEntry = {};
|
storageEntryTree: StorageEntry = {};
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
#home-page > div {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
gap: var(--large-gap);
|
||||||
|
}
|
||||||
|
|
||||||
|
#home-page > div > div {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: start;
|
||||||
|
|
||||||
|
gap: var(--gap-between-tiles);
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#home-page #overview-section {
|
||||||
|
max-width: var(--max-input-width);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1000px) {
|
||||||
|
#home-page > div {
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
gap: 8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#home-page #overview-section {
|
||||||
|
width: var(--max-input-width);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
import "./homePage.css";
|
||||||
|
|
||||||
|
import * as React from "bloatless-react";
|
||||||
|
|
||||||
|
import { translations } from "./translations";
|
||||||
|
|
||||||
|
export function HomePage() {
|
||||||
|
return (
|
||||||
|
<article id="home-page">
|
||||||
|
<header>
|
||||||
|
<span>{translations.homePage.appName}</span>
|
||||||
|
</header>
|
||||||
|
<div>
|
||||||
|
<div id="overview-section">
|
||||||
|
<h2>{translations.homePage.overviewHeadline}</h2>
|
||||||
|
|
||||||
|
<div class="tile flex-no">
|
||||||
|
<span class="icon">cell_tower</span>
|
||||||
|
<div>
|
||||||
|
<h3>{translations.homePage.statusHeadline}</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="tile flex-no">
|
||||||
|
<span class="icon">settings</span>
|
||||||
|
<div>{translations.homePage.settingsButton}</div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="chat-section">
|
||||||
|
<h2>{translations.homePage.chatsHeadline}</h2>
|
||||||
|
|
||||||
|
<div class="flex-row width-input">
|
||||||
|
<input
|
||||||
|
placeholder={translations.homePage.addChatPlaceholder}
|
||||||
|
aria-label={translations.homePage.addChatAudioLabel}
|
||||||
|
></input>
|
||||||
|
<button
|
||||||
|
class="primary"
|
||||||
|
aria-label={translations.homePage.addChatButton}
|
||||||
|
>
|
||||||
|
<span class="icon">add</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import * as React from "bloatless-react";
|
||||||
|
|
||||||
|
import { translations } from "./translations";
|
||||||
|
|
||||||
|
export function MainPage() {
|
||||||
|
return (
|
||||||
|
<article id="home-page">
|
||||||
|
<header>
|
||||||
|
<span>{translations.homePage.appName}</span>
|
||||||
|
</header>
|
||||||
|
<div></div>
|
||||||
|
</article>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import * as React from "bloatless-react";
|
||||||
|
|
||||||
|
import { translations } from "./translations";
|
||||||
|
|
||||||
|
export function SetttingsModal() {
|
||||||
|
return (
|
||||||
|
<div class="modal">
|
||||||
|
<div>
|
||||||
|
<main>
|
||||||
|
<h2>{translations.settings.settingsHeadline}</h2>
|
||||||
|
</main>
|
||||||
|
<button>
|
||||||
|
{translations.general.closeButton}
|
||||||
|
<span class="icon">close</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
const englishTranslations = {
|
||||||
|
general: {
|
||||||
|
closeButton: "close",
|
||||||
|
},
|
||||||
|
|
||||||
|
homePage: {
|
||||||
|
appName: "Comms",
|
||||||
|
|
||||||
|
///
|
||||||
|
|
||||||
|
overviewHeadline: "Overview",
|
||||||
|
|
||||||
|
statusHeadline: "Status",
|
||||||
|
settingsButton: "Settings",
|
||||||
|
|
||||||
|
///
|
||||||
|
|
||||||
|
chatsHeadline: "Chats",
|
||||||
|
|
||||||
|
addChatAudioLabel: "name of new chat",
|
||||||
|
addChatPlaceholder: "Add chat",
|
||||||
|
addChatButton: "Add chat",
|
||||||
|
},
|
||||||
|
|
||||||
|
settings: {
|
||||||
|
settingsHeadline: "Settings",
|
||||||
|
|
||||||
|
///
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const allTranslations: { [language: string]: typeof englishTranslations } = {
|
||||||
|
en: englishTranslations,
|
||||||
|
};
|
||||||
|
|
||||||
|
const language = navigator.language.substring(0, 2);
|
||||||
|
export const translations = allTranslations[language] || allTranslations.en;
|
||||||
+11
-6
@@ -1,12 +1,17 @@
|
|||||||
import ConnectionModel from "./Model/connectionModel";
|
import ConnectionModel from "./Model/connectionModel";
|
||||||
|
import { HomePage } from "./View/homePage";
|
||||||
|
import { MainPage } from "./View/mainPage";
|
||||||
|
import { SetttingsModal } from "./View/setingsModal";
|
||||||
import StorageModel from "./Model/storageModel";
|
import StorageModel from "./Model/storageModel";
|
||||||
|
|
||||||
|
// models
|
||||||
const storageModel = new StorageModel();
|
const storageModel = new StorageModel();
|
||||||
const connectionModel = new ConnectionModel({
|
const connectionModel = new ConnectionModel({
|
||||||
connectionChangeHandler() {
|
connectionChangeHandler() {},
|
||||||
|
messageHandler(data) {},
|
||||||
|
});
|
||||||
|
|
||||||
},
|
// view
|
||||||
messageHandler(data) {
|
document
|
||||||
|
.querySelector("main")!
|
||||||
},
|
.append(HomePage(), MainPage(), SetttingsModal());
|
||||||
})
|
|
||||||
|
|||||||
Reference in New Issue
Block a user