Redesigned Primary note

This commit is contained in:
Bojan Mojsilovic 2024-04-16 14:37:31 +02:00
parent 20b4bf76da
commit 33e7efdc02
14 changed files with 102 additions and 56 deletions

View File

@ -7,6 +7,11 @@
background-color: var(--text-tertiary);
-webkit-mask: url(../../assets/icons/bookmark_empty.svg) no-repeat 0 / 16px;
mask: url(../../assets/icons/bookmark_empty.svg) no-repeat 0 / 16px;
&.large {
width: 20px;
height: 20px;
}
}
.fullBookmark {
@ -17,6 +22,11 @@
background-color: var(--active-bookmarked);
-webkit-mask: url(../../assets/icons/bookmark_filled.svg) no-repeat 0 / 16px;
mask: url(../../assets/icons/bookmark_filled.svg) no-repeat 0 / 16px;
&.large {
width: 20px;
height: 20px;
}
}
&:hover {

View File

@ -16,7 +16,7 @@ import styles from './BookmarkNote.module.scss';
import { saveBookmarks } from '../../lib/localStore';
import { importEvents, triggerImportEvents } from '../../lib/notes';
const BookmarkNote: Component<{ note: PrimalNote }> = (props) => {
const BookmarkNote: Component<{ note: PrimalNote, large?: boolean }> = (props) => {
const account = useAccountContext();
const app = useAppContext();
const intl = useIntl();
@ -147,10 +147,10 @@ const BookmarkNote: Component<{ note: PrimalNote }> = (props) => {
<Show
when={isBookmarked()}
fallback={
<div class={styles.emptyBookmark}></div>
<div class={`${styles.emptyBookmark} ${props.large ? styles.large : ''}`}></div>
}
>
<div class={styles.fullBookmark}></div>
<div class={`${styles.fullBookmark} ${props.large ? styles.large : ''}`}></div>
</Show>
</ButtonGhost>
</div>

View File

@ -245,8 +245,9 @@
background-color: var(--background-card);
display: flex;
flex-direction: column;
padding: 12px;
padding-inline: 12px;
padding-top: 0;
padding-bottom: 12px;
border-radius: 0;
border: none;
@ -286,6 +287,29 @@
}
}
.time {
padding-block: 20px;
border-bottom: 1px solid var(--devider);
margin-bottom: 16px;
color: var(--text-tertiary);
font-size: 16px;
font-weight: 400;
line-height: 16px;
.reactSummary {
&::before {
content: ' · ';
}
.number {
color: var(--text-primary);
font-size: 16px;
font-weight: 600;
line-height: 16px;
}
}
}
}
}

View File

@ -16,6 +16,7 @@ import NoteHeader from './NoteHeader/NoteHeader';
import { createStore } from 'solid-js/store';
import { CustomZapInfo, useAppContext } from '../../contexts/AppContext';
import NoteContextTrigger from './NoteContextTrigger';
import { date, longDate, veryLongDate } from '../../lib/dates';
export type NoteFooterState = {
likes: number,
@ -146,6 +147,12 @@ const Note: Component<{
);
}
const reactionSum = () => {
const { likes, zaps, reposts } = props.note.post;
return (likes || 0) + (zaps || 0) + (reposts || 0);
};
return (
<Switch>
<Match when={noteType() === 'notification'}>
@ -200,12 +207,25 @@ const Note: Component<{
<ParsedNote note={props.note} width={Math.min(574, window.innerWidth)} />
</div>
<div
class={styles.time}
title={date(props.note.post?.created_at).date.toLocaleString()}
>
<span>
{veryLongDate(props.note.post?.created_at).replace('at', '·')}
</span>
<span class={styles.reactSummary}>
<span class={styles.number}>{reactionSum()}</span> Reactions
</span>
</div>
<NoteFooter
note={props.note}
state={footerState}
updateState={updateFooterState}
customZapInfo={customZapInfo}
wide={true}
large={true}
/>
</div>
</div>

View File

@ -1,18 +1,11 @@
import { A } from '@solidjs/router';
import { Component, createSignal, Show } from 'solid-js';
import { PrimalNote, PrimalUser } from '../../types/primal';
import ParsedNote from '../ParsedNote/ParsedNote';
import NoteFooter from './NoteFooter/NoteFooter';
import NoteHeader from './NoteHeader/NoteHeader';
import { Component, Show } from 'solid-js';
import { PrimalUser } from '../../types/primal';
import styles from './Note.module.scss';
import { useThreadContext } from '../../contexts/ThreadContext';
import { useIntl } from '@cookbook/solid-intl';
import { authorName, nip05Verification, truncateNpub } from '../../stores/profile';
import { note as t } from '../../translations';
import { authorName, nip05Verification } from '../../stores/profile';
import { hookForDev } from '../../lib/devTools';
import NoteReplyHeader from './NoteHeader/NoteReplyHeader';
import Avatar from '../Avatar/Avatar';
import { date } from '../../lib/dates';
import VerificationCheck from '../VerificationCheck/VerificationCheck';

View File

@ -1,27 +1,17 @@
import { A } from '@solidjs/router';
import { Component, createEffect, createSignal, Show } from 'solid-js';
import { MenuItem, NostrRelaySignedEvent, PrimalNote, PrimalRepost, PrimalUser } from '../../types/primal';
import ParsedNote from '../ParsedNote/ParsedNote';
import NoteFooter from './NoteFooter/NoteFooter';
import NoteHeader from './NoteHeader/NoteHeader';
import { Component, createEffect, createSignal } from 'solid-js';
import { MenuItem, NostrRelaySignedEvent } from '../../types/primal';
import styles from './Note.module.scss';
import { useThreadContext } from '../../contexts/ThreadContext';
import { useIntl } from '@cookbook/solid-intl';
import { authorName, nip05Verification, truncateNpub, userName } from '../../stores/profile';
import { authorName, userName } from '../../stores/profile';
import { note as t, actions as tActions, toast as tToast } from '../../translations';
import { hookForDev } from '../../lib/devTools';
import NoteReplyHeader from './NoteHeader/NoteReplyHeader';
import Avatar from '../Avatar/Avatar';
import { date } from '../../lib/dates';
import VerificationCheck from '../VerificationCheck/VerificationCheck';
import PrimalMenu from '../PrimalMenu/PrimalMenu';
import { useAccountContext } from '../../contexts/AccountContext';
import { APP_ID } from '../../App';
import { reportUser } from '../../lib/profile';
import { useToastContext } from '../Toaster/Toaster';
import { broadcastEvent } from '../../lib/notes';
import { getScreenCordinates } from '../../utils';
import { NoteContextMenuInfo } from '../../contexts/AppContext';
import ConfirmModal from '../ConfirmModal/ConfirmModal';

View File

@ -2,11 +2,23 @@
width: 16px;
height: 16px;
background-color: var(--text-tertiary-2);
&.large {
width: 20px;
height: 20px;
}
}
@mixin typeDiv {
display: flex;
align-items: center;
font-weight: 400;
font-size: 14px;
line-height: 16px;
&.large {
font-size: 16px;
}
}
.contextButton {
@ -59,9 +71,6 @@
}
.stat {
font-weight: 400;
font-size: 14px;
line-height: 16px;
align-items: center;
margin: 0px;
padding: 0px;

View File

@ -30,6 +30,7 @@ const NoteFooter: Component<{
state: NoteFooterState,
updateState: SetStoreFunction<NoteFooterState>,
customZapInfo: CustomZapInfo,
large?: boolean,
}> = (props) => {
const account = useAccountContext();
@ -321,6 +322,7 @@ const NoteFooter: Component<{
highlighted={props.state.replied}
label={props.state.replies === 0 ? '' : truncateNumber(props.state.replies, 2)}
title={props.state.replies.toLocaleString()}
large={props.large}
/>
<NoteFooterActionButton
@ -335,6 +337,7 @@ const NoteFooter: Component<{
label={props.state.satsZapped === 0 ? '' : truncateNumber(props.state.satsZapped, 2)}
hidden={props.state.hideZapIcon}
title={props.state.satsZapped.toLocaleString()}
large={props.large}
/>
<NoteFooterActionButton
@ -344,6 +347,7 @@ const NoteFooter: Component<{
highlighted={props.state.liked}
label={props.state.likes === 0 ? '' : truncateNumber(props.state.likes, 2)}
title={props.state.likes.toLocaleString()}
large={props.large}
/>
<button
@ -357,7 +361,7 @@ const NoteFooter: Component<{
ref={repostMenu}
>
<div
class={styles.icon}
class={`${styles.icon} ${props.large ? styles.large : ''}`}
style={'visibility: visible'}
></div>
<div class={styles.statNumber}>
@ -373,7 +377,10 @@ const NoteFooter: Component<{
</div>
</button>
<BookmarkNote note={props.note} />
<BookmarkNote
note={props.note}
large={props.large}
/>
</div>
)

View File

@ -23,6 +23,7 @@ const NoteFooterActionButton: Component<{
label: string | number,
hidden?: boolean,
title?: string,
large?: boolean,
}> = (props) => {
return (
@ -36,9 +37,9 @@ const NoteFooterActionButton: Component<{
onTouchEnd={props.onTouchEnd ?? (() => {})}
disabled={props.disabled}
>
<div class={`${buttonTypeClasses[props.type]}`}>
<div class={`${buttonTypeClasses[props.type]} ${props.large ? styles.large : ''}`}>
<div
class={styles.icon}
class={`${styles.icon} ${props.large ? styles.large : ''}`}
style={props.hidden ? 'visibility: hidden': 'visibility: visible'}
></div>
<div class={styles.statNumber}>{props.label || ''}</div>

View File

@ -222,17 +222,7 @@ const NoteHeader: Component<{
<VerificationCheck
user={props.note.user}
fallback={<div class={styles.ellipsisIcon}></div>}
/>
<span
class={styles.time}
title={date(props.note.post?.created_at).date.toLocaleString()}
>
{props.primary ?
longDate(props.note.post?.created_at) :
date(props.note.post?.created_at).label}
</span>
</div>
<Show
when={props.note.user?.nip05}

View File

@ -1,14 +1,9 @@
import { A } from '@solidjs/router';
import { Component, createMemo, createSignal, Show } from 'solid-js';
import { PrimalNote, PrimalRepost, PrimalUser } from '../../types/primal';
import ParsedNote from '../ParsedNote/ParsedNote';
import NoteFooter from './NoteFooter/NoteFooter';
import NoteHeader from './NoteHeader/NoteHeader';
import { Component, createMemo, Show } from 'solid-js';
import { PrimalNote } from '../../types/primal';
import styles from './Note.module.scss';
import { useThreadContext } from '../../contexts/ThreadContext';
import { useIntl } from '@cookbook/solid-intl';
import { authorName, nip05Verification, truncateNpub, userName } from '../../stores/profile';
import { note as t } from '../../translations';
import { hookForDev } from '../../lib/devTools';
import MentionedUserLink from './MentionedUserLink/MentionedUserLink';

View File

@ -86,7 +86,7 @@
padding: 12px;
background-color: var(--background-card);
border: none;
border-bottom: 1px solid var(--devider);
border-block: 1px solid var(--devider);
border-radius: 0;
outline: none;
display: flex;

View File

@ -18,6 +18,16 @@ export const longDate = (timestamp: number | undefined) => {
return dtf.format(date);
};
export const veryLongDate = (timestamp: number | undefined) => {
if (!timestamp || timestamp < 0) {
return '';
}
const date = new Date(timestamp * 1000);
const dtf = new Intl.DateTimeFormat('en-US', { dateStyle: 'full', timeStyle: 'short'});
return dtf.format(date);
};
export const date = (postTimestamp: number, style: Intl.RelativeTimeFormatStyle = 'short', since?: number) => {
const today = since ?? Math.floor((new Date()).getTime() / 1000);
const date = new Date(postTimestamp * 1000);

View File

@ -3,9 +3,7 @@ import Note from '../components/Note/Note';
import styles from './Thread.module.scss';
import { useNavigate, useParams } from '@solidjs/router';
import { PrimalNote, SendNoteResult } from '../types/primal';
import NotePrimary from '../components/Note/NotePrimary/NotePrimary';
import PeopleList from '../components/PeopleList/PeopleList';
import PageNav from '../components/PageNav/PageNav';
import ReplyToNote from '../components/ReplyToNote/ReplyToNote';
import { nip19 } from 'nostr-tools';
@ -13,7 +11,6 @@ import { useThreadContext } from '../contexts/ThreadContext';
import Wormhole from '../components/Wormhole/Wormhole';
import { useAccountContext } from '../contexts/AccountContext';
import { sortByRecency } from '../stores/note';
import { scrollWindowTo } from '../lib/scroll';
import { useIntl } from '@cookbook/solid-intl';
import Search from '../components/Search/Search';
import { placeholders as tPlaceholders, thread as t } from '../translations';