Skip to content

Commit

Permalink
Community nye UI improvements (#511)
Browse files Browse the repository at this point in the history
* Added custom tooltip for reactions/status;

* Type fix;

* Using names instead of domains;

* Save back-up from before a collaborative edit;

* Save back-up from before a collaborative edit;

* Add virtualizer to the threads page

* WIP threads page;

* Added inline composers to the threads page;

* Added loading state for messagecomposer; Improved threads layout;

* Better handle fast editing of a sent message;

* Added status details dialog;

* Add options to restore original message when making a message private again;

* Restored activity page to see recent messages in a channel;

* UI Cleanup; Rename;

* Added cache buster queryString to manifest icons (owner & community);

* Layout fix;

* Fix for in thread message edits;

* Better support editing in one place only;
  • Loading branch information
stef-coenen authored Jan 7, 2025
1 parent 1100afc commit fc4cc76
Show file tree
Hide file tree
Showing 31 changed files with 544 additions and 237 deletions.
10 changes: 5 additions & 5 deletions packages/apps/community-app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
<base href="/apps/community/" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />

<link rel="apple-touch-icon" sizes="180x180" href="/icons/apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="32x32" href="/icons/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/icons/favicon-16x16.png" />
<link rel="manifest" href="/icons/site.webmanifest" />
<link rel="shortcut icon" href="/icons/favicon.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="/icons/apple-touch-icon.png?v=202501" />
<link rel="icon" type="image/png" sizes="32x32" href="/icons/favicon-32x32.png?v=202501" />
<link rel="icon" type="image/png" sizes="16x16" href="/icons/favicon-16x16.png?v=202501" />
<link rel="manifest" href="/icons/site.webmanifest?v=202501" />
<link rel="shortcut icon" href="/icons/favicon.ico?v=202501" />
<meta name="theme-color" content="#ffffff" />

<title>Homebase | Community</title>
Expand Down
4 changes: 2 additions & 2 deletions packages/apps/community-app/public/icons/site.webmanifest
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
"scope": "/",
"icons": [
{
"src": "/icons/android-chrome-192x192.png",
"src": "/icons/android-chrome-192x192.png?v=202501",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/icons/android-chrome-512x512.png",
"src": "/icons/android-chrome-512x512.png?v=202501",
"sizes": "512x512",
"type": "image/png"
}
Expand Down
34 changes: 34 additions & 0 deletions packages/apps/community-app/src/app/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,37 @@
.faded-scrollbar::-webkit-scrollbar-track {
background-color: rgba(0, 0, 0, 0);
}

[data-tooltip] {
position: relative;
}

[data-tooltip]:after {
content: attr(data-tooltip);
position: absolute;
left: 0;
bottom: calc(100% + 0.3rem); /* put it on the top */
background-color: rgba(var(--color-page-background));
border-radius: 0.2rem;
border: 1px solid rgba(var(--color-foreground) / 0.1);
font-size: 0.9rem;
padding: 0.05rem 0.2rem;
color: rgba(var(--color-foreground));
width: max-content;
opacity: 0;
-webkit-transition: opacity 0.3s ease-in-out;
pointer-events: none;

--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000),
var(--tw-shadow);
}
[data-tooltip-dir='left']:after {
right: calc(100% + 0.3rem);
left: auto;
}

[data-tooltip]:hover:after {
opacity: 1;
}
26 changes: 9 additions & 17 deletions packages/apps/community-app/src/app/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ const CommunityChannelDetail = lazy(() =>
default: communityApp.CommunityChannelDetail,
}))
);
const CommunityCatchup = lazy(() =>
import('../templates/Community/CommunityCatchup').then((communityApp) => ({
default: communityApp.CommunityCatchup,
const CommunityChannelsCatchup = lazy(() =>
import('../templates/Community/CommunityChannelsCatchup').then((communityApp) => ({
default: communityApp.CommunityChannelsCatchup,
}))
);
const CommunityThreadsCatchup = lazy(() =>
Expand Down Expand Up @@ -119,20 +119,12 @@ function App() {
<Route path={'threads'} element={<CommunityThreadsCatchup />} />
<Route path={'later'} element={<CommunityLater />} />

{/* Items for 'all' */}
<Route path={'all'} element={<CommunityCatchup />} />
<Route path={'all/:chatMessageKey'} element={<CommunityCatchup />} />
<Route path={'all/:chatMessageKey/:mediaKey'} element={<CommunityCatchup />} />

{/* Items for 'all' within a thread */}
<Route path={'all/:threadKey/thread'} element={<CommunityCatchup />} />
<Route
path={'all/:threadKey/thread/:chatMessageKey'}
element={<CommunityCatchup />}
/>
{/* Items for 'activity' */}
<Route path={'activity'} element={<CommunityChannelsCatchup />} />
<Route path={'activity/:chatMessageKey'} element={<CommunityChannelsCatchup />} />
<Route
path={'all/:threadKey/thread/:chatMessageKey/:mediaKey'}
element={<CommunityCatchup />}
path={'activity/:chatMessageKey/:mediaKey'}
element={<CommunityChannelsCatchup />}
/>

{/* Items for 'channel' */}
Expand Down Expand Up @@ -206,7 +198,7 @@ function App() {
const CommunityRootRoute = () => {
const { odinKey, communityKey } = useParams();
return window.innerWidth > 1024 ? (
<Navigate to={`${COMMUNITY_ROOT_PATH}/${odinKey}/${communityKey}/all`} />
<Navigate to={`${COMMUNITY_ROOT_PATH}/${odinKey}/${communityKey}/activity`} />
) : null;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,13 @@ export const CommunityThread = memo(
className="p-2 xl:hidden"
size="none"
type="mute"
href={`${COMMUNITY_ROOT_PATH}/${odinKey}/${communityKey}/${channelKey || 'all'}`}
href={`${COMMUNITY_ROOT_PATH}/${odinKey}/${communityKey}/${channelKey || 'activity'}`}
>
<ChevronLeft className="h-5 w-5" />
</ActionLink>
{t('Thread')}
<ActionLink
href={`${COMMUNITY_ROOT_PATH}/${odinKey}/${communityKey}/${channelKey || 'all'}`}
href={`${COMMUNITY_ROOT_PATH}/${odinKey}/${communityKey}/${channelKey || 'activity'}`}
icon={Times}
size="none"
type="mute"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { CommunityMessage } from '../../../../providers/CommunityMessageProvider
import { CommunityMetadata, Draft } from '../../../../providers/CommunityMetadataProvider';
import { CommunityChannel } from '../../../../providers/CommunityProvider';
import { ChannelPlugin } from '../RTEChannelDropdown/RTEChannelDropdownPlugin';
import { Mentionable } from '@homebase-id/rich-text-editor/src/components/plate-ui/mention-input-element';

const RichTextEditor = lazy(() =>
import('@homebase-id/rich-text-editor').then((rootExport) => ({
Expand Down Expand Up @@ -166,7 +167,7 @@ export const MessageComposer = ({
};

const { data: contacts } = useAllContacts(true);
const mentionables: { key: string; text: string }[] = useMemo(() => {
const mentionables: Mentionable[] = useMemo(() => {
const filteredContacts =
(contacts
?.filter(
Expand All @@ -176,15 +177,24 @@ export const MessageComposer = ({
contact.fileMetadata.appData.content.odinId
)
)
?.map((contact) =>
contact.fileMetadata.appData.content.odinId
? {
key: contact.fileMetadata.appData.content.odinId,
text: contact.fileMetadata.appData.content.odinId,
}
: undefined
)
.filter(Boolean) as { key: string; text: string }[]) || [];
?.map((contact) => {
const content = contact.fileMetadata.appData.content;
if (!content?.odinId) return;
const name =
content.name &&
(content.name.displayName ??
(content.name.givenName || content.name.surname
? `${content.name.givenName ?? ''} ${content.name.surname ?? ''}`
: undefined));

return {
key: `${content.odinId} (${name})`,
value: content.odinId,
text: content.odinId,
label: `${content.odinId} (${name})`,
};
})
.filter(Boolean) as Mentionable[]) || [];

filteredContacts.push({ key: '@channel', text: '@channel' });
return filteredContacts;
Expand All @@ -210,7 +220,11 @@ export const MessageComposer = ({
}
}}
>
<Suspense>
<Suspense
fallback={
<div className="relative h-[119px] w-full border-t bg-background px-2 pb-1 dark:border-slate-800 md:rounded-md md:border" />
}
>
<RichTextEditor
className="relative w-8 flex-grow border-t bg-background px-2 pb-1 dark:border-slate-800 md:rounded-md md:border"
contentClassName="max-h-[50vh] overflow-auto"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ import {
} from '@homebase-id/common-app';
import { ImageSource, OdinPayloadImage, OdinPreviewImage } from '@homebase-id/ui-lib';
import { useNavigate, useParams } from 'react-router-dom';
import { CommunityMessage } from '../../../../providers/CommunityMessageProvider';
import {
BACKEDUP_PAYLOAD_KEY,
CommunityMessage,
} from '../../../../providers/CommunityMessageProvider';
import { getTargetDriveFromCommunityId } from '../../../../providers/CommunityDefinitionProvider';
import { Times, ArrowLeft, Arrow } from '@homebase-id/common-app/icons';

Expand Down Expand Up @@ -46,7 +49,7 @@ export const CommunityMediaGallery = ({
};

const allkeys = msg.fileMetadata.payloads
?.filter((pyld) => pyld.key !== DEFAULT_PAYLOAD_KEY)
?.filter((pyld) => pyld.key !== DEFAULT_PAYLOAD_KEY && pyld.key !== BACKEDUP_PAYLOAD_KEY)
?.map((p) => p.key);
const nextKey = allkeys?.[allkeys.indexOf(mediaKey) + 1];
const prevKey = allkeys?.[allkeys.indexOf(mediaKey) - 1];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { Triangle } from '@homebase-id/common-app/icons';
import { useNavigate, useParams } from 'react-router-dom';
import { useMemo, useState } from 'react';
import {
BACKEDUP_PAYLOAD_KEY,
COMMUNITY_LINKS_PAYLOAD_KEY,
CommunityMessage,
} from '../../../../providers/CommunityMessageProvider';
Expand All @@ -34,7 +35,9 @@ export const CommunityMedia = ({
communityId: string;
msg: HomebaseFile<CommunityMessage> | NewHomebaseFile<CommunityMessage>;
}) => {
const payloads = msg.fileMetadata.payloads?.filter((pyld) => pyld.key !== DEFAULT_PAYLOAD_KEY);
const payloads = msg.fileMetadata.payloads?.filter(
(pyld) => pyld.key !== DEFAULT_PAYLOAD_KEY && pyld.key !== BACKEDUP_PAYLOAD_KEY
);
const isGallery = payloads && payloads.length >= 2;
const navigate = useNavigate();
const { odinKey, communityKey, channelKey } = useParams();
Expand All @@ -53,7 +56,7 @@ export const CommunityMedia = ({
fit={'contain'}
onClick={() =>
navigate(
`${COMMUNITY_ROOT_PATH}/${odinKey}/${communityKey}/${channelKey}/${msg.fileMetadata.appData.uniqueId}/${payloads[0].key}`
`${COMMUNITY_ROOT_PATH}/${odinKey}/${communityKey}/${channelKey || msg.fileMetadata.appData.content.channelId}/${msg.fileMetadata.appData.uniqueId}/${payloads[0].key}`
)
}
previewThumbnail={isGallery ? undefined : msg.fileMetadata.appData.previewThumbnail}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
ActionButton,
useContentFromPayload,
useLongPress,
ConnectionName,
} from '@homebase-id/common-app';
import { DEFAULT_PAYLOAD_KEY, HomebaseFile, RichText } from '@homebase-id/js-lib/core';
import {
Expand Down Expand Up @@ -88,7 +89,8 @@ export const CommunityMessageItem = memo(
const editInThreadMatch = useMatch(
`${COMMUNITY_ROOT_PATH}/:odinKey/:communityKey/:channelKey/:threadKey/thread/:chatMessageKey/edit`
);
const isEdit = !!isDetail && !!(editMatch || editInThreadMatch);
const isEdit =
!!isDetail && ((!!editMatch && !hideThreads) || (!!editInThreadMatch && hideThreads));

const navigate = useNavigate();
const extendedCommunityActions: CommunityActions | undefined = useMemo(() => {
Expand All @@ -97,7 +99,7 @@ export const CommunityMessageItem = memo(
...communityActions,
doEdit: () =>
navigate(
`${COMMUNITY_ROOT_PATH}/${community?.fileMetadata.senderOdinId}/${community?.fileMetadata.appData.uniqueId}/${channelKey}/${threadKey ? `${threadKey}/thread/` : ``}${msg.fileMetadata.appData.uniqueId}/edit`
`${COMMUNITY_ROOT_PATH}/${community?.fileMetadata.senderOdinId}/${community?.fileMetadata.appData.uniqueId}/${channelKey || msg.fileMetadata.appData.content.channelId}/${threadKey ? `${threadKey}/thread/` : ``}${msg.fileMetadata.appData.uniqueId}/edit`
),
};
}, []);
Expand Down Expand Up @@ -368,13 +370,14 @@ const MessageTextRenderer = ({
target="_blank"
rel="noreferrer noopener"
className="break-words text-primary hover:underline"
data-tooltip={`@${attributes.value.replaceAll('@', '')}`}
>
@{attributes.value.replaceAll('@', '')}
@<ConnectionName odinId={attributes.value.replaceAll('@', '')} />
</a>
);
else
return (
<span className="break-all text-primary">
<span className="break-all font-semibold" data-tooltip={attributes.value}>
@{attributes.value.replaceAll('@', '')}
</span>
);
Expand Down Expand Up @@ -520,7 +523,7 @@ const CommunityMessageThreadSummary = ({
return (
<Link
className="mr-auto flex w-full max-w-xs flex-row items-center gap-2 rounded-lg px-1 py-1 text-indigo-500 transition-colors hover:bg-background hover:shadow-sm"
to={`${COMMUNITY_ROOT_PATH}/${odinKey}/${communityKey}/${channelKey || 'all'}/${msg.fileMetadata.appData.uniqueId}/thread`}
to={`${COMMUNITY_ROOT_PATH}/${odinKey}/${communityKey}/${channelKey || msg.fileMetadata.appData.content.channelId}/${msg.fileMetadata.appData.uniqueId}/thread`}
>
{uniqueSenders.map((sender) => (
<AuthorImage odinId={sender} key={sender} className="h-7 w-7" excludeLink={true} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ const ReactionButton = ({
<button
className={`flex flex-row items-center gap-2 rounded-3xl border bg-background px-2 py-[0.1rem] shadow-sm hover:bg-primary hover:text-primary-contrast ${myReaction ? 'border-primary bg-primary/10 dark:bg-primary/60' : 'border-transparent'}`}
{...clickProps}
title={`${authors?.length ? authors.join(', ') : ''} ${t('reacted with')} ${emoji.emoji}`}
data-tooltip={`${authors?.length ? authors.join(', ') : ''} ${t('reacted with')} ${emoji.emoji}`}
>
<p>{emoji.emoji}</p>
<p className="text-sm">{emoji.count}</p>
Expand Down
Loading

0 comments on commit fc4cc76

Please sign in to comment.