move translations to CoreVM, move models to CoreVM for sentralization

This commit is contained in:
marlon-erler
2026-04-09 16:48:22 +00:00
parent 6204669ba3
commit 78672afc40
42 changed files with 1786 additions and 1322 deletions
+13 -4
View File
@@ -11,9 +11,12 @@ import { TaskCategoryBulkChangeViewModel } from "../../ViewModel/Utility/taskPro
import TaskViewModel from "../../ViewModel/Pages/taskViewModel";
import { TaskViewModelToEntry } from "../Components/taskEntry";
import { allowDrop } from "../utility";
import { translations } from "../translations";
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
export function BoardKanbanPage(boardViewModel: BoardViewModel) {
export function BoardKanbanPage(
coreViewModel: CoreViewModel,
boardViewModel: BoardViewModel,
) {
return PropertyValueList(
"category",
(taskViewModel: TaskViewModel) => taskViewModel.task,
@@ -30,7 +33,12 @@ export function BoardKanbanPage(boardViewModel: BoardViewModel) {
sortedCategories,
categoryName,
);
return Column(categoryName, index, boardViewModel);
return Column(
coreViewModel,
categoryName,
index,
boardViewModel,
);
};
return (
@@ -44,6 +52,7 @@ export function BoardKanbanPage(boardViewModel: BoardViewModel) {
}
function Column(
coreViewModel: CoreViewModel,
categoryName: string,
index: React.State<number>,
boardViewModel: BoardViewModel,
@@ -72,7 +81,7 @@ function Column(
<div class="flex-row width-input">
<input
placeholder={
translations.chatPage.task
coreViewModel.translations.chatPage.task
.renameCategoryInputPlaceholder
}
bind:value={viewModel.inputValue}
+23 -14
View File
@@ -11,10 +11,13 @@ import { BoardViewToggleButton } from "../Components/boardViewToggleButton";
import { SearchModal } from "../Modals/searchModal";
import { TaskSettingsModal } from "../Modals/taskSettingsModal";
import { TaskViewModelToEntry } from "../Components/taskEntry";
import { translations } from "../translations";
import { setFocusWithDelay } from "../utility";
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
export function BoardPage(boardViewModel: BoardViewModel) {
export function BoardPage(
coreViewModel: CoreViewModel,
boardViewModel: BoardViewModel,
) {
boardViewModel.loadData();
// main content
@@ -23,10 +26,10 @@ export function BoardPage(boardViewModel: BoardViewModel) {
() => {
switch (boardViewModel.selectedPage.value) {
case BoardPageTypes.Kanban: {
return BoardKanbanPage(boardViewModel);
return BoardKanbanPage(coreViewModel, boardViewModel);
}
case BoardPageTypes.StatusGrid: {
return BoardStatusGridPage(boardViewModel);
return BoardStatusGridPage(coreViewModel, boardViewModel);
}
default: {
return (
@@ -53,6 +56,7 @@ export function BoardPage(boardViewModel: BoardViewModel) {
setFocusWithDelay();
return TaskSettingsModal(
coreViewModel,
boardViewModel.selectedTaskViewModel.value,
);
}
@@ -66,7 +70,7 @@ export function BoardPage(boardViewModel: BoardViewModel) {
<button
class="ghost board-close-button"
aria-label={
translations.chatPage.task
coreViewModel.translations.chatPage.task
.closeBoardButtonAudioLabel
}
on:click={boardViewModel.close}
@@ -76,7 +80,7 @@ export function BoardPage(boardViewModel: BoardViewModel) {
<button
class="ghost board-toggle-button inset-outline"
aria-label={
translations.chatPage.task
coreViewModel.translations.chatPage.task
.toggleBoardButtonAudioLabel
}
on:click={
@@ -91,7 +95,8 @@ export function BoardPage(boardViewModel: BoardViewModel) {
<button
class="ghost"
aria-label={
translations.chatPage.task.boardSettingsHeadline
coreViewModel.translations.chatPage.task
.boardSettingsHeadline
}
on:click={boardViewModel.showSettings}
>
@@ -100,19 +105,22 @@ export function BoardPage(boardViewModel: BoardViewModel) {
</span>
<span class="scroll-h ribbon">
{BoardViewToggleButton(
translations.chatPage.task.listViewButtonAudioLabel,
coreViewModel.translations.chatPage.task
.listViewButtonAudioLabel,
"view_list",
BoardPageTypes.List,
boardViewModel,
)}
{BoardViewToggleButton(
translations.chatPage.task.kanbanViewButtonAudioLabel,
coreViewModel.translations.chatPage.task
.kanbanViewButtonAudioLabel,
"view_kanban",
BoardPageTypes.Kanban,
boardViewModel,
)}
{BoardViewToggleButton(
translations.chatPage.task.statusViewButtonAudioLabel,
coreViewModel.translations.chatPage.task
.statusViewButtonAudioLabel,
"grid_view",
BoardPageTypes.StatusGrid,
boardViewModel,
@@ -122,7 +130,7 @@ export function BoardPage(boardViewModel: BoardViewModel) {
<button
class="ghost"
aria-label={
translations.chatPage.task
coreViewModel.translations.chatPage.task
.filterTasksButtonAudioLabel
}
on:click={boardViewModel.showFilterModal}
@@ -132,7 +140,7 @@ export function BoardPage(boardViewModel: BoardViewModel) {
<button
class="ghost"
aria-label={
translations.chatPage.task
coreViewModel.translations.chatPage.task
.createTaskButtonAudioLabel
}
on:click={boardViewModel.createTask}
@@ -143,10 +151,11 @@ export function BoardPage(boardViewModel: BoardViewModel) {
</div>
<div class="content main-content" children:set={mainContent}></div>
{BoardSettingsModal(boardViewModel)}
{BoardSettingsModal(coreViewModel, boardViewModel)}
{SearchModal(
coreViewModel,
boardViewModel.searchViewModel,
translations.chatPage.task.filterTasksHeadline,
coreViewModel.translations.chatPage.task.filterTasksHeadline,
TaskViewModelToEntry,
boardViewModel.isPresentingFilterModal,
)}
+12 -5
View File
@@ -16,9 +16,12 @@ import { FilteredList } from "../Components/filteredList";
import TaskViewModel from "../../ViewModel/Pages/taskViewModel";
import { TaskViewModelToEntry } from "../Components/taskEntry";
import { allowDrop } from "../utility";
import { translations } from "../translations";
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
export function BoardStatusGridPage(boardViewModel: BoardViewModel) {
export function BoardStatusGridPage(
coreViewModel: CoreViewModel,
boardViewModel: BoardViewModel,
) {
const statuses: React.ListState<string> = new React.ListState();
const sortedStatuses: React.State<string[]> =
createSortedPropertyValueState(statuses);
@@ -36,7 +39,7 @@ export function BoardStatusGridPage(boardViewModel: BoardViewModel) {
statusName: string,
) => {
const index = createPropertyValueIndexState(sortedStatuses, statusName);
return StatusNameCell(statusName, index, boardViewModel);
return StatusNameCell(coreViewModel, statusName, index, boardViewModel);
};
return (
@@ -63,6 +66,7 @@ export function BoardStatusGridPage(boardViewModel: BoardViewModel) {
);
return CategoryRow(
coreViewModel,
categoryName,
index,
statuses,
@@ -84,6 +88,7 @@ export function BoardStatusGridPage(boardViewModel: BoardViewModel) {
}
function StatusNameCell(
coreViewModel: CoreViewModel,
statusName: string,
index: React.State<number>,
boardViewModel: BoardViewModel,
@@ -118,7 +123,8 @@ function StatusNameCell(
<div class="property-input-wrapper">
<input
placeholder={
translations.chatPage.task.renameStatusInputPlaceholder
coreViewModel.translations.chatPage.task
.renameStatusInputPlaceholder
}
bind:value={viewModel.inputValue}
on:enter={viewModel.set}
@@ -142,6 +148,7 @@ function StatusNameCell(
}
function CategoryRow(
coreViewModel: CoreViewModel,
categoryName: string,
index: React.State<number>,
allStatuses: React.ListState<string>,
@@ -180,7 +187,7 @@ function CategoryRow(
<div class="property-input-wrapper">
<input
placeholder={
translations.chatPage.task
coreViewModel.translations.chatPage.task
.renameCategoryInputPlaceholder
}
bind:value={viewModel.inputValue}
+21 -16
View File
@@ -7,10 +7,13 @@ import CalendarPageViewModel from "../../ViewModel/Pages/calendarPageViewModel";
import { MonthGrid } from "../Components/monthGrid";
import { TaskSettingsModal } from "../Modals/taskSettingsModal";
import { TaskViewModelToEntry } from "../Components/taskEntry";
import { translations } from "../translations";
import { setFocusWithDelay } from "../utility";
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
export function CalendarPage(calendarPageViewModel: CalendarPageViewModel) {
export function CalendarPage(
coreViewModel: CoreViewModel,
calendarPageViewModel: CalendarPageViewModel,
) {
calendarPageViewModel.loadData();
const mainContent = React.createProxyState(
@@ -30,6 +33,7 @@ export function CalendarPage(calendarPageViewModel: CalendarPageViewModel) {
}
return MonthGrid(
coreViewModel,
monthGrid,
calendarPageViewModel.selectedDate,
drop,
@@ -58,8 +62,8 @@ export function CalendarPage(calendarPageViewModel: CalendarPageViewModel) {
<div class="width-100 height-100 flex-column justify-center align-center">
<span class="secondary slide-up">
{
translations.chatPage.calendar
.noEvents
coreViewModel.translations.chatPage
.calendar.noEvents
}
</span>
</div>
@@ -99,6 +103,7 @@ export function CalendarPage(calendarPageViewModel: CalendarPageViewModel) {
setFocusWithDelay();
return TaskSettingsModal(
coreViewModel,
calendarPageViewModel.selectedTaskViewModel.value,
);
}
@@ -114,7 +119,7 @@ export function CalendarPage(calendarPageViewModel: CalendarPageViewModel) {
<button
class="ghost"
aria-label={
translations.chatPage.calendar
coreViewModel.translations.chatPage.calendar
.todayButtonAudioLabel
}
on:click={calendarPageViewModel.showToday}
@@ -126,7 +131,7 @@ export function CalendarPage(calendarPageViewModel: CalendarPageViewModel) {
<button
class="ghost"
aria-label={
translations.chatPage.calendar
coreViewModel.translations.chatPage.calendar
.previousMonthButtonAudioLabel
}
on:click={
@@ -140,12 +145,12 @@ export function CalendarPage(calendarPageViewModel: CalendarPageViewModel) {
class="year-input"
type="number"
aria-label={
translations.chatPage.calendar
.yearInputAudioLabel
coreViewModel.translations.chatPage
.calendar.yearInputAudioLabel
}
placeholder={
translations.chatPage.calendar
.yearInputPlaceholder
coreViewModel.translations.chatPage
.calendar.yearInputPlaceholder
}
bind:value={
calendarPageViewModel.selectedYear
@@ -155,12 +160,12 @@ export function CalendarPage(calendarPageViewModel: CalendarPageViewModel) {
class="month-input"
type="number"
aria-label={
translations.chatPage.calendar
.monthInputAudioLabel
coreViewModel.translations.chatPage
.calendar.monthInputAudioLabel
}
placeholder={
translations.chatPage.calendar
.monthInputPlaceholder
coreViewModel.translations.chatPage
.calendar.monthInputPlaceholder
}
bind:value={
calendarPageViewModel.selectedMonth
@@ -170,7 +175,7 @@ export function CalendarPage(calendarPageViewModel: CalendarPageViewModel) {
<button
class="ghost"
aria-label={
translations.chatPage.calendar
coreViewModel.translations.chatPage.calendar
.nextMonthButtonAudioLabel
}
on:click={calendarPageViewModel.showNextMonth}
@@ -182,7 +187,7 @@ export function CalendarPage(calendarPageViewModel: CalendarPageViewModel) {
<button
class="ghost"
aria-label={
translations.chatPage.task
coreViewModel.translations.chatPage.task
.createTaskButtonAudioLabel
}
on:click={calendarPageViewModel.createEvent}
+20 -6
View File
@@ -2,12 +2,21 @@ import "./messagePage.css";
import * as React from "bloatless-react";
import { ChatMessageViewModelToView } from "../Components/chatMessage";
import MessagePageViewModel from "../../ViewModel/Pages/messagePageViewModel";
import { translations } from "../translations";
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
import ChatMessageViewModel from "../../ViewModel/Chat/chatMessageViewModel";
import { ChatMessage } from "../Components/chatMessage";
export function MessagePage(messagePageViewModel: MessagePageViewModel) {
export function MessagePage(
coreViewModel: CoreViewModel,
messagePageViewModel: MessagePageViewModel,
) {
messagePageViewModel.loadData();
const ChatMessageViewModelToView: React.StateItemConverter<
ChatMessageViewModel
> = (chatMessageViewModel: ChatMessageViewModel) => {
return ChatMessage(coreViewModel, chatMessageViewModel);
};
const messageContainer = (
<div
@@ -45,7 +54,10 @@ export function MessagePage(messagePageViewModel: MessagePageViewModel) {
<div class="pane">
<div class="toolbar">
<span class="title">
{translations.chatPage.message.messagesHeadline}
{
coreViewModel.translations.chatPage.message
.messagesHeadline
}
</span>
</div>
<div class="content">
@@ -61,14 +73,16 @@ export function MessagePage(messagePageViewModel: MessagePageViewModel) {
messagePageViewModel.sendMessage
}
placeholder={
translations.chatPage.message
coreViewModel.translations.chatPage
.message
.composerInputPlaceholder
}
></input>
<button
class="primary"
aria-label={
translations.chatPage.message
coreViewModel.translations.chatPage
.message
.sendMessageButtonAudioLabel
}
on:click={
+35 -19
View File
@@ -5,17 +5,25 @@ import { ColorPicker } from "../Components/colorPicker";
import { DangerousActionButton } from "../Components/dangerousActionButton";
import { DeletableListItem } from "../Components/deletableListItem";
import SettingsPageViewModel from "../../ViewModel/Pages/settingsPageViewModel";
import { translations } from "../translations";
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
export function SettingsPage(settingsPageViewModel: SettingsPageViewModel) {
export function SettingsPage(
coreViewModel: CoreViewModel,
settingsPageViewModel: SettingsPageViewModel,
) {
settingsPageViewModel.loadData();
const secondaryChannelConverter: React.StateItemConverter<string> = (
secondaryChannel: string,
) => {
return DeletableListItem(secondaryChannel, <span></span>, () => {
settingsPageViewModel.removeSecondaryChannel(secondaryChannel);
});
return DeletableListItem(
coreViewModel,
secondaryChannel,
<span></span>,
() => {
settingsPageViewModel.removeSecondaryChannel(secondaryChannel);
},
);
};
return (
@@ -24,7 +32,10 @@ export function SettingsPage(settingsPageViewModel: SettingsPageViewModel) {
<div class="pane">
<div class="toolbar">
<span class="title">
{translations.chatPage.settings.settingsHeadline}
{
coreViewModel.translations.chatPage.settings
.settingsHeadline
}
</span>
</div>
<div class="content">
@@ -33,8 +44,8 @@ export function SettingsPage(settingsPageViewModel: SettingsPageViewModel) {
<div>
<span>
{
translations.chatPage.settings
.primaryChannelLabel
coreViewModel.translations.chatPage
.settings.primaryChannelLabel
}
</span>
<input
@@ -51,7 +62,7 @@ export function SettingsPage(settingsPageViewModel: SettingsPageViewModel) {
<button
class="width-50"
aria-label={
translations.chatPage.settings
coreViewModel.translations.chatPage.settings
.setPrimaryChannelButtonAudioLabel
}
on:click={
@@ -61,7 +72,7 @@ export function SettingsPage(settingsPageViewModel: SettingsPageViewModel) {
settingsPageViewModel.cannotSetPrimaryChannel
}
>
{translations.general.setButton}
{coreViewModel.translations.general.setButton}
<span class="icon">check</span>
</button>
</div>
@@ -71,11 +82,11 @@ export function SettingsPage(settingsPageViewModel: SettingsPageViewModel) {
<div class="flex-row width-input margin-bottom">
<input
aria-label={
translations.chatPage.settings
coreViewModel.translations.chatPage.settings
.newSecondaryChannelAudioLabel
}
placeholder={
translations.chatPage.settings
coreViewModel.translations.chatPage.settings
.newSecondaryChannelPlaceholder
}
bind:value={
@@ -88,7 +99,7 @@ export function SettingsPage(settingsPageViewModel: SettingsPageViewModel) {
<button
class="primary"
aria-label={
translations.chatPage.settings
coreViewModel.translations.chatPage.settings
.addSecondaryChannelButtonAudioLabel
}
on:click={
@@ -117,8 +128,8 @@ export function SettingsPage(settingsPageViewModel: SettingsPageViewModel) {
<div>
<span>
{
translations.chatPage.settings
.encryptionKeyLabel
coreViewModel.translations.chatPage
.settings.encryptionKeyLabel
}
</span>
<input
@@ -138,7 +149,7 @@ export function SettingsPage(settingsPageViewModel: SettingsPageViewModel) {
<button
class="width-50"
aria-label={
translations.chatPage.settings
coreViewModel.translations.chatPage.settings
.setEncryptionKeyButtonAudioLabel
}
on:click={
@@ -148,7 +159,7 @@ export function SettingsPage(settingsPageViewModel: SettingsPageViewModel) {
settingsPageViewModel.cannotSetEncryptionKey
}
>
{translations.general.setButton}
{coreViewModel.translations.general.setButton}
<span class="icon">check</span>
</button>
</div>
@@ -160,7 +171,10 @@ export function SettingsPage(settingsPageViewModel: SettingsPageViewModel) {
settingsPageViewModel.shouldShowEncryptionKey
}
></input>
{translations.chatPage.settings.showEncryptionKey}
{
coreViewModel.translations.chatPage.settings
.showEncryptionKey
}
</label>
<hr></hr>
@@ -171,7 +185,9 @@ export function SettingsPage(settingsPageViewModel: SettingsPageViewModel) {
<div class="width-input">
{DangerousActionButton(
translations.chatPage.settings.deleteChatButton,
coreViewModel,
coreViewModel.translations.chatPage.settings
.deleteChatButton,
"chat_error",
settingsPageViewModel.remove,
)}
+16 -7
View File
@@ -5,9 +5,12 @@ import * as React from "bloatless-react";
import { BoardPage } from "./boardPage";
import { BoardViewModelToEntry } from "../Components/boardEntry";
import TaskPageViewModel from "../../ViewModel/Pages/taskPageViewModel";
import { translations } from "../translations";
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
export function TaskPage(taskPageViewModel: TaskPageViewModel) {
export function TaskPage(
coreViewModel: CoreViewModel,
taskPageViewModel: TaskPageViewModel,
) {
taskPageViewModel.loadData();
const isShowingBoard = React.createProxyState(
@@ -23,7 +26,10 @@ export function TaskPage(taskPageViewModel: TaskPageViewModel) {
return (
<div class="pane align-center justify-center">
<span class="secondary">
{translations.chatPage.task.noBoardSelected}
{
coreViewModel.translations.chatPage.task
.noBoardSelected
}
</span>
</div>
);
@@ -34,13 +40,16 @@ export function TaskPage(taskPageViewModel: TaskPageViewModel) {
return (
<div class="pane align-center justify-center">
<span class="secondary">
{translations.chatPage.task.boardNotFound}
{
coreViewModel.translations.chatPage.task
.boardNotFound
}
</span>
</div>
);
}
return BoardPage(selectedBoard);
return BoardPage(coreViewModel, selectedBoard);
},
);
@@ -63,14 +72,14 @@ export function TaskPage(taskPageViewModel: TaskPageViewModel) {
bind:value={taskPageViewModel.newBoardNameInput}
on:enter={taskPageViewModel.createBoard}
placeholder={
translations.chatPage.task
coreViewModel.translations.chatPage.task
.newBoardNamePlaceholder
}
></input>
<button
class="primary"
aria-label={
translations.chatPage.task
coreViewModel.translations.chatPage.task
.createBoardButtonAudioLabel
}
on:click={taskPageViewModel.createBoard}
+8 -11
View File
@@ -3,10 +3,13 @@ import * as React from "bloatless-react";
import { ChatMessageInfoModal } from "../Modals/chatMessageInfoModal";
import { ChatMessageStatuses } from "../../Model/Chat/chatModel";
import ChatMessageViewModel from "../../ViewModel/Chat/chatMessageViewModel";
import { translations } from "../translations";
import { MessageReactionButtonRow } from "./messageReactionButtonRow";
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
export function ChatMessage(chatMessageViewModel: ChatMessageViewModel) {
export function ChatMessage(
coreViewModel: CoreViewModel,
chatMessageViewModel: ChatMessageViewModel,
) {
const statusIcon = React.createProxyState(
[chatMessageViewModel.status],
() => {
@@ -50,7 +53,7 @@ export function ChatMessage(chatMessageViewModel: ChatMessageViewModel) {
<button
on:click={chatMessageViewModel.showInfoModal}
aria-label={
translations.chatPage.message
coreViewModel.translations.chatPage.message
.showMessageInfoButtonAudioLabel
}
>
@@ -58,14 +61,8 @@ export function ChatMessage(chatMessageViewModel: ChatMessageViewModel) {
</button>
</div>
</div>
{MessageReactionButtonRow(chatMessageViewModel)}
{ChatMessageInfoModal(chatMessageViewModel)}
{MessageReactionButtonRow(coreViewModel, chatMessageViewModel)}
{ChatMessageInfoModal(coreViewModel, chatMessageViewModel)}
</div>
);
}
export const ChatMessageViewModelToView: React.StateItemConverter<
ChatMessageViewModel
> = (chatMessageViewModel: ChatMessageViewModel) => {
return ChatMessage(chatMessageViewModel);
};
@@ -1,8 +1,8 @@
import * as React from "bloatless-react";
import { translations } from "../translations";
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
export function DangerousActionButton(
coreViewModel: CoreViewModel,
label: string,
icon: string,
action: () => void,
@@ -23,7 +23,7 @@ export function DangerousActionButton(
return (
<div class="flex-row">
<button class="flex" on:click={abort} toggle:hidden={cannotConfirm}>
{translations.general.abortButton}
{coreViewModel.translations.general.abortButton}
<span class="icon">undo</span>
</button>
<button
@@ -39,7 +39,7 @@ export function DangerousActionButton(
on:click={action}
toggle:hidden={cannotConfirm}
>
{translations.general.confirmButton}
{coreViewModel.translations.general.confirmButton}
<span class="icon">warning</span>
</button>
</div>
+6 -3
View File
@@ -1,8 +1,8 @@
import * as React from "bloatless-react";
import { translations } from "../translations";
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
export function DeletableListItem(
coreViewModel: CoreViewModel,
text: string,
primaryButton: HTMLElement,
ondelete: () => void,
@@ -16,7 +16,10 @@ export function DeletableListItem(
<button
class="danger"
aria-label={translations.general.deleteItemButtonAudioLabel}
aria-label={
coreViewModel.translations.general
.deleteItemButtonAudioLabel
}
on:click={ondelete}
>
<span class="icon">delete</span>
+2 -1
View File
@@ -26,7 +26,8 @@ export function DirectoryItemList(
function loadItems() {
items.clear();
const directoryItems = storageViewModel.storageModel.list(path);
const directoryItems =
storageViewModel.coreViewModel.storageModel.list(path);
for (const directoryItem of directoryItems) {
const itemPath = [...path, directoryItem];
+15 -7
View File
@@ -4,9 +4,10 @@ import {
ReactionSymbols,
} from "../../Model/Chat/chatModel";
import ChatMessageViewModel from "../../ViewModel/Chat/chatMessageViewModel";
import { translations } from "../translations";
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
export function MessageReactionButton(
coreViewModel: CoreViewModel,
chatMessageViewModel: ChatMessageViewModel,
content: ReactionSymbols,
) {
@@ -31,37 +32,44 @@ export function MessageReactionButton(
switch (content) {
case ReactionSymbols.ThumbsUp: {
audioLabel = translations.chatPage.message.thumbsUpReaction;
audioLabel =
coreViewModel.translations.chatPage.message.thumbsUpReaction;
count = chatMessageViewModel.reactionsThumbsUpCount;
reactionState = chatMessageViewModel.reactionsThumbsUp;
break;
}
case ReactionSymbols.Check: {
audioLabel = translations.chatPage.message.checkReaction;
audioLabel =
coreViewModel.translations.chatPage.message.checkReaction;
count = chatMessageViewModel.reactionsCheckCount;
reactionState = chatMessageViewModel.reactionsCheck;
break;
}
case ReactionSymbols.Stop: {
audioLabel = translations.chatPage.message.stopReaction;
audioLabel =
coreViewModel.translations.chatPage.message.stopReaction;
count = chatMessageViewModel.reactionsStopCount;
reactionState = chatMessageViewModel.reactionsStop;
break;
}
case ReactionSymbols.Attention: {
audioLabel = translations.chatPage.message.attentionReaction;
audioLabel =
coreViewModel.translations.chatPage.message.attentionReaction;
count = chatMessageViewModel.reactionsAttentionCount;
reactionState = chatMessageViewModel.reactionsAttention;
break;
}
case ReactionSymbols.DoubleAttention: {
audioLabel = translations.chatPage.message.doubleAttentionReaction;
audioLabel =
coreViewModel.translations.chatPage.message
.doubleAttentionReaction;
count = chatMessageViewModel.reactionsDoubleAttentionCount;
reactionState = chatMessageViewModel.reactionsDoubleAttention;
break;
}
case ReactionSymbols.Question: {
audioLabel = translations.chatPage.message.questionReaction;
audioLabel =
coreViewModel.translations.chatPage.message.questionReaction;
count = chatMessageViewModel.reactionsQuestionCount;
reactionState = chatMessageViewModel.reactionsQuestion;
break;
@@ -1,29 +1,42 @@
import * as React from "bloatless-react";
import { ReactionSymbols } from "../../Model/Chat/chatModel";
import ChatMessageViewModel from "../../ViewModel/Chat/chatMessageViewModel";
import { translations } from "../translations";
import { MessageReactionButton } from "./messageReactionButton";
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
export function MessageReactionButtonRow(
coreViewModel: CoreViewModel,
chatMessageViewModel: ChatMessageViewModel,
) {
return (
<div class="grid gap width-100 message-reaction-row">
{MessageReactionButton(
coreViewModel,
chatMessageViewModel,
ReactionSymbols.ThumbsUp,
)}
{MessageReactionButton(chatMessageViewModel, ReactionSymbols.Check)}
{MessageReactionButton(chatMessageViewModel, ReactionSymbols.Stop)}
{MessageReactionButton(
coreViewModel,
chatMessageViewModel,
ReactionSymbols.Check,
)}
{MessageReactionButton(
coreViewModel,
chatMessageViewModel,
ReactionSymbols.Stop,
)}
{MessageReactionButton(
coreViewModel,
chatMessageViewModel,
ReactionSymbols.Attention,
)}
{MessageReactionButton(
coreViewModel,
chatMessageViewModel,
ReactionSymbols.DoubleAttention,
)}
{MessageReactionButton(
coreViewModel,
chatMessageViewModel,
ReactionSymbols.Question,
)}
+7 -2
View File
@@ -3,11 +3,12 @@ import "./monthGrid.css";
import * as React from "bloatless-react";
import { MonthGrid } from "../../Model/Files/calendarModel";
import TaskViewModel from "../../ViewModel/Pages/taskViewModel";
import { translations } from "../translations";
import { allowDrop } from "../utility";
import { localeCompare } from "../../Model/Utility/utility";
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
export function MonthGrid<T>(
coreViewModel: CoreViewModel,
monthGrid: MonthGrid<React.MapState<T>>,
selectedDate: React.State<number>,
handleDrop: (date: string) => void,
@@ -17,7 +18,11 @@ export function MonthGrid<T>(
while (dayLabels.length < 7) {
dayLabels.push(
<span class="secondary">
{translations.regional.weekdays.abbreviated[currentWeekday]}
{
coreViewModel.translations.regional.weekdays.abbreviated[
currentWeekday
]
}
</span>,
);
currentWeekday++;
+19 -6
View File
@@ -3,9 +3,12 @@ import * as React from "bloatless-react";
import BoardViewModel from "../../ViewModel/Pages/boardViewModel";
import { ColorPicker } from "../Components/colorPicker";
import { DangerousActionButton } from "../Components/dangerousActionButton";
import { translations } from "../translations";
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
export function BoardSettingsModal(boardViewModel: BoardViewModel) {
export function BoardSettingsModal(
coreViewModel: CoreViewModel,
boardViewModel: BoardViewModel,
) {
return (
<div
class="modal"
@@ -13,13 +16,21 @@ export function BoardSettingsModal(boardViewModel: BoardViewModel) {
>
<div>
<main>
<h2>{translations.chatPage.task.boardSettingsHeadline}</h2>
<h2>
{
coreViewModel.translations.chatPage.task
.boardSettingsHeadline
}
</h2>
<label class="tile flex-no">
<span class="icon">label</span>
<div>
<span>
{translations.chatPage.task.boardNameInputLabel}
{
coreViewModel.translations.chatPage.task
.boardNameInputLabel
}
</span>
<input
on:enter={boardViewModel.saveSettings}
@@ -36,14 +47,16 @@ export function BoardSettingsModal(boardViewModel: BoardViewModel) {
<div class="width-input">
{DangerousActionButton(
translations.chatPage.task.deleteBoardButton,
coreViewModel,
coreViewModel.translations.chatPage.task
.deleteBoardButton,
"delete_forever",
boardViewModel.deleteBoard,
)}
</div>
</main>
<button on:click={boardViewModel.hideSettings}>
{translations.general.closeButton}
{coreViewModel.translations.general.closeButton}
<span class="icon">close</span>
</button>
</div>
+31 -11
View File
@@ -1,11 +1,12 @@
import * as React from "bloatless-react";
import ChatMessageViewModel from "../../ViewModel/Chat/chatMessageViewModel";
import { translations } from "../translations";
import { MessageReactionButtonRow } from "../Components/messageReactionButtonRow";
import { InfoTile } from "../Components/infoTile";
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
export function ChatMessageInfoModal(
coreViewModel: CoreViewModel,
chatMessageViewModel: ChatMessageViewModel,
) {
return (
@@ -15,27 +16,34 @@ export function ChatMessageInfoModal(
>
<div>
<main>
<h2>{translations.chatPage.message.messageInfoHeadline}</h2>
<h2>
{
coreViewModel.translations.chatPage.message
.messageInfoHeadline
}
</h2>
<div class="flex-column gap">
{InfoTile(
"account_circle",
translations.chatPage.message.sentBy,
coreViewModel.translations.chatPage.message.sentBy,
chatMessageViewModel.sender,
)}
{InfoTile(
"schedule",
translations.chatPage.message.timeSent,
coreViewModel.translations.chatPage.message
.timeSent,
chatMessageViewModel.dateSent,
)}
{InfoTile(
"forum",
translations.chatPage.message.channel,
coreViewModel.translations.chatPage.message.channel,
chatMessageViewModel.channel,
)}
{InfoTile(
"description",
translations.chatPage.message.messageContent,
coreViewModel.translations.chatPage.message
.messageContent,
chatMessageViewModel.body,
)}
</div>
@@ -44,25 +52,37 @@ export function ChatMessageInfoModal(
<div class="flex-column gap">
<button on:click={chatMessageViewModel.copyMessage}>
{translations.chatPage.message.copyMessageButton}
{
coreViewModel.translations.chatPage.message
.copyMessageButton
}
<span class="icon">content_copy</span>
</button>
<button on:click={chatMessageViewModel.resendMessage}>
{translations.chatPage.message.resendMessageButton}
{
coreViewModel.translations.chatPage.message
.resendMessageButton
}
<span class="icon">redo</span>
</button>
<button on:click={chatMessageViewModel.decryptMessage}>
{translations.chatPage.message.decryptMessageButton}
{
coreViewModel.translations.chatPage.message
.decryptMessageButton
}
<span class="icon">key</span>
</button>
</div>
<hr></hr>
{MessageReactionButtonRow(chatMessageViewModel)}
{MessageReactionButtonRow(
coreViewModel,
chatMessageViewModel,
)}
</main>
<button on:click={chatMessageViewModel.hideInfoModal}>
{translations.general.closeButton}
{coreViewModel.translations.general.closeButton}
<span class="icon">close</span>
</button>
</div>
+15 -6
View File
@@ -2,9 +2,12 @@ import * as React from "bloatless-react";
import ConnectionViewModel from "../../ViewModel/Global/connectionViewModel";
import { DeletableListItem } from "../Components/deletableListItem";
import { translations } from "../translations";
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
export function ConnectionModal(connectionViewModel: ConnectionViewModel) {
export function ConnectionModal(
coreViewModel: CoreViewModel,
connectionViewModel: ConnectionViewModel,
) {
const previousAddressConverter: React.StateItemConverter<string> = (
address: string,
) => {
@@ -16,17 +19,20 @@ export function ConnectionModal(connectionViewModel: ConnectionViewModel) {
[connectionViewModel.isConnected],
() =>
connectionViewModel.isConnected.value == true &&
connectionViewModel.connectionModel.address == address,
connectionViewModel.coreViewModel.connectionModel.address ==
address,
);
return DeletableListItem(
coreViewModel,
address,
<button
class="primary"
on:click={connnect}
toggle:disabled={cannotConnect}
aria-label={
translations.connectionModal.connectButtonAudioLabel
coreViewModel.translations.connectionModal
.connectButtonAudioLabel
}
>
<span class="icon">link</span>
@@ -45,7 +51,10 @@ export function ConnectionModal(connectionViewModel: ConnectionViewModel) {
<div>
<main>
<h2>
{translations.connectionModal.connectionModalHeadline}
{
coreViewModel.translations.connectionModal
.connectionModalHeadline
}
</h2>
<div
@@ -57,7 +66,7 @@ export function ConnectionModal(connectionViewModel: ConnectionViewModel) {
></div>
</main>
<button on:click={connectionViewModel.hideConnectionModal}>
{translations.general.closeButton}
{coreViewModel.translations.general.closeButton}
<span class="icon">close</span>
</button>
</div>
+104 -39
View File
@@ -9,28 +9,31 @@ import ConnectionViewModel from "../../ViewModel/Global/connectionViewModel";
import StorageModel from "../../Model/Global/storageModel";
import { StringToTextSpan } from "../Components/textSpan";
import { reload } from "../utility";
import { translations } from "../translations";
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
export function DataTransferModalWrapper(
coreViewModel: CoreViewModel,
connectionViewModel: ConnectionViewModel,
fileTransferViewModel: FileTransferViewModel,
) {
return (
<div>
{DirectionSelectionModal(
coreViewModel,
connectionViewModel,
fileTransferViewModel,
)}
{FileSelectionModal(fileTransferViewModel)}
{TransferDataDisplayModal(fileTransferViewModel)}
{TransferDisplayModal(fileTransferViewModel)}
{TransferDataInputModal(fileTransferViewModel)}
{DataReceptionModal(fileTransferViewModel)}
{FileSelectionModal(coreViewModel, fileTransferViewModel)}
{TransferDataDisplayModal(coreViewModel, fileTransferViewModel)}
{TransferDisplayModal(coreViewModel, fileTransferViewModel)}
{TransferDataInputModal(coreViewModel, fileTransferViewModel)}
{DataReceptionModal(coreViewModel, fileTransferViewModel)}
</div>
);
}
function DirectionSelectionModal(
coreViewModel: CoreViewModel,
connectionViewModel: ConnectionViewModel,
fileTransferViewModel: FileTransferViewModel,
) {
@@ -51,14 +54,20 @@ function DirectionSelectionModal(
<div>
<main>
<h2>
{translations.dataTransferModal.transferDataHeadline}
{
coreViewModel.translations.dataTransferModal
.transferDataHeadline
}
</h2>
<p
class="error"
toggle:hidden={connectionViewModel.isConnected}
>
{translations.dataTransferModal.notConnectedError}
{
coreViewModel.translations.dataTransferModal
.notConnectedError
}
</p>
<div
@@ -75,7 +84,8 @@ function DirectionSelectionModal(
<div>
<b>
{
translations.dataTransferModal
coreViewModel.translations
.dataTransferModal
.fromThisDeviceButton
}
</b>
@@ -92,7 +102,8 @@ function DirectionSelectionModal(
<div>
<b>
{
translations.dataTransferModal
coreViewModel.translations
.dataTransferModal
.toThisDeviceButton
}
</b>
@@ -102,7 +113,7 @@ function DirectionSelectionModal(
</div>
</main>
<button on:click={fileTransferViewModel.hideModal}>
{translations.general.closeButton}
{coreViewModel.translations.general.closeButton}
<span class="icon">close</span>
</button>
</div>
@@ -110,7 +121,10 @@ function DirectionSelectionModal(
);
}
function FileSelectionModal(fileTransferViewModel: FileTransferViewModel) {
function FileSelectionModal(
coreViewModel: CoreViewModel,
fileTransferViewModel: FileTransferViewModel,
) {
// option
const OptionConverter: React.StateItemConverter<FileTransferOption> = (
fileOption: FileTransferOption,
@@ -164,15 +178,26 @@ function FileSelectionModal(fileTransferViewModel: FileTransferViewModel) {
<div>
<main>
<h2>
{translations.dataTransferModal.transferDataHeadline}
{
coreViewModel.translations.dataTransferModal
.transferDataHeadline
}
</h2>
<span class="secondary">
{translations.dataTransferModal.selectionDescription}
{
coreViewModel.translations.dataTransferModal
.selectionDescription
}
</span>
<hr></hr>
<h3>{translations.dataTransferModal.generalHeadline}</h3>
<h3>
{
coreViewModel.translations.dataTransferModal
.generalHeadline
}
</h3>
<div
class="flex-column gap content-margin-bottom"
children:append={[
@@ -181,7 +206,12 @@ function FileSelectionModal(fileTransferViewModel: FileTransferViewModel) {
]}
></div>
<h3>{translations.dataTransferModal.chatsHeadline}</h3>
<h3>
{
coreViewModel.translations.dataTransferModal
.chatsHeadline
}
</h3>
<div
class="flex-column gap"
children:append={[
@@ -197,7 +227,7 @@ function FileSelectionModal(fileTransferViewModel: FileTransferViewModel) {
fileTransferViewModel.showDirectionSelectionModal
}
>
{translations.general.backButton}
{coreViewModel.translations.general.backButton}
</button>
<button
class="primary flex"
@@ -206,7 +236,7 @@ function FileSelectionModal(fileTransferViewModel: FileTransferViewModel) {
fileTransferViewModel.hasNoPathsSelected
}
>
{translations.general.continueButton}
{coreViewModel.translations.general.continueButton}
<span class="icon">arrow_forward</span>
</button>
</div>
@@ -216,6 +246,7 @@ function FileSelectionModal(fileTransferViewModel: FileTransferViewModel) {
}
function TransferDataDisplayModal(
coreViewModel: CoreViewModel,
fileTransferViewModel: FileTransferViewModel,
) {
const isPresented = React.createProxyState(
@@ -230,11 +261,17 @@ function TransferDataDisplayModal(
<div>
<main>
<h2>
{translations.dataTransferModal.transferDataHeadline}
{
coreViewModel.translations.dataTransferModal
.transferDataHeadline
}
</h2>
<span class="secondary">
{translations.dataTransferModal.dataEntryDescription}
{
coreViewModel.translations.dataTransferModal
.dataEntryDescription
}
</span>
<hr></hr>
@@ -245,7 +282,8 @@ function TransferDataDisplayModal(
<div>
<span class="secondary">
{
translations.dataTransferModal
coreViewModel.translations
.dataTransferModal
.transferChannelHeadline
}
</span>
@@ -261,7 +299,8 @@ function TransferDataDisplayModal(
<div>
<span class="secondary">
{
translations.dataTransferModal
coreViewModel.translations
.dataTransferModal
.transferKeyHeadline
}
</span>
@@ -279,10 +318,10 @@ function TransferDataDisplayModal(
class="flex"
on:click={fileTransferViewModel.showFileSelectionModal}
>
{translations.general.backButton}
{coreViewModel.translations.general.backButton}
</button>
<button disabled class="flex">
{translations.general.waitingLabel}
{coreViewModel.translations.general.waitingLabel}
</button>
</div>
</div>
@@ -290,7 +329,10 @@ function TransferDataDisplayModal(
);
}
function TransferDisplayModal(fileTransferViewModel: FileTransferViewModel) {
function TransferDisplayModal(
coreViewModel: CoreViewModel,
fileTransferViewModel: FileTransferViewModel,
) {
const isPresented = React.createProxyState(
[fileTransferViewModel.presentedModal],
() =>
@@ -303,7 +345,10 @@ function TransferDisplayModal(fileTransferViewModel: FileTransferViewModel) {
<div>
<main>
<h2>
{translations.dataTransferModal.transferDataHeadline}
{
coreViewModel.translations.dataTransferModal
.transferDataHeadline
}
</h2>
<p
@@ -319,7 +364,10 @@ function TransferDisplayModal(fileTransferViewModel: FileTransferViewModel) {
fileTransferViewModel.didNotFinishSending
}
>
{translations.dataTransferModal.allFilesSent}
{
coreViewModel.translations.dataTransferModal
.allFilesSent
}
</p>
<hr></hr>
@@ -337,7 +385,10 @@ function TransferDisplayModal(fileTransferViewModel: FileTransferViewModel) {
class="flex"
on:click={fileTransferViewModel.initiateTransfer}
>
{translations.dataTransferModal.sendAgainButton}
{
coreViewModel.translations.dataTransferModal
.sendAgainButton
}
<span class="icon">restart_alt</span>
</button>
<button
@@ -347,7 +398,7 @@ function TransferDisplayModal(fileTransferViewModel: FileTransferViewModel) {
fileTransferViewModel.didNotFinishSending
}
>
{translations.general.closeButton}
{coreViewModel.translations.general.closeButton}
<span class="icon">close</span>
</button>
</div>
@@ -356,7 +407,10 @@ function TransferDisplayModal(fileTransferViewModel: FileTransferViewModel) {
);
}
function TransferDataInputModal(fileTransferViewModel: FileTransferViewModel) {
function TransferDataInputModal(
coreViewModel: CoreViewModel,
fileTransferViewModel: FileTransferViewModel,
) {
const isPresented = React.createProxyState(
[fileTransferViewModel.presentedModal],
() =>
@@ -369,12 +423,15 @@ function TransferDataInputModal(fileTransferViewModel: FileTransferViewModel) {
<div>
<main>
<h2>
{translations.dataTransferModal.transferDataHeadline}
{
coreViewModel.translations.dataTransferModal
.transferDataHeadline
}
</h2>
<span class="secondary">
{
translations.dataTransferModal
coreViewModel.translations.dataTransferModal
.dataEntryInputDescription
}
</span>
@@ -387,7 +444,8 @@ function TransferDataInputModal(fileTransferViewModel: FileTransferViewModel) {
<div>
<span class="secondary">
{
translations.dataTransferModal
coreViewModel.translations
.dataTransferModal
.transferChannelHeadline
}
</span>
@@ -403,7 +461,8 @@ function TransferDataInputModal(fileTransferViewModel: FileTransferViewModel) {
<div>
<span class="secondary">
{
translations.dataTransferModal
coreViewModel.translations
.dataTransferModal
.transferKeyHeadline
}
</span>
@@ -423,7 +482,7 @@ function TransferDataInputModal(fileTransferViewModel: FileTransferViewModel) {
fileTransferViewModel.showDirectionSelectionModal
}
>
{translations.general.backButton}
{coreViewModel.translations.general.backButton}
</button>
<button
class="primary flex"
@@ -432,7 +491,7 @@ function TransferDataInputModal(fileTransferViewModel: FileTransferViewModel) {
fileTransferViewModel.cannotPrepareToReceive
}
>
{translations.general.continueButton}
{coreViewModel.translations.general.continueButton}
<span class="icon">arrow_forward</span>
</button>
</div>
@@ -441,7 +500,10 @@ function TransferDataInputModal(fileTransferViewModel: FileTransferViewModel) {
);
}
function DataReceptionModal(fileTransferViewModel: FileTransferViewModel) {
function DataReceptionModal(
coreViewModel: CoreViewModel,
fileTransferViewModel: FileTransferViewModel,
) {
const isPresented = React.createProxyState(
[fileTransferViewModel.presentedModal],
() =>
@@ -454,7 +516,10 @@ function DataReceptionModal(fileTransferViewModel: FileTransferViewModel) {
<div>
<main>
<h2>
{translations.dataTransferModal.transferDataHeadline}
{
coreViewModel.translations.dataTransferModal
.transferDataHeadline
}
</h2>
<p
@@ -475,7 +540,7 @@ function DataReceptionModal(fileTransferViewModel: FileTransferViewModel) {
></div>
</main>
<button on:click={reload}>
{translations.general.reloadAppButton}
{coreViewModel.translations.general.reloadAppButton}
<span class="icon">refresh</span>
</button>
</div>
+8 -4
View File
@@ -2,10 +2,11 @@ import * as React from "bloatless-react";
import SearchViewModel from "../../ViewModel/Utility/searchViewModel";
import { StringToOption } from "../Components/option";
import { translations } from "../translations";
import { v4 } from "uuid";
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
export function SearchModal<T>(
coreViewModel: CoreViewModel,
searchViewModel: SearchViewModel<T>,
headline: string,
converter: React.StateItemConverter<T>,
@@ -24,7 +25,9 @@ export function SearchModal<T>(
<h2>{headline}</h2>
<div class="flex-row width-input">
<input
placeholder={translations.general.searchLabel}
placeholder={
coreViewModel.translations.general.searchLabel
}
bind:value={searchViewModel.searchInput}
on:enter={searchViewModel.applySearch}
list={suggestionId}
@@ -40,7 +43,8 @@ export function SearchModal<T>(
<button
class="primary"
aria-label={
translations.general.searchButtonAudioLabel
coreViewModel.translations.general
.searchButtonAudioLabel
}
on:click={searchViewModel.applySearch}
toggle:disabled={searchViewModel.cannotApplySearch}
@@ -61,7 +65,7 @@ export function SearchModal<T>(
></div>
</main>
<button on:click={close}>
{translations.general.closeButton}
{coreViewModel.translations.general.closeButton}
<span class="icon">close</span>
</button>
</div>
+59 -20
View File
@@ -1,14 +1,18 @@
import * as React from "bloatless-react";
import { translations } from "../translations";
import { Languages } from "../translations";
import SettingsViewModel, {
SettingsModalPages,
} from "../../ViewModel/Global/settingsViewModel";
import { SplitModal } from "../Components/splitModal";
import { InfoTile } from "../Components/infoTile";
import { Option } from "../Components/option";
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
export function SettingsModal(settingsViewModel: SettingsViewModel) {
export function SettingsModal(
coreViewModel: CoreViewModel,
settingsViewModel: SettingsViewModel,
) {
const detailView = React.createProxyState(
[settingsViewModel.selectedModalPage],
() => {
@@ -16,9 +20,12 @@ export function SettingsModal(settingsViewModel: SettingsViewModel) {
case SettingsModalPages.Appearance:
return <div>Appearance</div>;
case SettingsModalPages.Regional:
return SettingsRegionalPane(settingsViewModel);
return SettingsRegionalPane(
coreViewModel,
settingsViewModel,
);
case SettingsModalPages.Info:
return SettingsInfoPane(settingsViewModel);
return SettingsInfoPane(coreViewModel, settingsViewModel);
}
},
);
@@ -31,7 +38,9 @@ export function SettingsModal(settingsViewModel: SettingsViewModel) {
<div>
<main class="padding-0">
{SplitModal(
new React.State(SettingsLeftPane(settingsViewModel)),
new React.State(
SettingsLeftPane(coreViewModel, settingsViewModel),
),
detailView,
new React.State(""),
false,
@@ -39,7 +48,7 @@ export function SettingsModal(settingsViewModel: SettingsViewModel) {
)}
</main>
<button on:click={settingsViewModel.hideSettingsModal}>
{translations.general.closeButton}
{coreViewModel.translations.general.closeButton}
<span class="icon">close</span>
</button>
</div>
@@ -47,23 +56,26 @@ export function SettingsModal(settingsViewModel: SettingsViewModel) {
);
}
function SettingsLeftPane(settingsViewModel: SettingsViewModel) {
function SettingsLeftPane(
coreViewModel: CoreViewModel,
settingsViewModel: SettingsViewModel,
) {
return (
<div class="flex-column gap">
{SettingsPaneButton(
settingsViewModel,
SettingsModalPages.Appearance,
translations.settings.pages.appearance,
coreViewModel.translations.settings.pages.appearance,
)}
{SettingsPaneButton(
settingsViewModel,
SettingsModalPages.Regional,
translations.settings.pages.regional,
coreViewModel.translations.settings.pages.regional,
)}
{SettingsPaneButton(
settingsViewModel,
SettingsModalPages.Info,
translations.settings.pages.info,
coreViewModel.translations.settings.pages.info,
)}
</div>
);
@@ -89,15 +101,18 @@ function SettingsPaneButton(
);
}
function SettingsInfoPane(settingsViewModel: SettingsViewModel) {
function SettingsInfoPane(
coreViewModel: CoreViewModel,
settingsViewModel: SettingsViewModel,
) {
return (
<div class="slide-up">
<h2>{translations.homePage.appName}</h2>
<h2>{coreViewModel.translations.homePage.appName}</h2>
<hr></hr>
<div class="flex-column gap">
{InfoTile(
"build",
translations.settings.version,
coreViewModel.translations.settings.version,
settingsViewModel.coreViewModel.BUILD,
)}
</div>
@@ -105,30 +120,54 @@ function SettingsInfoPane(settingsViewModel: SettingsViewModel) {
);
}
function SettingsRegionalPane(settingsViewModel: SettingsViewModel) {
function SettingsRegionalPane(
coreViewModel: CoreViewModel,
settingsViewModel: SettingsViewModel,
) {
return (
<div class="slide-up">
<h2>{translations.settings.pages.regional}</h2>
<h2>{coreViewModel.translations.settings.pages.regional}</h2>
<hr></hr>
<label class="tile flex-no">
<span class="icon">calendar_month</span>
<div>
<span>{translations.homePage.firstDayOfWeekLabel}</span>
<select bind:value={settingsViewModel.firstDayOfWeekInput}>
{...translations.regional.weekdays.full.map(
<span>
{
coreViewModel.translations.settings
.firstDayOfWeekLabel
}
</span>
<select bind:value={settingsViewModel.firstDayOfWeek}>
{...coreViewModel.translations.regional.weekdays.full.map(
(weekdayName, i) =>
Option(
weekdayName,
i.toString(),
i.toString() ==
settingsViewModel.firstDayOfWeekInput
.value,
settingsViewModel.firstDayOfWeek.value,
),
)}
</select>
<span class="icon">arrow_drop_down</span>
</div>
</label>
<label class="tile flex-no">
<span class="icon">language</span>
<div>
<span>{coreViewModel.translations.settings.language}</span>
<select bind:value={settingsViewModel.language}>
{...[...Object.values(Languages)].map((language, i) =>
Option(
language,
i.toString(),
i.toString() ==
settingsViewModel.language.value,
),
)}
</select>
<span class="icon">arrow_drop_down</span>
</div>
</label>
</div>
);
}
+13 -8
View File
@@ -2,13 +2,16 @@ import * as React from "bloatless-react";
import { PATH_COMPONENT_SEPARATOR } from "../../Model/Global/storageModel";
import StorageViewModel from "../../ViewModel/Global/storageViewModel";
import { translations } from "../translations";
import { SplitModal } from "../Components/splitModal";
import { DangerousActionButton } from "../Components/dangerousActionButton";
import { DirectoryItemList } from "../Components/directoryItemList";
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
export function StorageModal(storageViewModel: StorageViewModel) {
export function StorageModal(
coreViewModel: CoreViewModel,
storageViewModel: StorageViewModel,
) {
const detailView = React.createProxyState(
[storageViewModel.selectedPath],
() => {
@@ -16,13 +19,14 @@ export function StorageModal(storageViewModel: StorageViewModel) {
return (
<div>
<span class="secondary">
{translations.storage.noItemSelected}
{coreViewModel.translations.storage.noItemSelected}
</span>
<hr></hr>
{DangerousActionButton(
translations.storage.removeJunkButton,
coreViewModel,
coreViewModel.translations.storage.removeJunkButton,
"delete_forever",
storageViewModel.removeJunk,
)}
@@ -33,7 +37,7 @@ export function StorageModal(storageViewModel: StorageViewModel) {
<div class="flex-column gap">
<div class="tile flex-no">
<div>
<b>{translations.storage.path}</b>
<b>{coreViewModel.translations.storage.path}</b>
<span
class="break-all"
subscribe:innerText={
@@ -44,7 +48,7 @@ export function StorageModal(storageViewModel: StorageViewModel) {
</div>
<div class="tile flex-no">
<div>
<b>{translations.storage.content}</b>
<b>{coreViewModel.translations.storage.content}</b>
<code
subscribe:innerText={
storageViewModel.selectedFileContent
@@ -54,7 +58,8 @@ export function StorageModal(storageViewModel: StorageViewModel) {
</div>
{DangerousActionButton(
translations.storage.deleteItem,
coreViewModel,
coreViewModel.translations.storage.deleteItem,
"delete_forever",
storageViewModel.deleteSelectedItem,
)}
@@ -74,7 +79,7 @@ export function StorageModal(storageViewModel: StorageViewModel) {
)}
</main>
<button on:click={storageViewModel.hideStorageModal}>
{translations.general.closeButton}
{coreViewModel.translations.general.closeButton}
<span class="icon">close</span>
</button>
</div>
+51 -16
View File
@@ -2,7 +2,6 @@ import * as React from "bloatless-react";
import {
Entry,
EntryToOption,
Option,
StringToOption,
VersionIdToOption,
@@ -10,10 +9,13 @@ import {
import { DangerousActionButton } from "../Components/dangerousActionButton";
import TaskViewModel from "../../ViewModel/Pages/taskViewModel";
import { translations } from "../translations";
import { v4 } from "uuid";
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
export function TaskSettingsModal(taskViewModel: TaskViewModel) {
export function TaskSettingsModal(
coreViewModel: CoreViewModel,
taskViewModel: TaskViewModel,
) {
const categorySuggestionId = v4();
const statusSuggestionId = v4();
@@ -28,12 +30,22 @@ export function TaskSettingsModal(taskViewModel: TaskViewModel) {
<div class="modal" open keystroke:s={taskViewModel.closeAndSave}>
<div>
<main>
<h2>{translations.chatPage.task.taskSettingsHeadline}</h2>
<h2>
{
coreViewModel.translations.chatPage.task
.taskSettingsHeadline
}
</h2>
<label class="tile flex-no">
<span class="icon">history</span>
<div>
<span>{translations.general.fileVersionLabel}</span>
<span>
{
coreViewModel.translations.general
.fileVersionLabel
}
</span>
<select
bind:value={taskViewModel.selectedVersionId}
children:append={[
@@ -51,7 +63,10 @@ export function TaskSettingsModal(taskViewModel: TaskViewModel) {
<span class="icon">label</span>
<div>
<span>
{translations.chatPage.task.taskNameLabel}
{
coreViewModel.translations.chatPage.task
.taskNameLabel
}
</span>
<input
bind:value={taskViewModel.name}
@@ -64,7 +79,10 @@ export function TaskSettingsModal(taskViewModel: TaskViewModel) {
<span class="icon">category</span>
<div>
<span>
{translations.chatPage.task.taskBoardLabel}
{
coreViewModel.translations.chatPage.task
.taskBoardLabel
}
</span>
<select
bind:value={taskViewModel.boardId}
@@ -83,7 +101,7 @@ export function TaskSettingsModal(taskViewModel: TaskViewModel) {
<div>
<span>
{
translations.chatPage.task
coreViewModel.translations.chatPage.task
.taskDescriptionLabel
}
</span>
@@ -100,7 +118,10 @@ export function TaskSettingsModal(taskViewModel: TaskViewModel) {
<span class="icon">category</span>
<div>
<span>
{translations.chatPage.task.taskCategoryLabel}
{
coreViewModel.translations.chatPage.task
.taskCategoryLabel
}
</span>
<input
bind:value={taskViewModel.category}
@@ -121,7 +142,10 @@ export function TaskSettingsModal(taskViewModel: TaskViewModel) {
<span class="icon">clock_loader_40</span>
<div>
<span>
{translations.chatPage.task.taskStatusLabel}
{
coreViewModel.translations.chatPage.task
.taskStatusLabel
}
</span>
<input
bind:value={taskViewModel.status}
@@ -142,7 +166,10 @@ export function TaskSettingsModal(taskViewModel: TaskViewModel) {
<span class="icon">priority_high</span>
<div>
<span>
{translations.chatPage.task.taskPriorityLabel}
{
coreViewModel.translations.chatPage.task
.taskPriorityLabel
}
</span>
<input
type="number"
@@ -157,7 +184,10 @@ export function TaskSettingsModal(taskViewModel: TaskViewModel) {
<span class="icon">calendar_month</span>
<div>
<span>
{translations.chatPage.task.taskDateLabel}
{
coreViewModel.translations.chatPage.task
.taskDateLabel
}
</span>
<input
type="date"
@@ -170,7 +200,10 @@ export function TaskSettingsModal(taskViewModel: TaskViewModel) {
<span class="icon">schedule</span>
<div>
<span>
{translations.chatPage.task.taskTimeLabel}
{
coreViewModel.translations.chatPage.task
.taskTimeLabel
}
</span>
<input
type="time"
@@ -183,7 +216,9 @@ export function TaskSettingsModal(taskViewModel: TaskViewModel) {
<div class="width-input">
{DangerousActionButton(
translations.chatPage.task.deleteTaskButton,
coreViewModel,
coreViewModel.translations.chatPage.task
.deleteTaskButton,
"delete_forever",
taskViewModel.deleteTask,
)}
@@ -194,13 +229,13 @@ export function TaskSettingsModal(taskViewModel: TaskViewModel) {
class="flex"
on:click={taskViewModel.closeAndDiscard}
>
{translations.general.closeButton}
{coreViewModel.translations.general.closeButton}
</button>
<button
class="flex primary"
on:click={taskViewModel.closeAndSave}
>
{translations.general.saveButton}
{coreViewModel.translations.general.saveButton}
<span class="icon">save</span>
</button>
</div>
+32 -12
View File
@@ -9,9 +9,12 @@ import { ChatViewToggleButton } from "./Components/chatViewToggleButton";
import { MessagePage } from "./ChatPages/messagePage";
import { SettingsPage } from "./ChatPages/settingsPage";
import { TaskPage } from "./ChatPages/taskPage";
import { translations } from "./translations";
import CoreViewModel from "../ViewModel/Global/coreViewModel";
export function ChatPage(chatViewModel: ChatViewModel) {
export function ChatPage(
coreViewModel: CoreViewModel,
chatViewModel: ChatViewModel,
) {
const mainContent = React.createProxyState(
[chatViewModel.selectedPage],
() => {
@@ -19,16 +22,28 @@ export function ChatPage(chatViewModel: ChatViewModel) {
switch (chatViewModel.selectedPage.value) {
case ChatPageTypes.Settings: {
return SettingsPage(chatViewModel.settingsPageViewModel);
return SettingsPage(
coreViewModel,
chatViewModel.settingsPageViewModel,
);
}
case ChatPageTypes.Tasks: {
return TaskPage(chatViewModel.taskPageViewModel);
return TaskPage(
coreViewModel,
chatViewModel.taskPageViewModel,
);
}
case ChatPageTypes.Calendar: {
return CalendarPage(chatViewModel.calendarViewModel);
return CalendarPage(
coreViewModel,
chatViewModel.calendarViewModel,
);
}
default: {
return MessagePage(chatViewModel.messagePageViewModel);
return MessagePage(
coreViewModel,
chatViewModel.messagePageViewModel,
);
}
}
},
@@ -63,14 +78,19 @@ export function ChatPage(chatViewModel: ChatViewModel) {
<div id="ribbon">
<button
class="ghost"
aria-label={translations.chatPage.closeChatAudioLabe}
aria-label={
coreViewModel.translations.chatPage
.closeChatAudioLabe
}
on:click={chatViewModel.close}
>
<span class="icon">close</span>
</button>
<button
class="danger"
aria-label={translations.general.restoreConnection}
aria-label={
coreViewModel.translations.general.restoreConnection
}
on:click={
chatViewModel.connectionViewModel
.showConnectionModal
@@ -86,25 +106,25 @@ export function ChatPage(chatViewModel: ChatViewModel) {
<span class="navigation-buttons">
{ChatViewToggleButton(
translations.chatPage.pages.calendar,
coreViewModel.translations.chatPage.pages.calendar,
"calendar_month",
ChatPageTypes.Calendar,
chatViewModel,
)}
{ChatViewToggleButton(
translations.chatPage.pages.tasks,
coreViewModel.translations.chatPage.pages.tasks,
"task_alt",
ChatPageTypes.Tasks,
chatViewModel,
)}
{ChatViewToggleButton(
translations.chatPage.pages.messages,
coreViewModel.translations.chatPage.pages.messages,
"forum",
ChatPageTypes.Messages,
chatViewModel,
)}
{ChatViewToggleButton(
translations.chatPage.pages.settings,
coreViewModel.translations.chatPage.pages.settings,
"settings",
ChatPageTypes.Settings,
chatViewModel,
+9 -2
View File
@@ -4,15 +4,22 @@ import * as React from "bloatless-react";
import ChatListViewModel from "../ViewModel/Chat/chatListViewModel";
import { ChatPage } from "./chatPage";
import CoreViewModel from "../ViewModel/Global/coreViewModel";
export function ChatPageWrapper(chatListViewModel: ChatListViewModel) {
export function ChatPageWrapper(
coreViewModel: CoreViewModel,
chatListViewModel: ChatListViewModel,
) {
const chatPageContent = React.createProxyState(
[chatListViewModel.selectedChat],
() => {
if (chatListViewModel.selectedChat.value == undefined) {
return <div></div>;
} else {
return ChatPage(chatListViewModel.selectedChat.value);
return ChatPage(
coreViewModel,
chatListViewModel.selectedChat.value,
);
}
},
);
+41 -20
View File
@@ -10,12 +10,11 @@ import ConnectionViewModel from "../ViewModel/Global/connectionViewModel";
import FileTransferViewModel from "../ViewModel/Global/fileTransferViewModel";
import SettingsViewModel from "../ViewModel/Global/settingsViewModel";
import StorageViewModel from "../ViewModel/Global/storageViewModel";
import { translations } from "./translations";
import CoreViewModel from "../ViewModel/Global/coreViewModel";
import { HomePageButton } from "./Components/homePageButton";
export function HomePage(
coreVieWModel: CoreViewModel,
coreViewModel: CoreViewModel,
storageViewModel: StorageViewModel,
settingsViewModel: SettingsViewModel,
connectionViewModel: ConnectionViewModel,
@@ -25,16 +24,19 @@ export function HomePage(
// sections
const overviewSection = (
<div id="overview-section">
<h2>{translations.homePage.overviewHeadline}</h2>
<h2>{coreViewModel.translations.homePage.overviewHeadline}</h2>
<label class="tile flex-no">
<span class="icon">cell_tower</span>
<div>
<span>{translations.homePage.serverAddress}</span>
<span>
{coreViewModel.translations.homePage.serverAddress}
</span>
<input
list="previous-connection-list"
placeholder={
translations.homePage.serverAddressPlaceholder
coreViewModel.translations.homePage
.serverAddressPlaceholder
}
bind:value={connectionViewModel.serverAddressInput}
on:enter={connectionViewModel.connect}
@@ -53,7 +55,9 @@ export function HomePage(
<div class="flex-row">
<button
class="danger flex justify-center"
aria-label={translations.homePage.disconnectAudioLabel}
aria-label={
coreViewModel.translations.homePage.disconnectAudioLabel
}
on:click={connectionViewModel.disconnect}
toggle:disabled={connectionViewModel.cannotDisonnect}
>
@@ -62,7 +66,8 @@ export function HomePage(
<button
class="flex justify-center"
aria-label={
translations.homePage.manageConnectionsAudioLabel
coreViewModel.translations.homePage
.manageConnectionsAudioLabel
}
on:click={connectionViewModel.showConnectionModal}
toggle:disabled={
@@ -73,7 +78,9 @@ export function HomePage(
</button>
<button
class="primary flex justify-center"
aria-label={translations.homePage.connectAudioLabel}
aria-label={
coreViewModel.translations.homePage.connectAudioLabel
}
on:click={connectionViewModel.connect}
toggle:disabled={connectionViewModel.cannotConnect}
>
@@ -86,9 +93,14 @@ export function HomePage(
<label class="tile flex-no">
<span class="icon">account_circle</span>
<div>
<span>{translations.homePage.yourNameLabel}</span>
<span>
{coreViewModel.translations.homePage.yourNameLabel}
</span>
<input
placeholder={translations.homePage.yourNamePlaceholder}
placeholder={
coreViewModel.translations.homePage
.yourNamePlaceholder
}
bind:value={settingsViewModel.usernameInput}
on:enter={settingsViewModel.setName}
></input>
@@ -99,9 +111,12 @@ export function HomePage(
class="width-50"
on:click={settingsViewModel.setName}
toggle:disabled={settingsViewModel.cannotSetName}
aria-label={translations.homePage.setNameButtonAudioLabel}
aria-label={
coreViewModel.translations.homePage
.setNameButtonAudioLabel
}
>
{translations.general.setButton}
{coreViewModel.translations.general.setButton}
<span class="icon">check</span>
</button>
</div>
@@ -110,17 +125,17 @@ export function HomePage(
{HomePageButton(
settingsViewModel.showSettingsModal,
translations.homePage.settingsButton,
coreViewModel.translations.homePage.settingsButton,
"settings",
)}
{HomePageButton(
fileTransferViewModel.showDirectionSelectionModal,
translations.homePage.transferDataButton,
coreViewModel.translations.homePage.transferDataButton,
"sync_alt",
)}
{HomePageButton(
storageViewModel.showStorageModal,
translations.homePage.manageStorageButton,
coreViewModel.translations.homePage.manageStorageButton,
"hard_drive",
)}
@@ -129,7 +144,7 @@ export function HomePage(
<div class="flex-row justify-end">
<button class="ghost width-50" on:click={scrollToChat}>
{translations.homePage.scrollToChatButton}
{coreViewModel.translations.homePage.scrollToChatButton}
<span class="icon">arrow_forward</span>
</button>
</div>
@@ -139,18 +154,24 @@ export function HomePage(
const chatSection = (
<div id="chat-section">
<h2>{translations.homePage.chatsHeadline}</h2>
<h2>{coreViewModel.translations.homePage.chatsHeadline}</h2>
<div class="flex-row width-input">
<input
placeholder={translations.homePage.addChatPlaceholder}
aria-label={translations.homePage.addChatAudioLabel}
placeholder={
coreViewModel.translations.homePage.addChatPlaceholder
}
aria-label={
coreViewModel.translations.homePage.addChatAudioLabel
}
bind:value={chatListViewModel.newChatPrimaryChannel}
on:enter={chatListViewModel.createChat}
></input>
<button
class="primary"
aria-label={translations.homePage.addChatButton}
aria-label={
coreViewModel.translations.homePage.addChatButton
}
on:click={chatListViewModel.createChat}
toggle:disabled={chatListViewModel.cannotCreateChat}
>
+3 -4
View File
@@ -1,12 +1,11 @@
import * as React from "bloatless-react";
import CoreViewModel from "../ViewModel/Global/coreViewModel";
import { translations } from "./translations";
export function MainPage() {
export function MainPage(coreViewModel: CoreViewModel) {
return (
<article id="home-page">
<header>
<span>{translations.homePage.appName}</span>
<span>{coreViewModel.translations.homePage.appName}</span>
</header>
<div></div>
</article>
+18 -9
View File
@@ -58,8 +58,6 @@ const englishTranslations = {
yourNamePlaceholder: "Jane Doe",
setNameButtonAudioLabel: "set name",
firstDayOfWeekLabel: "First day of week",
settingsButton: "Settings",
manageStorageButton: "Manage storage",
transferDataButton: "Data Transfer",
@@ -84,6 +82,9 @@ const englishTranslations = {
},
version: "Version",
language: "Language",
firstDayOfWeekLabel: "First day of week",
},
connectionModal: {
@@ -291,7 +292,9 @@ const englishTranslations = {
},
};
const allTranslations: { [language: string]: typeof englishTranslations } = {
export const allTranslations: {
[language: string]: typeof englishTranslations;
} = {
en: englishTranslations,
de: {
@@ -352,8 +355,6 @@ const allTranslations: { [language: string]: typeof englishTranslations } = {
yourNamePlaceholder: "Max Mustermann",
setNameButtonAudioLabel: "Name speichern",
firstDayOfWeekLabel: "Erster Wochentag",
settingsButton: "Einstellungen",
manageStorageButton: "Daten verwalten",
transferDataButton: "Datenübertragung",
@@ -376,6 +377,9 @@ const allTranslations: { [language: string]: typeof englishTranslations } = {
},
version: "Version",
language: "Sprache",
firstDayOfWeekLabel: "Erster Wochentag",
},
connectionModal: {
@@ -615,8 +619,6 @@ const allTranslations: { [language: string]: typeof englishTranslations } = {
yourNamePlaceholder: "Juan Pérez",
setNameButtonAudioLabel: "establecer nombre",
firstDayOfWeekLabel: "Primer día de la semana",
settingsButton: "Ajustes",
manageStorageButton: "Gestionar almacenamiento",
transferDataButton: "Transferencia de datos",
@@ -639,6 +641,9 @@ const allTranslations: { [language: string]: typeof englishTranslations } = {
},
version: "Versión",
language: "Idioma",
firstDayOfWeekLabel: "Primer día de la semana",
},
connectionModal: {
connectionModalHeadline: "Gestionar Conexiones",
@@ -823,5 +828,9 @@ const allTranslations: { [language: string]: typeof englishTranslations } = {
},
};
const language = navigator.language.substring(0, 2);
export const translations = allTranslations[language] || allTranslations.en;
export type Translations = typeof englishTranslations;
export enum Languages {
English = "en",
German = "de",
Spanish = "es",
}