+ {t('profile.connect.direct_messaging_disabled', '{user} turned off direct messaging', {
+ user: user.name,
+ })}
+
+ )}
+
- {/* No surface at all. The chips are pills, and a pill is already this page's signal for "you can
+ {/* Its own section rather than a subheading under Connect: it is a distinct thing to do, not a
+ detail of messaging, and a smaller heading nested inside another read as one.
+ No surface at all. The chips are pills, and a pill is already this page's signal for "you can
click this" — the card was restating it in a heavier way, and it made this block outweigh the
two actions above it, which are boxless despite being just as actionable. Nothing on this page
is a card now; affordance is carried by the controls themselves. */}
-
-
-
- {t('profile.connect.private_connection_signal', 'Signal your interest — privately')}
-
- {/* Explaining the mechanism is only worth the row when the mechanism is available. */}
- {/*{hasSignalControls && (*/}
- {/* */}
- {/*)}*/}
-
+
+ {/* Explaining the mechanism is only worth the row when the mechanism is available. */}
+ {/*{hasSignalControls && (*/}
+ {/* */}
+ {/*)}*/}
{profile.allow_interest_indicating ? (
<>
{hasSignalControls && (
-
+
{t(
'profile.wont_be_notified_unless_mutual',
"Pick what you'd be open to with {name}. They're never notified unless they pick the same thing — then you both hear about it at once.",
@@ -158,7 +156,7 @@ export function ConnectActions(props: {profile: Profile; user: User}) {
{/* Every option locked means the chips can only say "no" three times over, in a shape that
still looks pressable. Say it once instead, and give back the height. */}
{noSharedTypes ? (
-
+
{t(
'profile.connect.no_shared_types',
"You and {name} aren't open to the same kind of connection.",
@@ -239,13 +237,13 @@ export function ConnectActions(props: {profile: Profile; user: User}) {
)}
>
) : (
-
+
{t('profile.turned_off_interest_indicators', '{user} turned off interest indicators', {
user: user.name,
})}
)}
-
-
+
+ >
)
}
diff --git a/web/components/profile/profile-info.tsx b/web/components/profile/profile-info.tsx
index ddc0f389..ad7f9d1d 100644
--- a/web/components/profile/profile-info.tsx
+++ b/web/components/profile/profile-info.tsx
@@ -13,6 +13,7 @@ import {ProfileHeaderActions} from 'web/components/profile/profile-header'
import ProfileHero from 'web/components/profile/profile-hero'
import ProfilePhotoCarousel from 'web/components/profile/profile-photo-carousel'
import {useProfilePhotos} from 'web/components/profile/profile-photos'
+import {Section, SectionHeading} from 'web/components/profile/section'
import ProfileAbout, {
hasAccessibility,
hasBigFive,
@@ -376,21 +377,6 @@ function RailBlocks(props: {
)
}
-/**
- * A section of the main reading column. No border and no card — the column is prose, and whitespace
- * plus a small-caps label separates sections better than five stacked boxes do.
- */
-function Section(props: {title?: ReactNode; id?: string; children: ReactNode; testId?: string}) {
- const {title, id, children, testId} = props
- if (children == null) return null
- return (
-
- {title != null && {title}}
- {children}
-
- )
-}
-
/**
* A block of the attribute rail: label, rule, content — the same object as `Section` on the left, with
* a rule added because the rail's rows are also rule-separated and the heading needs to sit outside
@@ -419,18 +405,6 @@ function RailSection(props: {title?: ReactNode; children: ReactNode}) {
)
}
-function SectionHeading(props: {children: ReactNode; className?: string}) {
- const {children, className} = props
- return (
-
- {children}
-
- )
-}
-
function ProfileContent(props: {
user: User
userActivity?: UserActivity
@@ -557,11 +531,9 @@ function ProfileContent(props: {
/>
- {!isCurrentUser && (
-
-
-
- )}
+ {/* Renders its own sections — reaching out and signalling interest privately are two
+ separate things to do, and each gets the same heading as everything else here. */}
+ {!isCurrentUser && }
)}
{!currentUser && }
diff --git a/web/components/profile/section.tsx b/web/components/profile/section.tsx
new file mode 100644
index 00000000..4749770c
--- /dev/null
+++ b/web/components/profile/section.tsx
@@ -0,0 +1,37 @@
+import clsx from 'clsx'
+import {ReactNode} from 'react'
+
+/**
+ * A section of the main reading column. No border and no card — the column is prose, and whitespace
+ * plus a small-caps label separates sections better than five stacked boxes do.
+ *
+ * Lives here rather than in `profile-info` so the sections it composes — Connect and the interest
+ * signal among them — can build themselves out of the same heading without importing their parent.
+ */
+export function Section(props: {
+ title?: ReactNode
+ id?: string
+ children: ReactNode
+ testId?: string
+}) {
+ const {title, id, children, testId} = props
+ if (children == null) return null
+ return (
+
+ {title != null && {title}}
+ {children}
+
+ )
+}
+
+export function SectionHeading(props: {children: ReactNode; className?: string}) {
+ const {children, className} = props
+ return (
+