From f4348e367da7f2ad85b7680572de69c6bd62e6ff Mon Sep 17 00:00:00 2001 From: Ole-Martin Bratteng <1681525+omBratteng@users.noreply.github.com> Date: Fri, 23 Jan 2026 17:58:57 +0100 Subject: [PATCH 1/2] feat: add user setting for which default post type to use --- .../src/components/fields/form/common.tsx | 2 +- .../freeform/write/WriteFreeFormSkeleton.tsx | 16 +++---- .../post/freeform/write/WritePostHeader.tsx | 2 +- .../src/components/tabs/TabContainer.tsx | 3 ++ .../shared/src/contexts/SettingsContext.tsx | 2 + packages/shared/src/graphql/settings.ts | 2 + packages/webapp/pages/settings/appearance.tsx | 38 +++++++++++++++- packages/webapp/pages/squads/create.tsx | 45 +++++++++++++++++-- 8 files changed, 94 insertions(+), 16 deletions(-) diff --git a/packages/shared/src/components/fields/form/common.tsx b/packages/shared/src/components/fields/form/common.tsx index bd3bde5fa5..e01ac0cbb8 100644 --- a/packages/shared/src/components/fields/form/common.tsx +++ b/packages/shared/src/components/fields/form/common.tsx @@ -1,6 +1,6 @@ export enum WriteFormTab { - Share = 'Share a link', NewPost = 'New post', + Share = 'Share a link', Poll = 'Poll', } diff --git a/packages/shared/src/components/post/freeform/write/WriteFreeFormSkeleton.tsx b/packages/shared/src/components/post/freeform/write/WriteFreeFormSkeleton.tsx index 1ea227b0e8..494830b09e 100644 --- a/packages/shared/src/components/post/freeform/write/WriteFreeFormSkeleton.tsx +++ b/packages/shared/src/components/post/freeform/write/WriteFreeFormSkeleton.tsx @@ -14,15 +14,13 @@ export function WriteFreeFormSkeleton({ return ( - - - - - - - - - + + + + + + + ); diff --git a/packages/shared/src/components/post/freeform/write/WritePostHeader.tsx b/packages/shared/src/components/post/freeform/write/WritePostHeader.tsx index 463d8f1166..5bee70a90a 100644 --- a/packages/shared/src/components/post/freeform/write/WritePostHeader.tsx +++ b/packages/shared/src/components/post/freeform/write/WritePostHeader.tsx @@ -14,7 +14,7 @@ export function WritePostHeader({ const { squad } = useWritePostContext(); return ( -
+

{isEdit ? 'Edit' : 'New'} post

{squad && squad.type === SourceType.Squad && ( diff --git a/packages/shared/src/components/tabs/TabContainer.tsx b/packages/shared/src/components/tabs/TabContainer.tsx index 7c3cf9a9a0..3fad5ef2aa 100644 --- a/packages/shared/src/components/tabs/TabContainer.tsx +++ b/packages/shared/src/components/tabs/TabContainer.tsx @@ -50,6 +50,7 @@ export interface TabContainerProps { style?: CSSProperties; tabListProps?: Pick; tabTag?: AllowedTabTags; + extraHeaderContent?: ReactNode; } export function TabContainer({ @@ -65,6 +66,7 @@ export function TabContainer({ style, tabListProps = {}, tabTag, + extraHeaderContent, }: TabContainerProps): ReactElement { const router = useRouter(); const containerRef = useRef(null); @@ -168,6 +170,7 @@ export function TabContainer({ autoScrollActive={tabListProps?.autoScrollActive} tag={tabTag} /> + {extraHeaderContent}
{render} diff --git a/packages/shared/src/contexts/SettingsContext.tsx b/packages/shared/src/contexts/SettingsContext.tsx index 065effa84e..bf1e3f8b3a 100644 --- a/packages/shared/src/contexts/SettingsContext.tsx +++ b/packages/shared/src/contexts/SettingsContext.tsx @@ -17,6 +17,7 @@ import { CampaignCtaPlacement, UPDATE_USER_SETTINGS_MUTATION, } from '../graphql/settings'; +import { WriteFormTab } from '../components/fields/form/common'; import AuthContext from './AuthContext'; import { capitalize } from '../lib/strings'; import { storageWrapper } from '../lib/storageWrapper'; @@ -136,6 +137,7 @@ const defaultSettings: RemoteSettings = { sidebarResourcesExpanded: true, sidebarBookmarksExpanded: true, clickbaitShieldEnabled: true, + defaultWriteTab: WriteFormTab.NewPost, }, }; diff --git a/packages/shared/src/graphql/settings.ts b/packages/shared/src/graphql/settings.ts index df5c764025..03862d6b0a 100644 --- a/packages/shared/src/graphql/settings.ts +++ b/packages/shared/src/graphql/settings.ts @@ -1,5 +1,6 @@ import { gql } from 'graphql-request'; import type { SortCommentsBy } from './comments'; +import type { WriteFormTab } from '../components/fields/form/common'; export type Spaciness = 'eco' | 'roomy' | 'cozy'; export type RemoteTheme = 'darcula' | 'bright' | 'auto'; @@ -19,6 +20,7 @@ export type SettingsFlags = { timezoneMismatchIgnore?: string; prompt?: Record; lastPrompt?: string; + defaultWriteTab?: WriteFormTab; }; export enum SidebarSettingsFlags { diff --git a/packages/webapp/pages/settings/appearance.tsx b/packages/webapp/pages/settings/appearance.tsx index 3a0b6e2169..ea2fdba6e7 100644 --- a/packages/webapp/pages/settings/appearance.tsx +++ b/packages/webapp/pages/settings/appearance.tsx @@ -10,6 +10,7 @@ import { TypographyColor, TypographyType, } from '@dailydotdev/shared/src/components/typography/Typography'; +import type { RadioItemProps } from '@dailydotdev/shared/src/components/fields/Radio'; import { Radio } from '@dailydotdev/shared/src/components/fields/Radio'; import { ToggleRadio } from '@dailydotdev/shared/src/components/fields/ToggleRadio'; import { useLogContext } from '@dailydotdev/shared/src/contexts/LogContext'; @@ -18,19 +19,28 @@ import { TargetId, TargetType, } from '@dailydotdev/shared/src/lib/log'; +import { WriteFormTab } from '@dailydotdev/shared/src/components/fields/form/common'; import classNames from 'classnames'; +import { Divider } from '@dailydotdev/shared/src/components/utilities'; import { AccountPageContainer } from '../../components/layouts/SettingsLayout/AccountPageContainer'; import { getSettingsLayout } from '../../components/layouts/SettingsLayout'; import { defaultSeo } from '../../next-seo'; import { getTemplatedTitle } from '../../components/layouts/utils'; import { SettingsSwitch } from '../../components/layouts/SettingsLayout/common'; -const densities = [ +const densities: RadioItemProps[] = [ { label: 'Eco', value: 'eco' }, { label: 'Roomy', value: 'roomy' }, { label: 'Cozy', value: 'cozy' }, ]; +const defaultWriteTabs: RadioItemProps[] = Object.keys(WriteFormTab).map( + (key) => ({ + label: WriteFormTab[key], + value: key, + }), +); + const AccountManageSubscriptionPage = (): ReactElement => { const isLaptop = useViewSize(ViewSize.Laptop); const { logEvent } = useLogContext(); @@ -48,6 +58,8 @@ const AccountManageSubscriptionPage = (): ReactElement => { toggleOptOutCompanion, autoDismissNotifications, toggleAutoDismissNotifications, + updateFlag, + flags, } = useSettingsContext(); const onLayoutToggle = useCallback( @@ -164,6 +176,30 @@ const AccountManageSubscriptionPage = (): ReactElement => { Auto-hide notifications after a few seconds + + + +
+
+ + Default post type + + + { + updateFlag('defaultWriteTab', value); + }} + className={{ + content: 'w-full justify-between !pr-0', + container: '!gap-0', + label: 'font-normal text-text-secondary typo-callout', + }} + reverse + /> +
); diff --git a/packages/webapp/pages/squads/create.tsx b/packages/webapp/pages/squads/create.tsx index 78c3a05574..1756df3946 100644 --- a/packages/webapp/pages/squads/create.tsx +++ b/packages/webapp/pages/squads/create.tsx @@ -36,11 +36,19 @@ import { useQueryClient } from '@tanstack/react-query'; import CreatePoll from '@dailydotdev/shared/src/components/post/poll/CreatePoll'; import { Pill, PillSize } from '@dailydotdev/shared/src/components/Pill'; import { useMultipleSourcePost } from '@dailydotdev/shared/src/features/squads/hooks/useMultipleSourcePost'; -import { webappUrl } from '@dailydotdev/shared/src/lib/constants'; +import { settingsUrl, webappUrl } from '@dailydotdev/shared/src/lib/constants'; import type { WriteForm } from '@dailydotdev/shared/src/contexts'; -import { getLayout as getMainLayout } from '../../components/layouts/MainLayout'; -import { defaultOpenGraph, defaultSeo } from '../../next-seo'; +import { useSettingsContext } from '@dailydotdev/shared/src/contexts/SettingsContext'; + +import { + Button, + ButtonSize, +} from '@dailydotdev/shared/src/components/buttons/Button'; +import { SettingsIcon } from '@dailydotdev/shared/src/components/icons'; +import { LinkWithTooltip } from '@dailydotdev/shared/src/components/tooltips/LinkWithTooltip'; import { getTemplatedTitle } from '../../components/layouts/utils'; +import { defaultOpenGraph, defaultSeo } from '../../next-seo'; +import { getLayout as getMainLayout } from '../../components/layouts/MainLayout'; const seo: NextSeoProps = { title: getTemplatedTitle('Create post'), @@ -59,6 +67,10 @@ function CreatePost(): ReactElement { ); const { push, isReady: isRouteReady, query } = useRouter(); const { squads, user, isAuthReady, isFetched } = useAuthContext(); + const { + flags: { defaultWriteTab }, + loadedSettings, + } = useSettingsContext(); const [selectedSourceIds, setSelectedSourceIds] = useState([]); const activeSquads = useMemo(() => { const collator = new Intl.Collator('en'); @@ -191,6 +203,8 @@ function CreatePost(): ReactElement { setDisplay(WriteFormTab.Share); } else if (isInitialPoll) { setDisplay(WriteFormTab.Poll); + } else if (defaultWriteTab in WriteFormTab) { + setDisplay(WriteFormTab[defaultWriteTab]); } const preselectedSquad = @@ -220,6 +234,7 @@ function CreatePost(): ReactElement { activeSquads, selectedSourceIds.length, query, + defaultWriteTab, ]); useEffect(() => { @@ -228,7 +243,7 @@ function CreatePost(): ReactElement { } }, [display, hasCheckedPollTab, completeAction]); - if (!isFetched || !isAuthReady || !isRouteReady) { + if (!isFetched || !isAuthReady || !isRouteReady || !loadedSettings) { return ; } @@ -255,6 +270,28 @@ function CreatePost(): ReactElement { shouldMountInactive className={{ header: 'px-1' }} showHeader={isTablet} + extraHeaderContent={ + !isMobile && ( + + You can change the default post type settings + + ), + placement: 'left', + }} + href={`${settingsUrl}/appearance#compose`} + passHref + > +