format
This commit is contained in:
@@ -46,7 +46,10 @@ export function BoardPage(
|
||||
);
|
||||
|
||||
const wrapper = (
|
||||
<div class="content main-content allow-drag-move" children:set={pages}></div>
|
||||
<div
|
||||
class="content main-content allow-drag-move"
|
||||
children:set={pages}
|
||||
></div>
|
||||
);
|
||||
Utility.implementPinchZoom(wrapper, boardViewModel.pinchToZoomData);
|
||||
|
||||
|
||||
@@ -36,11 +36,11 @@
|
||||
width: 100%;
|
||||
padding-left: var(--content-padding);
|
||||
gap: var(--gap-in-controls);
|
||||
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
|
||||
background: var(--surface);
|
||||
}
|
||||
|
||||
@@ -285,7 +285,8 @@
|
||||
padding: var(--gap-between-tiles);
|
||||
}
|
||||
|
||||
#message-page[reply-view] :is(.reply-link, .inline-reply, #composer .reply-preview-wrapper) {
|
||||
#message-page[reply-view]
|
||||
:is(.reply-link, .inline-reply, #composer .reply-preview-wrapper) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
+169
-148
@@ -15,156 +15,177 @@ export function MessagePage(
|
||||
messagePageViewModel.loadData();
|
||||
|
||||
const ChatMessageViewModelToView: React.StateItemConverter<
|
||||
ChatMessageViewModel
|
||||
> = (chatMessageViewModel: ChatMessageViewModel) => {
|
||||
return ChatMessage(coreViewModel, chatMessageViewModel);
|
||||
};
|
||||
ChatMessageViewModel
|
||||
> = (chatMessageViewModel: ChatMessageViewModel) => {
|
||||
return ChatMessage(coreViewModel, chatMessageViewModel);
|
||||
};
|
||||
|
||||
const messageContainer = (
|
||||
<div
|
||||
id="message-container"
|
||||
children:append={[
|
||||
messagePageViewModel.filteredMessageViewModels,
|
||||
ChatMessageViewModelToView,
|
||||
]}
|
||||
></div>
|
||||
);
|
||||
const messageContainer = (
|
||||
<div
|
||||
id="message-container"
|
||||
children:append={[
|
||||
messagePageViewModel.filteredMessageViewModels,
|
||||
ChatMessageViewModelToView,
|
||||
]}
|
||||
></div>
|
||||
);
|
||||
|
||||
const persistenceId = messagePageViewModel.chatViewModel.chatModel.id;
|
||||
const replyPreview = ViewController.inlineReplies.setState(
|
||||
persistenceId,
|
||||
() =>
|
||||
React.createProxyState(
|
||||
[messagePageViewModel.replyingMessage],
|
||||
() => {
|
||||
if (messagePageViewModel.replyingMessage.value == undefined)
|
||||
return <div></div>;
|
||||
return ReplyPreview(
|
||||
coreViewModel,
|
||||
messagePageViewModel.replyingMessage.value,
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
const persistenceId = messagePageViewModel.chatViewModel.chatModel.id;
|
||||
const replyPreview = ViewController.inlineReplies.setState(
|
||||
persistenceId,
|
||||
() =>
|
||||
React.createProxyState(
|
||||
[messagePageViewModel.replyingMessage],
|
||||
() => {
|
||||
if (messagePageViewModel.replyingMessage.value == undefined)
|
||||
return <div></div>;
|
||||
return ReplyPreview(
|
||||
coreViewModel,
|
||||
messagePageViewModel.replyingMessage.value,
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
function scrollDown(hard: boolean = false) {
|
||||
if (hard) {
|
||||
messageContainer.setAttribute("scroll-hard", "");
|
||||
function scrollDown(hard: boolean = false) {
|
||||
if (hard) {
|
||||
messageContainer.setAttribute("scroll-hard", "");
|
||||
}
|
||||
messageContainer.scrollTop = messageContainer.scrollHeight;
|
||||
messageContainer.removeAttribute("scroll-hard");
|
||||
}
|
||||
messageContainer.scrollTop = messageContainer.scrollHeight;
|
||||
messageContainer.removeAttribute("scroll-hard");
|
||||
}
|
||||
function scrollDownIfApplicable() {
|
||||
const scrollFromBottom =
|
||||
messageContainer.scrollHeight -
|
||||
(messageContainer.scrollTop + messageContainer.offsetHeight);
|
||||
if (scrollFromBottom > 400) return;
|
||||
|
||||
scrollDown();
|
||||
}
|
||||
messagePageViewModel.filteredMessageViewModels.subscribeSilent(
|
||||
scrollDownIfApplicable,
|
||||
);
|
||||
React.bulkSubscribe([messagePageViewModel.reactionFilter, messagePageViewModel.searchViewModel.appliedQuery], scrollDown)
|
||||
messagePageViewModel.replyViewSelectedMessage.subscribeSilent(selectedMessage => {
|
||||
if (selectedMessage != undefined) return;
|
||||
setTimeout(scrollDown, 100);
|
||||
})
|
||||
setTimeout(() => scrollDown(true), 100);
|
||||
|
||||
messagePageViewModel.focusSetter.subscribeSilent(() => {
|
||||
ViewController.setFocusWithDelay();
|
||||
});
|
||||
|
||||
const isInReplyView = React.createProxyState([messagePageViewModel.replyViewSelectedMessage], ()=>messagePageViewModel.replyViewSelectedMessage.value != undefined);
|
||||
|
||||
const title = React.createProxyState([messagePageViewModel.isReplyViewActive], ()=>messagePageViewModel.isReplyViewActive.value ? coreViewModel.translations.chatPage.message.replyHeaderLabel((messagePageViewModel.replyViewSelectedMessage.value!).body.value) : coreViewModel.translations.chatPage.message.messagesHeadline);
|
||||
|
||||
return (
|
||||
<div id="message-page" toggle:reply-view={isInReplyView}>
|
||||
<div class="pane-wrapper">
|
||||
<div class="pane">
|
||||
<div class="toolbar">
|
||||
<button
|
||||
class="ghost"
|
||||
on:click={messagePageViewModel.resetReplyView}
|
||||
toggle:hidden={messagePageViewModel.isReplyViewInactive}
|
||||
>
|
||||
<span class="icon">arrow_back</span>
|
||||
</button>
|
||||
<span
|
||||
class="title ellipsis width-100 flex"
|
||||
subscribe:innerText={title}
|
||||
>
|
||||
</span>
|
||||
<span>
|
||||
<button
|
||||
class="ghost inset-outline"
|
||||
on:click={messagePageViewModel.showFilterModal}
|
||||
aria-label={
|
||||
coreViewModel.translations.chatPage.message
|
||||
.filterMessagesButtonAudioLabel
|
||||
}
|
||||
toggle:selected={
|
||||
messagePageViewModel.isFilterActive
|
||||
}
|
||||
>
|
||||
<span class="icon">filter_alt</span>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
<div class="content">
|
||||
{messageContainer}
|
||||
<div id="composer">
|
||||
<div class="content-width-constraint">
|
||||
<div
|
||||
class="reply-preview-wrapper"
|
||||
children:set={replyPreview}
|
||||
></div>
|
||||
<div class="input-width-constraint">
|
||||
<input
|
||||
id="focused"
|
||||
class="blur"
|
||||
bind:value={
|
||||
messagePageViewModel.composingMessage
|
||||
}
|
||||
on:enter={
|
||||
messagePageViewModel.sendMessage
|
||||
}
|
||||
placeholder={
|
||||
coreViewModel.translations.chatPage
|
||||
.message
|
||||
.composerInputPlaceholder
|
||||
}
|
||||
></input>
|
||||
<button
|
||||
class="primary blur"
|
||||
aria-label={
|
||||
coreViewModel.translations.chatPage
|
||||
.message
|
||||
.sendMessageButtonAudioLabel
|
||||
}
|
||||
on:click={
|
||||
messagePageViewModel.sendMessage
|
||||
}
|
||||
toggle:disabled={
|
||||
messagePageViewModel.cannotSendMessage
|
||||
}
|
||||
>
|
||||
<span class="icon">send</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{MessageFilterModal(
|
||||
coreViewModel,
|
||||
messagePageViewModel,
|
||||
ChatMessageViewModelToView,
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
function scrollDownIfApplicable() {
|
||||
const scrollFromBottom =
|
||||
messageContainer.scrollHeight -
|
||||
(messageContainer.scrollTop + messageContainer.offsetHeight);
|
||||
if (scrollFromBottom > 400) return;
|
||||
|
||||
scrollDown();
|
||||
}
|
||||
messagePageViewModel.filteredMessageViewModels.subscribeSilent(
|
||||
scrollDownIfApplicable,
|
||||
);
|
||||
React.bulkSubscribe(
|
||||
[
|
||||
messagePageViewModel.reactionFilter,
|
||||
messagePageViewModel.searchViewModel.appliedQuery,
|
||||
],
|
||||
scrollDown,
|
||||
);
|
||||
messagePageViewModel.replyViewSelectedMessage.subscribeSilent(
|
||||
(selectedMessage) => {
|
||||
if (selectedMessage != undefined) return;
|
||||
setTimeout(scrollDown, 100);
|
||||
},
|
||||
);
|
||||
setTimeout(() => scrollDown(true), 100);
|
||||
|
||||
messagePageViewModel.focusSetter.subscribeSilent(() => {
|
||||
ViewController.setFocusWithDelay();
|
||||
});
|
||||
|
||||
const isInReplyView = React.createProxyState(
|
||||
[messagePageViewModel.replyViewSelectedMessage],
|
||||
() => messagePageViewModel.replyViewSelectedMessage.value != undefined,
|
||||
);
|
||||
|
||||
const title = React.createProxyState(
|
||||
[messagePageViewModel.isReplyViewActive],
|
||||
() =>
|
||||
messagePageViewModel.isReplyViewActive.value
|
||||
? coreViewModel.translations.chatPage.message.replyHeaderLabel(
|
||||
messagePageViewModel.replyViewSelectedMessage.value!.body
|
||||
.value,
|
||||
)
|
||||
: coreViewModel.translations.chatPage.message.messagesHeadline,
|
||||
);
|
||||
|
||||
return (
|
||||
<div id="message-page" toggle:reply-view={isInReplyView}>
|
||||
<div class="pane-wrapper">
|
||||
<div class="pane">
|
||||
<div class="toolbar">
|
||||
<button
|
||||
class="ghost"
|
||||
on:click={messagePageViewModel.resetReplyView}
|
||||
toggle:hidden={
|
||||
messagePageViewModel.isReplyViewInactive
|
||||
}
|
||||
>
|
||||
<span class="icon">arrow_back</span>
|
||||
</button>
|
||||
<span
|
||||
class="title ellipsis width-100 flex"
|
||||
subscribe:innerText={title}
|
||||
></span>
|
||||
<span>
|
||||
<button
|
||||
class="ghost inset-outline"
|
||||
on:click={messagePageViewModel.showFilterModal}
|
||||
aria-label={
|
||||
coreViewModel.translations.chatPage.message
|
||||
.filterMessagesButtonAudioLabel
|
||||
}
|
||||
toggle:selected={
|
||||
messagePageViewModel.isFilterActive
|
||||
}
|
||||
>
|
||||
<span class="icon">filter_alt</span>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
<div class="content">
|
||||
{messageContainer}
|
||||
<div id="composer">
|
||||
<div class="content-width-constraint">
|
||||
<div
|
||||
class="reply-preview-wrapper"
|
||||
children:set={replyPreview}
|
||||
></div>
|
||||
<div class="input-width-constraint">
|
||||
<input
|
||||
id="focused"
|
||||
class="blur"
|
||||
bind:value={
|
||||
messagePageViewModel.composingMessage
|
||||
}
|
||||
on:enter={
|
||||
messagePageViewModel.sendMessage
|
||||
}
|
||||
placeholder={
|
||||
coreViewModel.translations.chatPage
|
||||
.message
|
||||
.composerInputPlaceholder
|
||||
}
|
||||
></input>
|
||||
<button
|
||||
class="primary blur"
|
||||
aria-label={
|
||||
coreViewModel.translations.chatPage
|
||||
.message
|
||||
.sendMessageButtonAudioLabel
|
||||
}
|
||||
on:click={
|
||||
messagePageViewModel.sendMessage
|
||||
}
|
||||
toggle:disabled={
|
||||
messagePageViewModel.cannotSendMessage
|
||||
}
|
||||
>
|
||||
<span class="icon">send</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{MessageFilterModal(
|
||||
coreViewModel,
|
||||
messagePageViewModel,
|
||||
ChatMessageViewModelToView,
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -47,12 +47,8 @@ export function SettingsPage(
|
||||
}
|
||||
</span>
|
||||
<input
|
||||
bind:value={
|
||||
settingsPageViewModel.nameInput
|
||||
}
|
||||
on:enter={
|
||||
settingsPageViewModel.setName
|
||||
}
|
||||
bind:value={settingsPageViewModel.nameInput}
|
||||
on:enter={settingsPageViewModel.setName}
|
||||
></input>
|
||||
</div>
|
||||
</label>
|
||||
@@ -63,9 +59,7 @@ export function SettingsPage(
|
||||
coreViewModel.translations.chatPage.settings
|
||||
.setNameButtonAudioLabel
|
||||
}
|
||||
on:click={
|
||||
settingsPageViewModel.setName
|
||||
}
|
||||
on:click={settingsPageViewModel.setName}
|
||||
toggle:disabled={
|
||||
settingsPageViewModel.cannotSetPrimaryChannel
|
||||
}
|
||||
@@ -177,7 +171,7 @@ export function SettingsPage(
|
||||
|
||||
<hr></hr>
|
||||
|
||||
{ColorPicker(settingsPageViewModel.color)}
|
||||
{ColorPicker(settingsPageViewModel.color)}
|
||||
|
||||
<div class="flex-row justify-end width-input">
|
||||
<button
|
||||
@@ -186,17 +180,16 @@ export function SettingsPage(
|
||||
coreViewModel.translations.chatPage.settings
|
||||
.setColorButtonAudioLabel
|
||||
}
|
||||
on:click={
|
||||
settingsPageViewModel.applyColor
|
||||
}
|
||||
toggle:disabled={settingsPageViewModel.cannotSetColor}
|
||||
on:click={settingsPageViewModel.applyColor}
|
||||
toggle:disabled={
|
||||
settingsPageViewModel.cannotSetColor
|
||||
}
|
||||
>
|
||||
{coreViewModel.translations.general.setButton}
|
||||
<span class="icon">check</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
<hr></hr>
|
||||
|
||||
<div class="width-input">
|
||||
|
||||
@@ -2,11 +2,11 @@ import "./taskPage.css";
|
||||
import { BoardPage } from "./boardPage";
|
||||
import { ViewController } from "../viewController";
|
||||
import { PlaceholderView } from "../Components/placeholderView";
|
||||
import { NewItemEntry } from "../Components/newItemEntry";
|
||||
import { BoardViewModelToEntry } from "../Components/boardEntry";
|
||||
import * as React from "../../react";
|
||||
import TaskPageViewModel from "../../ViewModel/Pages/taskPageViewModel";
|
||||
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
|
||||
import {NewItemEntry} from "../Components/newItemEntry";
|
||||
|
||||
export function TaskPage(
|
||||
coreViewModel: CoreViewModel,
|
||||
@@ -66,13 +66,18 @@ export function TaskPage(
|
||||
bind:value={taskPageViewModel.boardQuery}
|
||||
on:enter={taskPageViewModel.createBoard}
|
||||
placeholder={
|
||||
coreViewModel.translations.general.filterOrCreateLabel
|
||||
coreViewModel.translations.general
|
||||
.filterOrCreateLabel
|
||||
}
|
||||
></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content gap">
|
||||
{NewItemEntry(coreViewModel, taskPageViewModel.boardQuery, taskPageViewModel.createBoard)}
|
||||
<div class="content gap">
|
||||
{NewItemEntry(
|
||||
coreViewModel,
|
||||
taskPageViewModel.boardQuery,
|
||||
taskPageViewModel.createBoard,
|
||||
)}
|
||||
<div
|
||||
class="grid gap"
|
||||
style="grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr))"
|
||||
|
||||
Reference in New Issue
Block a user