mirror of
https://github.com/PrimalHQ/primal-web-app.git
synced 2024-10-01 17:31:13 +00:00
Redesigned people list
This commit is contained in:
parent
e359b127a2
commit
20b4bf76da
@ -90,8 +90,6 @@ const Cashu: Component< { id?: string, token: string, alternative?: boolean, noB
|
|||||||
lnurl,
|
lnurl,
|
||||||
)}&autopay=yes`;
|
)}&autopay=yes`;
|
||||||
|
|
||||||
console.log('Redeem: ', url);
|
|
||||||
|
|
||||||
window.open(url, 'blank_');
|
window.open(url, 'blank_');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
45
src/components/PeopleList/MentionedPeople.tsx
Normal file
45
src/components/PeopleList/MentionedPeople.tsx
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import { A } from '@solidjs/router';
|
||||||
|
import { Component, For, Show } from 'solid-js';
|
||||||
|
import { useAccountContext } from '../../contexts/AccountContext';
|
||||||
|
import { hookForDev } from '../../lib/devTools';
|
||||||
|
import { authorName, nip05Verification, truncateNpub } from '../../stores/profile';
|
||||||
|
import { PrimalNote, PrimalUser } from '../../types/primal';
|
||||||
|
import Avatar from '../Avatar/Avatar';
|
||||||
|
import FollowButton from '../FollowButton/FollowButton';
|
||||||
|
import MentionedPerson from './MentionedPerson';
|
||||||
|
|
||||||
|
import styles from './PeopleList.module.scss';
|
||||||
|
|
||||||
|
|
||||||
|
const MentionedPeople: Component<{
|
||||||
|
mentioned: PrimalUser[],
|
||||||
|
label: string,
|
||||||
|
id?: string,
|
||||||
|
author: PrimalUser,
|
||||||
|
}> = (props) => {
|
||||||
|
const account = useAccountContext();
|
||||||
|
|
||||||
|
const author = () => props.author;
|
||||||
|
const mentioned = () => props.mentioned;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div class={styles.heading}>{props.label}</div>
|
||||||
|
<div id="trending_section" class={styles.authorSection}>
|
||||||
|
<MentionedPerson
|
||||||
|
person={author()}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<For each={mentioned()}>
|
||||||
|
{(person) =>
|
||||||
|
<MentionedPerson
|
||||||
|
person={person}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default hookForDev(MentionedPeople);
|
54
src/components/PeopleList/MentionedPerson.tsx
Normal file
54
src/components/PeopleList/MentionedPerson.tsx
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import { A } from '@solidjs/router';
|
||||||
|
import { Component, For, Show } from 'solid-js';
|
||||||
|
import { useAccountContext } from '../../contexts/AccountContext';
|
||||||
|
import { hookForDev } from '../../lib/devTools';
|
||||||
|
import { authorName, nip05Verification, truncateNpub } from '../../stores/profile';
|
||||||
|
import { PrimalNote, PrimalUser } from '../../types/primal';
|
||||||
|
import Avatar from '../Avatar/Avatar';
|
||||||
|
import FollowButton from '../FollowButton/FollowButton';
|
||||||
|
|
||||||
|
import styles from './PeopleList.module.scss';
|
||||||
|
|
||||||
|
|
||||||
|
const MentionedPerson: Component<{
|
||||||
|
person: PrimalUser,
|
||||||
|
id?: string,
|
||||||
|
}> = (props) => {
|
||||||
|
const account = useAccountContext();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<A href={`/p/${props.person?.npub}`} class={styles.mentionedPerson}>
|
||||||
|
<div class={styles.header}>
|
||||||
|
<Avatar
|
||||||
|
size="sm"
|
||||||
|
user={props.person}
|
||||||
|
/>
|
||||||
|
<div class={styles.content}>
|
||||||
|
<div class={styles.name}>
|
||||||
|
{authorName(props.person)}
|
||||||
|
</div>
|
||||||
|
<div class={styles.verification} title={props.person?.nip05}>
|
||||||
|
<Show when={props.person?.nip05}>
|
||||||
|
<span
|
||||||
|
class={styles.verifiedBy}
|
||||||
|
title={props.person?.nip05}
|
||||||
|
>
|
||||||
|
{nip05Verification(props.person)}
|
||||||
|
</span>
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Show when={account?.publicKey !== props.person?.pubkey || !account?.following.includes(props.person?.pubkey || '')}>
|
||||||
|
<FollowButton person={props.person} />
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class={styles.about}>
|
||||||
|
{props.person.about || ''}
|
||||||
|
</div>
|
||||||
|
</A>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default hookForDev(MentionedPerson);
|
@ -5,7 +5,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 44px;
|
height: 44px;
|
||||||
z-index: 5;
|
z-index: 5;
|
||||||
padding-bottom: 22px;
|
padding-block: 22px;
|
||||||
display:flex;
|
display:flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -25,6 +25,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.authorSection {
|
||||||
|
// position: -webkit-sticky;
|
||||||
|
// position: sticky;
|
||||||
|
// top: 0px;
|
||||||
|
// padding-top: 44px;
|
||||||
|
}
|
||||||
|
|
||||||
.trendingSection {
|
.trendingSection {
|
||||||
// position: -webkit-sticky;
|
// position: -webkit-sticky;
|
||||||
// position: sticky;
|
// position: sticky;
|
||||||
@ -48,6 +55,25 @@
|
|||||||
@include heading();
|
@include heading();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@mixin followButton {
|
||||||
|
grid-area: follow;
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
button {
|
||||||
|
width: 72px;
|
||||||
|
height: 28px;
|
||||||
|
background: var(--brand-gradient);
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 0px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 16px;
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
.peopleList {
|
.peopleList {
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
display: grid;
|
display: grid;
|
||||||
@ -79,9 +105,9 @@
|
|||||||
|
|
||||||
.name {
|
.name {
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
font-weight: 400;
|
font-size: 16px;
|
||||||
font-size: 12px;
|
font-weight: 700;
|
||||||
line-height: 12px;
|
line-height: 16px;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@ -117,6 +143,22 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.about {
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 16px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: var(--text-tertiary-2);
|
||||||
|
|
||||||
|
overflow: hidden;
|
||||||
|
display: -webkit-box;
|
||||||
|
line-clamp: 3;
|
||||||
|
-webkit-line-clamp: 3;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-moz-box-orient: vertical;
|
||||||
|
-ms-box-orient: vertical;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
.message, .name, .time {
|
.message, .name, .time {
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
@ -127,25 +169,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin followButton {
|
|
||||||
grid-area: follow;
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
button {
|
|
||||||
width: 72px;
|
|
||||||
height: 28px;
|
|
||||||
background: var(--brand-gradient);
|
|
||||||
border-radius: 6px;
|
|
||||||
padding: 0px;
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 600;
|
|
||||||
line-height: 16px;
|
|
||||||
margin: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.follow {
|
.follow {
|
||||||
@include followButton;
|
@include followButton;
|
||||||
}
|
}
|
||||||
@ -168,6 +191,126 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.mentionedPerson {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 300px;
|
||||||
|
gap: 8px;
|
||||||
|
padding-block: 12px;
|
||||||
|
border-bottom: 1px solid var(--devider);
|
||||||
|
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.content {
|
||||||
|
grid-area: content;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 4px;
|
||||||
|
flex-grow: 1;
|
||||||
|
|
||||||
|
.name {
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 16px;
|
||||||
|
max-width: 168px;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.verification {
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 16px;
|
||||||
|
color: var(--text-tertiary-2);
|
||||||
|
max-width: 168px;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.verifiedName {
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 16px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--text-tertiary-2);
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.npub {
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 16px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: var(--text-tertiary-2);
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.follow {
|
||||||
|
@include followButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unfollow {
|
||||||
|
@include followButton;
|
||||||
|
button {
|
||||||
|
background-color: var(--background-card);
|
||||||
|
background: linear-gradient(var(--background-card), var(--background-card)) padding-box,
|
||||||
|
var(--brand-gradient) border-box;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.name {
|
||||||
|
text-decoration: underline;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.about {
|
||||||
|
width: 300px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 18px;
|
||||||
|
color: var(--text-tertiary-2);
|
||||||
|
|
||||||
|
overflow: hidden;
|
||||||
|
display: -webkit-box;
|
||||||
|
line-clamp: 3;
|
||||||
|
-webkit-line-clamp: 3;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-moz-box-orient: vertical;
|
||||||
|
-ms-box-orient: vertical;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
|
||||||
|
.content {
|
||||||
|
.name {
|
||||||
|
color: var(--text-primary);
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.verifiedIcon {
|
.verifiedIcon {
|
||||||
width:13px;
|
width:13px;
|
||||||
height: 12px;
|
height: 12px;
|
||||||
|
@ -3,58 +3,55 @@ import { Component, For, Show } from 'solid-js';
|
|||||||
import { useAccountContext } from '../../contexts/AccountContext';
|
import { useAccountContext } from '../../contexts/AccountContext';
|
||||||
import { hookForDev } from '../../lib/devTools';
|
import { hookForDev } from '../../lib/devTools';
|
||||||
import { authorName, nip05Verification, truncateNpub } from '../../stores/profile';
|
import { authorName, nip05Verification, truncateNpub } from '../../stores/profile';
|
||||||
import { PrimalUser } from '../../types/primal';
|
import { PrimalNote, PrimalUser } from '../../types/primal';
|
||||||
import Avatar from '../Avatar/Avatar';
|
import Avatar from '../Avatar/Avatar';
|
||||||
import FollowButton from '../FollowButton/FollowButton';
|
import FollowButton from '../FollowButton/FollowButton';
|
||||||
|
import MentionedPeople from './MentionedPeople';
|
||||||
|
|
||||||
import styles from './PeopleList.module.scss';
|
import styles from './PeopleList.module.scss';
|
||||||
|
import Repliers from './Repliers';
|
||||||
|
|
||||||
|
|
||||||
const PeopleList: Component<{ people: PrimalUser[], label: string, id?: string }> = (props) => {
|
const PeopleList: Component<{
|
||||||
|
people: PrimalUser[],
|
||||||
|
label: string,
|
||||||
|
id?: string,
|
||||||
|
note?: PrimalNote,
|
||||||
|
}> = (props) => {
|
||||||
const account = useAccountContext();
|
const account = useAccountContext();
|
||||||
|
|
||||||
const people = () => props.people;
|
const author = () => props.note?.user;
|
||||||
|
|
||||||
|
const mentioned = () => {
|
||||||
|
if (!props.note) return [];
|
||||||
|
|
||||||
|
return props.people.filter(p => p.pubkey !== author()?.pubkey && (props.note?.mentionedUsers || {})[p.pubkey] !== undefined);
|
||||||
|
};
|
||||||
|
|
||||||
|
const repliers = () => {
|
||||||
|
if (!props.note) return props.people;
|
||||||
|
|
||||||
|
return props.people.filter(p => p.pubkey !== author()?.pubkey && (props.note?.mentionedUsers || {})[p.pubkey] === undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id={props.id} class={styles.stickyWrapper}>
|
<div id={props.id} class={styles.stickyWrapper}>
|
||||||
<div class={styles.heading}>{props.label}</div>
|
<Show when={author()}>
|
||||||
<div id="trending_section" class={styles.trendingSection}>
|
<MentionedPeople
|
||||||
<For each={people()}>
|
mentioned={mentioned()}
|
||||||
{
|
author={author()}
|
||||||
(person) =>
|
label="People in this Note"
|
||||||
<A href={`/p/${person?.npub}`} class={styles.peopleList}>
|
/>
|
||||||
<div class={styles.avatar}>
|
</Show>
|
||||||
<Avatar
|
|
||||||
size="md"
|
<Show when={repliers().length > 0}>
|
||||||
user={person}
|
<Repliers
|
||||||
/>
|
people={repliers()}
|
||||||
</div>
|
label={props.label}
|
||||||
<div class={styles.content}>
|
/>
|
||||||
<div class={styles.name}>
|
</Show>
|
||||||
{authorName(person)}
|
|
||||||
</div>
|
|
||||||
<div class={styles.verification} title={person?.nip05}>
|
|
||||||
<Show when={person?.nip05}>
|
|
||||||
<span
|
|
||||||
class={styles.verifiedBy}
|
|
||||||
title={person?.nip05}
|
|
||||||
>
|
|
||||||
{nip05Verification(person)}
|
|
||||||
</span>
|
|
||||||
</Show>
|
|
||||||
</div>
|
|
||||||
<div class={styles.npub} title={person?.npub}>
|
|
||||||
{truncateNpub(person?.npub)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<Show when={account?.publicKey !== person.pubkey || !account?.following.includes(person.pubkey)}>
|
|
||||||
<FollowButton person={person} />
|
|
||||||
</Show>
|
|
||||||
</A>
|
|
||||||
}
|
|
||||||
</For>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
62
src/components/PeopleList/Repliers.tsx
Normal file
62
src/components/PeopleList/Repliers.tsx
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import { A } from '@solidjs/router';
|
||||||
|
import { Component, For, Show } from 'solid-js';
|
||||||
|
import { useAccountContext } from '../../contexts/AccountContext';
|
||||||
|
import { hookForDev } from '../../lib/devTools';
|
||||||
|
import { authorName, nip05Verification, truncateNpub } from '../../stores/profile';
|
||||||
|
import { PrimalNote, PrimalUser } from '../../types/primal';
|
||||||
|
import Avatar from '../Avatar/Avatar';
|
||||||
|
import FollowButton from '../FollowButton/FollowButton';
|
||||||
|
|
||||||
|
import styles from './PeopleList.module.scss';
|
||||||
|
|
||||||
|
|
||||||
|
const Repliers: Component<{
|
||||||
|
people: PrimalUser[],
|
||||||
|
label: string,
|
||||||
|
id?: string,
|
||||||
|
}> = (props) => {
|
||||||
|
const account = useAccountContext();
|
||||||
|
|
||||||
|
const people = () => props.people;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div class={styles.heading}>{props.label}</div>
|
||||||
|
<div id="trending_section" class={styles.trendingSection}>
|
||||||
|
<For each={people()}>
|
||||||
|
{
|
||||||
|
(person) =>
|
||||||
|
<A href={`/p/${person?.npub}`} class={styles.peopleList}>
|
||||||
|
<div class={styles.avatar}>
|
||||||
|
<Avatar
|
||||||
|
size="md"
|
||||||
|
user={person}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class={styles.content}>
|
||||||
|
<div class={styles.name}>
|
||||||
|
{authorName(person)}
|
||||||
|
</div>
|
||||||
|
<div class={styles.verification} title={person?.nip05}>
|
||||||
|
<Show when={person?.nip05}>
|
||||||
|
<span
|
||||||
|
class={styles.verifiedBy}
|
||||||
|
title={person?.nip05}
|
||||||
|
>
|
||||||
|
{nip05Verification(person)}
|
||||||
|
</span>
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Show when={account?.publicKey !== person.pubkey || !account?.following.includes(person.pubkey)}>
|
||||||
|
<FollowButton person={person} />
|
||||||
|
</Show>
|
||||||
|
</A>
|
||||||
|
}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default hookForDev(Repliers);
|
@ -160,6 +160,7 @@ const Thread: Component = () => {
|
|||||||
|
|
||||||
<Wormhole to='right_sidebar'>
|
<Wormhole to='right_sidebar'>
|
||||||
<PeopleList
|
<PeopleList
|
||||||
|
note={primaryNote()}
|
||||||
people={people()}
|
people={people()}
|
||||||
label={intl.formatMessage(t.sidebar)}
|
label={intl.formatMessage(t.sidebar)}
|
||||||
/>
|
/>
|
||||||
|
Loading…
Reference in New Issue
Block a user