diff --git a/packages/shared/src/components/feeds/FeedSettings/sections/FeedSettingsGeneralSection.tsx b/packages/shared/src/components/feeds/FeedSettings/sections/FeedSettingsGeneralSection.tsx
index 5c65c3285c7..b5b765c680c 100644
--- a/packages/shared/src/components/feeds/FeedSettings/sections/FeedSettingsGeneralSection.tsx
+++ b/packages/shared/src/components/feeds/FeedSettings/sections/FeedSettingsGeneralSection.tsx
@@ -19,8 +19,14 @@ import { useAuthContext } from '../../../../contexts/AuthContext';
import { ColorName } from '../../../../styles/colors';
import useProfileForm from '../../../../hooks/useProfileForm';
import { FeedType } from '../../../../graphql/feed';
-import { usePlusSubscription } from '../../../../hooks';
+import { usePlusSubscription, useToastNotification } from '../../../../hooks';
import { Tooltip } from '../../../tooltip/Tooltip';
+import { Switch } from '../../../fields/Switch';
+import { useSettingsContext } from '../../../../contexts/SettingsContext';
+import { SidebarSettingsFlags } from '../../../../graphql/settings';
+import { useLogContext } from '../../../../contexts/LogContext';
+import { LogEvent, Origin, TargetId } from '../../../../lib/log';
+import { labels } from '../../../../lib';
export const FeedSettingsGeneralSection = (): ReactElement => {
const { setData, data, feed, onDelete, editFeedSettings } = useContext(
@@ -31,6 +37,9 @@ export const FeedSettingsGeneralSection = (): ReactElement => {
const isMainFeed = feed?.type === FeedType.Main;
const isCustomFeed = feed?.type === FeedType.Custom;
const { isPlus } = usePlusSubscription();
+ const { flags, updateFlag } = useSettingsContext();
+ const { displayToast } = useToastNotification();
+ const { logEvent } = useLogContext();
const isDefaultFeed = isMainFeed
? user.defaultFeedId === null
@@ -167,6 +176,48 @@ export const FeedSettingsGeneralSection = (): ReactElement => {
)}
+
+
+
+
+ Pin highlights to top
+
+
+ When highlights appear in your feed, show them in the first
+ position. Otherwise they're placed somewhere near the top.
+
+
+
{
+ const newState = !(flags?.highlightsFirstEnabled ?? false);
+ await updateFlag(
+ SidebarSettingsFlags.HighlightsFirstEnabled,
+ newState,
+ );
+
+ displayToast(
+ labels.feed.settings.globalPreferenceNotice.highlightsFirst,
+ );
+
+ logEvent({
+ event_name: LogEvent.ToggleHighlightsFirst,
+ target_id: newState ? TargetId.On : TargetId.Off,
+ extra: JSON.stringify({
+ origin: Origin.Settings,
+ }),
+ });
+ }}
+ >
+ Pin highlights to first position
+
+
{isCustomFeed && (
<>
diff --git a/packages/shared/src/graphql/settings.ts b/packages/shared/src/graphql/settings.ts
index 9395806461b..6daa930135a 100644
--- a/packages/shared/src/graphql/settings.ts
+++ b/packages/shared/src/graphql/settings.ts
@@ -44,6 +44,7 @@ export type SettingsFlags = {
sidebarResourcesExpanded: boolean;
sidebarBookmarksExpanded: boolean;
clickbaitShieldEnabled: boolean;
+ highlightsFirstEnabled?: boolean;
timezoneMismatchIgnore?: string;
prompt?: Record;
defaultWriteTab?: WriteFormTab;
@@ -65,6 +66,7 @@ export enum SidebarSettingsFlags {
ResourcesExpanded = 'sidebarResourcesExpanded',
BookmarksExpanded = 'sidebarBookmarksExpanded',
ClickbaitShieldEnabled = 'clickbaitShieldEnabled',
+ HighlightsFirstEnabled = 'highlightsFirstEnabled',
}
export type RemoteSettings = {
diff --git a/packages/shared/src/lib/labels.ts b/packages/shared/src/lib/labels.ts
index 484395d26fe..f311aeb90db 100644
--- a/packages/shared/src/lib/labels.ts
+++ b/packages/shared/src/lib/labels.ts
@@ -88,6 +88,8 @@ export const labels = {
globalPreferenceNotice: {
clickbaitShield: 'Clickbait shield has been applied for all feeds',
contentLanguage: 'New language preferences set for all feeds',
+ highlightsFirst:
+ 'Highlights pinning preference applied to all your feeds',
},
},
},
diff --git a/packages/shared/src/lib/log.ts b/packages/shared/src/lib/log.ts
index 8142d3eaaba..06227beaf07 100644
--- a/packages/shared/src/lib/log.ts
+++ b/packages/shared/src/lib/log.ts
@@ -339,6 +339,7 @@ export enum LogEvent {
ToggleClickbaitShield = 'toggle clickbait shield',
ClickbaitShieldTitle = 'clickbait shield title',
// End Clickbait Shield
+ ToggleHighlightsFirst = 'toggle highlights first',
InstallPWA = 'install pwa',
// Start Share
ShareProfile = 'share profile',
diff --git a/scripts/typecheck-strict-changed.js b/scripts/typecheck-strict-changed.js
index c5569d3f888..75389dae3d6 100644
--- a/scripts/typecheck-strict-changed.js
+++ b/scripts/typecheck-strict-changed.js
@@ -74,6 +74,12 @@ const strictSkipList = new Set([
// path; pre-existing strict violations (queryResult.data optionality,
// NotificationItem reduce typing) are unrelated to the rename.
'packages/webapp/pages/notifications.tsx',
+ // Highlights-first toggle — touched only to add a new Switch subsection
+ // for the highlightsFirstEnabled flag. Pre-existing strict violations
+ // (auth user / feed optionality, Button prop mismatches, defaultFeedId
+ // null vs undefined) live on unrelated lines and should be addressed in
+ // a dedicated cleanup PR.
+ 'packages/shared/src/components/feeds/FeedSettings/sections/FeedSettingsGeneralSection.tsx',
]);
const changedFiles = getChangedTypescriptFiles().filter(