diff --git a/dist/index.css b/dist/index.css
index 321b420d..506572c6 100644
--- a/dist/index.css
+++ b/dist/index.css
@@ -1,130 +1,26 @@
-/* src/styles.css */
-[unread] {
- 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 {
+/* src/View/homePage.css */
+#home-page > div {
display: flex;
flex-direction: column;
- width: 100%;
- height: 100%;
+ gap: var(--large-gap);
}
-.calendar-wrapper .month-grid {
- border-bottom: 1px solid var(--border);
-}
-.calendar-wrapper > * {
+#home-page > div > div {
+ display: flex;
+ flex-direction: column;
+ justify-content: start;
+ gap: var(--gap-between-tiles);
width: 100%;
- height: 100%;
flex: 1;
}
-.day-miniature[today] h3 {
- color: var(--primary);
+#home-page #overview-section {
+ max-width: var(--max-input-width);
}
-.day-miniature:has(> div:not(:empty)):not([selected]) {
- border: var(--gap-between-tiles) solid var(--text-warning);
-}
-@media (min-width: 750px) {
- .calendar-wrapper:not([chatvisible] *) {
+@media (min-width: 1000px) {
+ #home-page > div {
flex-direction: row;
+ gap: 8rem;
}
- .calendar-wrapper:not([chatvisible] *) .month-grid {
- border-bottom: none;
- 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;
+ #home-page #overview-section {
+ width: var(--max-input-width);
}
}
diff --git a/dist/index.js b/dist/index.js
index b354a1db..dc7117c7 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -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
var UDNFrontend = class {
ws;
@@ -257,7 +111,7 @@
}
};
- // src/utility.ts
+ // src/Model/Utility/utility.ts
function stringify(data) {
return JSON.stringify(data);
}
@@ -308,30 +162,164 @@
}
};
- // src/View/maintenance.tsx
- var addressInput = restoreState("maintenance-address", "");
- var connectedAddress = new State("");
- var isConnected = new State(false);
- var connectionModel = new ConnectionModel({
- connectionChangeHandler() {
- isConnected.value = connectionModel.isConnected;
- connectedAddress.value = connectionModel.address ?? "---";
- },
- messageHandler(data) {
- console.log(data);
- }
- });
- function connect() {
- connectionModel.connect(addressInput.value);
+ // node_modules/bloatless-react/index.ts
+ 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;
}
- 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";
// src/Model/storageModel.ts
@@ -421,5 +409,11 @@
// src/index.tsx
var storageModel = new StorageModel();
- console.log(storageModel.list("z"));
+ var connectionModel = new ConnectionModel({
+ connectionChangeHandler() {
+ },
+ messageHandler(data) {
+ }
+ });
+ document.querySelector("main").append(HomePage(), MainPage(), SetttingsModal());
})();
diff --git a/src/typeSafety.ts b/src/Model/Utility/typeSafety.ts
similarity index 100%
rename from src/typeSafety.ts
rename to src/Model/Utility/typeSafety.ts
diff --git a/src/utility.ts b/src/Model/Utility/utility.ts
similarity index 100%
rename from src/utility.ts
rename to src/Model/Utility/utility.ts
diff --git a/src/Model/chatModel.ts b/src/Model/chatModel.ts
index 6ddb30c2..8d738cd2 100644
--- a/src/Model/chatModel.ts
+++ b/src/Model/chatModel.ts
@@ -2,8 +2,8 @@
import StorageModel, { storageKeys } from "./storageModel";
-import { checkIsValidObject } from "../typeSafety";
-import { createTimestamp } from "../utility";
+import { checkIsValidObject } from "./Utility/typeSafety";
+import { createTimestamp } from "./Utility/utility";
import { v4 } from "uuid";
export class ChatModel {
diff --git a/src/Model/connectionModel.ts b/src/Model/connectionModel.ts
index 26aa19cd..22f2245a 100644
--- a/src/Model/connectionModel.ts
+++ b/src/Model/connectionModel.ts
@@ -3,7 +3,7 @@
import UDNFrontend, { Message } from "udn-frontend";
import { ChatMessage } from "./chatModel";
-import { stringify } from "../utility";
+import { stringify } from "./Utility/utility";
export default class ConnectionModel {
// basic
diff --git a/src/Model/storageModel.ts b/src/Model/storageModel.ts
index e0f563c4..f9a237ac 100644
--- a/src/Model/storageModel.ts
+++ b/src/Model/storageModel.ts
@@ -1,8 +1,8 @@
// 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 {
storageEntryTree: StorageEntry = {};
diff --git a/src/View/homePage.css b/src/View/homePage.css
new file mode 100644
index 00000000..72b31675
--- /dev/null
+++ b/src/View/homePage.css
@@ -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);
+ }
+}
diff --git a/src/View/homePage.tsx b/src/View/homePage.tsx
new file mode 100644
index 00000000..014adf0f
--- /dev/null
+++ b/src/View/homePage.tsx
@@ -0,0 +1,48 @@
+import "./homePage.css";
+
+import * as React from "bloatless-react";
+
+import { translations } from "./translations";
+
+export function HomePage() {
+ return (
+ {translations.homePage.overviewHeadline}
+
+ {translations.homePage.statusHeadline}
+ {translations.homePage.chatsHeadline}
+
+