From 0147b25feae9fc51f4fcf24b3c37f8ad380d7edb Mon Sep 17 00:00:00 2001 From: Lee Hansel Solevilla <13744167+sshanzel@users.noreply.github.com> Date: Wed, 5 Jun 2024 15:11:37 +0800 Subject: [PATCH] feat: feed settings survey (#3174) --- packages/shared/src/components/Feed.tsx | 24 +++++- .../src/components/FeedItemComponent.tsx | 14 ++++ .../shared/src/components/buttons/Button.tsx | 4 +- .../cards/MarketingCta/MarketingCtaCard.tsx | 6 +- .../shared/src/components/cards/common.tsx | 1 + .../cards/survey/FeedSurveyBanner.tsx | 50 +++++++++++++ .../cards/survey/FeedSurveyCard.tsx | 66 +++++++++++++++++ .../src/components/cards/survey/common.ts | 12 +++ .../src/components/cards/survey/index.ts | 2 + .../components/cards/v1/MarketingCtaCard.tsx | 6 +- .../src/components/feeds/FeedContainer.tsx | 15 ++++ .../components/feeds/FeedSettingsButton.tsx | 42 +++++++++++ .../src/components/filters/MyFeedHeading.tsx | 15 ++-- .../src/components/utilities/RatingStars.tsx | 73 +++++++++++++++++++ packages/shared/src/contexts/AlertContext.tsx | 5 +- packages/shared/src/graphql/alerts.ts | 16 +++- .../shared/src/hooks/feed/useFeedSurvey.ts | 53 ++++++++++++++ packages/shared/src/hooks/useFeed.ts | 6 ++ packages/shared/src/lib/analytics.ts | 4 +- packages/shared/src/lib/featureManagement.ts | 1 + packages/shared/src/styles/custom.ts | 12 +++ packages/shared/tailwind/boxShadow.ts | 1 + 22 files changed, 406 insertions(+), 22 deletions(-) create mode 100644 packages/shared/src/components/cards/survey/FeedSurveyBanner.tsx create mode 100644 packages/shared/src/components/cards/survey/FeedSurveyCard.tsx create mode 100644 packages/shared/src/components/cards/survey/common.ts create mode 100644 packages/shared/src/components/cards/survey/index.ts create mode 100644 packages/shared/src/components/feeds/FeedSettingsButton.tsx create mode 100644 packages/shared/src/components/utilities/RatingStars.tsx create mode 100644 packages/shared/src/hooks/feed/useFeedSurvey.ts create mode 100644 packages/shared/src/styles/custom.ts diff --git a/packages/shared/src/components/Feed.tsx b/packages/shared/src/components/Feed.tsx index a20af3c5b7..582933578f 100644 --- a/packages/shared/src/components/Feed.tsx +++ b/packages/shared/src/components/Feed.tsx @@ -36,7 +36,14 @@ import ShareOptionsMenu from './ShareOptionsMenu'; import { SharedFeedPage } from './utilities'; import { FeedContainer, FeedContainerProps } from './feeds/FeedContainer'; import { ActiveFeedContext } from '../contexts'; -import { useBoot, useFeedLayout, useFeedVotePost } from '../hooks'; +import { + useBoot, + useConditionalFeature, + useFeedLayout, + useFeedVotePost, + useViewSize, + ViewSize, +} from '../hooks'; import { AllFeedPages, OtherFeedPage, @@ -51,6 +58,7 @@ import { useFeature } from './GrowthBookProvider'; import { feature } from '../lib/featureManagement'; import { acquisitionKey } from './cards/AcquisitionFormCard'; import { MarketingCtaVariant } from './cards/MarketingCta/common'; +import { useAlertsContext } from '../contexts/AlertContext'; export interface FeedProps extends Pick< @@ -148,6 +156,18 @@ export default function Feed({ insaneMode: listMode, loadedSettings, } = useContext(SettingsContext); + const { isFetched, alerts } = useAlertsContext(); + const shouldEvaluateSurvey = + !!user && + isFetched && + alerts.shouldShowFeedFeedback && + feedName === SharedFeedPage.MyFeed; + const { value: feedSurvey } = useConditionalFeature({ + feature: feature.feedSettingsFeedback, + shouldEvaluate: shouldEvaluateSurvey, + }); + const shouldShowSurvey = shouldEvaluateSurvey && feedSurvey; + const isLaptop = useViewSize(ViewSize.Laptop); const insaneMode = !forceCardMode && listMode; const numCards = currentSettings.numCards[spaciness ?? 'eco']; const isSquadFeed = feedName === OtherFeedPage.Squad; @@ -181,6 +201,7 @@ export default function Feed({ variables, options, showPublicSquadsEligibility, + shouldShowSurvey: shouldShowSurvey && isLaptop, settings: { disableAds, adPostLength: isSquadFeed ? 2 : undefined, @@ -408,6 +429,7 @@ export default function Feed({ actionButtons={actionButtons} isHorizontal={isHorizontal} feedContainerRef={feedContainerRef} + shouldShowSurvey={shouldShowSurvey && !isLaptop} > {items.map((_, index) => ( import(/* webpackChunkName: "commentPopup" */ './cards/CommentPopup'), @@ -281,6 +283,18 @@ export default function FeedItemComponent({ showImage={!insaneMode} /> ); + case FeedItemType.FeedSurvey: + return ( + , + }} + /> + ); case FeedItemType.UserAcquisition: return ; case FeedItemType.PublicSquadEligibility: diff --git a/packages/shared/src/components/buttons/Button.tsx b/packages/shared/src/components/buttons/Button.tsx index 15262c1770..2a7eb6203d 100644 --- a/packages/shared/src/components/buttons/Button.tsx +++ b/packages/shared/src/components/buttons/Button.tsx @@ -89,8 +89,8 @@ function ButtonComponent( aria-pressed={pressed} ref={ref} className={classNames( - `btn shadow-none focus-outline inline-flex cursor-pointer select-none - flex-row items-center border no-underline transition + `btn focus-outline inline-flex cursor-pointer select-none flex-row + items-center border no-underline shadow-none transition duration-200 ease-in-out typo-callout`, variant !== ButtonVariant.Option && 'justify-center font-bold', { iconOnly }, diff --git a/packages/shared/src/components/cards/MarketingCta/MarketingCtaCard.tsx b/packages/shared/src/components/cards/MarketingCta/MarketingCtaCard.tsx index eca2dcf61a..4aed49fc16 100644 --- a/packages/shared/src/components/cards/MarketingCta/MarketingCtaCard.tsx +++ b/packages/shared/src/components/cards/MarketingCta/MarketingCtaCard.tsx @@ -24,7 +24,7 @@ export function MarketingCtaCard({ trackEvent({ event_name: AnalyticsEvent.Impression, - target_type: TargetType.MarketingCtaCard, + target_type: TargetType.PromotionCard, target_id: marketingCta.campaignId, }); isImpressionTracked.current = true; @@ -33,7 +33,7 @@ export function MarketingCtaCard({ const onCtaClick = useCallback(() => { trackEvent({ event_name: AnalyticsEvent.Click, - target_type: TargetType.MarketingCtaCard, + target_type: TargetType.PromotionCard, target_id: marketingCta.campaignId, }); clearMarketingCta(marketingCta.campaignId); @@ -42,7 +42,7 @@ export function MarketingCtaCard({ const onCtaDismiss = useCallback(() => { trackEvent({ event_name: AnalyticsEvent.MarketingCtaDismiss, - target_type: TargetType.MarketingCtaCard, + target_type: TargetType.PromotionCard, target_id: marketingCta.campaignId, }); clearMarketingCta(marketingCta.campaignId); diff --git a/packages/shared/src/components/cards/common.tsx b/packages/shared/src/components/cards/common.tsx index 4e44426105..b2150b3eea 100644 --- a/packages/shared/src/components/cards/common.tsx +++ b/packages/shared/src/components/cards/common.tsx @@ -77,4 +77,5 @@ export enum FeedItemType { UserAcquisition = 'userAcquisition', PublicSquadEligibility = 'publicSquadEligibility', MarketingCta = 'marketingCta', + FeedSurvey = 'feedSurvey', } diff --git a/packages/shared/src/components/cards/survey/FeedSurveyBanner.tsx b/packages/shared/src/components/cards/survey/FeedSurveyBanner.tsx new file mode 100644 index 0000000000..77269dfaec --- /dev/null +++ b/packages/shared/src/components/cards/survey/FeedSurveyBanner.tsx @@ -0,0 +1,50 @@ +import React, { ReactElement, useState } from 'react'; +import { RatingStars } from '../../utilities/RatingStars'; +import { Button, ButtonSize, ButtonVariant } from '../../buttons/Button'; +import { useFeedSurvey } from '../../../hooks/feed/useFeedSurvey'; +import { FeedSurveyProps } from './common'; +import { feedSurveyBg, feedSurveyTopBorder } from '../../../styles/custom'; + +export function FeedSurveyBanner({ + max, + title, + lowScore, + postFeedbackMessage = 'Thank you for your feedback!', +}: FeedSurveyProps): ReactElement { + const [score, setScore] = useState(0); + const { submitted, onSubmit, onHide } = useFeedSurvey({ score }); + + return ( +
+
+
+
+

{title}

+ +
+ +
+ {submitted && ( +
+

+ {postFeedbackMessage} + {score <= lowScore.value ? lowScore.message : null} +

+ {score <= lowScore.value && lowScore.cta} +
+ )} +
+
+ ); +} diff --git a/packages/shared/src/components/cards/survey/FeedSurveyCard.tsx b/packages/shared/src/components/cards/survey/FeedSurveyCard.tsx new file mode 100644 index 0000000000..3ba5793621 --- /dev/null +++ b/packages/shared/src/components/cards/survey/FeedSurveyCard.tsx @@ -0,0 +1,66 @@ +import React, { ReactElement, useState } from 'react'; +import classNames from 'classnames'; +import { Card as CardV1 } from '../v1/Card'; +import { Card } from '../Card'; +import { useFeedLayout } from '../../../hooks'; +import { Button, ButtonSize, ButtonVariant } from '../../buttons/Button'; +import { RatingStars } from '../../utilities/RatingStars'; +import { useFeedSurvey } from '../../../hooks/feed/useFeedSurvey'; +import { FeedSurveyProps } from './common'; +import { feedSurveyBg, feedSurveyBorder } from '../../../styles/custom'; + +export function FeedSurveyCard({ + max, + title, + lowScore, + postFeedbackMessage = 'Thank you for your feedback!', +}: FeedSurveyProps): ReactElement { + const [score, setScore] = useState(0); + const { submitted, onSubmit, onHide } = useFeedSurvey({ score }); + const { shouldUseListFeedLayout } = useFeedLayout(); + const CardComponent = shouldUseListFeedLayout ? CardV1 : Card; + + return ( +
+ +

{title}

+ + {submitted && ( +

+ {postFeedbackMessage} + {score <= lowScore.value &&

{lowScore.message}

} + {score <= lowScore.value && lowScore.cta} +

+ )} + {score > 0 && !submitted && ( + + )} + {score === 0 && ( + + )} +
+
+ ); +} diff --git a/packages/shared/src/components/cards/survey/common.ts b/packages/shared/src/components/cards/survey/common.ts new file mode 100644 index 0000000000..edc58c19ba --- /dev/null +++ b/packages/shared/src/components/cards/survey/common.ts @@ -0,0 +1,12 @@ +import { ReactNode } from 'react'; + +export interface FeedSurveyProps { + title: string; + postFeedbackMessage?: string; + max: number; + lowScore: { + value: number; + message: string; + cta: ReactNode; + }; +} diff --git a/packages/shared/src/components/cards/survey/index.ts b/packages/shared/src/components/cards/survey/index.ts new file mode 100644 index 0000000000..4734b52971 --- /dev/null +++ b/packages/shared/src/components/cards/survey/index.ts @@ -0,0 +1,2 @@ +export * from './FeedSurveyBanner'; +export * from './FeedSurveyCard'; diff --git a/packages/shared/src/components/cards/v1/MarketingCtaCard.tsx b/packages/shared/src/components/cards/v1/MarketingCtaCard.tsx index eaab1bb6c7..2eba4d0fdd 100644 --- a/packages/shared/src/components/cards/v1/MarketingCtaCard.tsx +++ b/packages/shared/src/components/cards/v1/MarketingCtaCard.tsx @@ -30,7 +30,7 @@ export function MarketingCtaCardV1({ trackEvent({ event_name: AnalyticsEvent.Impression, - target_type: TargetType.MarketingCtaCard, + target_type: TargetType.PromotionCard, target_id: marketingCta.campaignId, }); isImpressionTracked.current = true; @@ -39,7 +39,7 @@ export function MarketingCtaCardV1({ const onCtaClick = useCallback(() => { trackEvent({ event_name: AnalyticsEvent.Click, - target_type: TargetType.MarketingCtaCard, + target_type: TargetType.PromotionCard, target_id: marketingCta.campaignId, }); clearMarketingCta(marketingCta.campaignId); @@ -48,7 +48,7 @@ export function MarketingCtaCardV1({ const onCtaDismiss = useCallback(() => { trackEvent({ event_name: AnalyticsEvent.MarketingCtaDismiss, - target_type: TargetType.MarketingCtaCard, + target_type: TargetType.PromotionCard, target_id: marketingCta.campaignId, }); clearMarketingCta(marketingCta.campaignId); diff --git a/packages/shared/src/components/feeds/FeedContainer.tsx b/packages/shared/src/components/feeds/FeedContainer.tsx index 4c0112f0db..b6d614e92a 100644 --- a/packages/shared/src/components/feeds/FeedContainer.tsx +++ b/packages/shared/src/components/feeds/FeedContainer.tsx @@ -25,6 +25,8 @@ import ConditionalWrapper from '../ConditionalWrapper'; import { useActiveFeedNameContext } from '../../contexts'; import { feature } from '../../lib/featureManagement'; import { SharedFeedPage } from '../utilities'; +import { FeedSurveyBanner } from '../cards/survey'; +import { FeedSettingsButton } from './FeedSettingsButton'; export interface FeedContainerProps { children: ReactNode; @@ -37,6 +39,7 @@ export interface FeedContainerProps { shortcuts?: ReactNode; actionButtons?: ReactNode; isHorizontal?: boolean; + shouldShowSurvey?: boolean; feedContainerRef?: React.Ref; } @@ -145,6 +148,7 @@ export const FeedContainer = ({ shortcuts, actionButtons, isHorizontal, + shouldShowSurvey, feedContainerRef, }: FeedContainerProps): ReactElement => { const { value: isShortcutsV1 } = useConditionalFeature({ @@ -269,6 +273,17 @@ export const FeedContainer = ({ )} > + {shouldShowSurvey && ( + , + }} + /> + )}
): ReactElement { + const { trackEvent } = useAnalyticsContext(); + const { openModal } = useLazyModal(); + const onButtonClick = (event: React.MouseEvent) => { + trackEvent({ event_name: AnalyticsEvent.ManageTags }); + + if (onClick) { + onClick(event); + } else { + openModal({ type: LazyModal.FeedFilters, persistOnRouteChange: true }); + } + }; + + return ( + + ); +} diff --git a/packages/shared/src/components/filters/MyFeedHeading.tsx b/packages/shared/src/components/filters/MyFeedHeading.tsx index 7e56f1a157..3cad727fff 100644 --- a/packages/shared/src/components/filters/MyFeedHeading.tsx +++ b/packages/shared/src/components/filters/MyFeedHeading.tsx @@ -17,6 +17,7 @@ import { setShouldRefreshFeed } from '../../lib/refreshFeed'; import { SharedFeedPage } from '../utilities'; import { getFeedName } from '../../lib/feed'; import { useFeedName } from '../../hooks/feed/useFeedName'; +import { FeedSettingsButton } from '../feeds/FeedSettingsButton'; export const filterAlertMessage = 'Edit your personal feed preferences here'; @@ -36,12 +37,6 @@ function MyFeedHeading({ const isLaptop = useViewSize(ViewSize.Laptop); const feedName = getFeedName(router.pathname); const { isCustomFeed } = useFeedName({ feedName }); - - const onClick = () => { - trackEvent({ event_name: AnalyticsEvent.ManageTags }); - onOpenFeedFilters(); - }; - const onRefresh = async () => { trackEvent({ event_name: AnalyticsEvent.RefreshFeed }); setShouldRefreshFeed(true); @@ -80,18 +75,18 @@ function MyFeedHeading({ {isLaptop ? 'Refresh feed' : null} )} - + ); } diff --git a/packages/shared/src/components/utilities/RatingStars.tsx b/packages/shared/src/components/utilities/RatingStars.tsx new file mode 100644 index 0000000000..8a6f710915 --- /dev/null +++ b/packages/shared/src/components/utilities/RatingStars.tsx @@ -0,0 +1,73 @@ +import React, { ReactElement, useState } from 'react'; +import classNames from 'classnames'; +import ConditionalWrapper from '../ConditionalWrapper'; +import { StarIcon } from '../icons'; +import { IconSize } from '../Icon'; + +interface RatingStarsProps { + max: number; + isDisabled?: boolean; + onStarClick?: (value: number) => void; +} + +export function RatingStars({ + max, + isDisabled, + onStarClick, +}: RatingStarsProps): ReactElement { + const [score, setScore] = useState(0); + const [hovered, setHovered] = useState(0); + const [justClicked, setJustClicked] = useState(false); + const highlighted = hovered || score; + + const onClick = (value: number) => { + setScore(value); + setJustClicked(true); + + if (onStarClick) { + onStarClick(value); + } + }; + + const onOut = () => { + setHovered(0); + setJustClicked(false); + }; + + return ( + + {Object.keys([...Array(max)]).map((key, i) => ( + ( + + )} + > + + + ))} + + ); +} diff --git a/packages/shared/src/contexts/AlertContext.tsx b/packages/shared/src/contexts/AlertContext.tsx index 0409fb9fd4..7df5b86c28 100644 --- a/packages/shared/src/contexts/AlertContext.tsx +++ b/packages/shared/src/contexts/AlertContext.tsx @@ -32,6 +32,7 @@ export interface AlertContextData { >; updateLastReferralReminder?: UseMutateAsyncFunction; updateLastBootPopup?: UseMutateAsyncFunction; + updateLocalBoot?: (alerts: Partial) => void; } export const MAX_DATE = new Date(3021, 0, 1); @@ -47,7 +48,6 @@ export interface AlertContextProviderProps { isFetched?: boolean; loadedAlerts?: boolean; updateAlerts?: (alerts: Alerts) => unknown; - updateLastReferralReminder?: () => unknown; updateLastBootPopup?: () => unknown; } @@ -124,8 +124,11 @@ export const AlertContextProvider = ({ updateAlerts: updateRemoteAlerts, updateLastReferralReminder, updateLastBootPopup, + updateLocalBoot: (params: Partial) => + updateAlerts({ ...alerts, ...params }), }), [ + updateAlerts, alerts, loadedAlerts, isFetched, diff --git a/packages/shared/src/graphql/alerts.ts b/packages/shared/src/graphql/alerts.ts index c64fa494e5..411c9c5f4d 100644 --- a/packages/shared/src/graphql/alerts.ts +++ b/packages/shared/src/graphql/alerts.ts @@ -1,4 +1,6 @@ -import { gql } from 'graphql-request'; +import request, { gql } from 'graphql-request'; +import { graphqlUrl } from '../lib/config'; +import { EmptyResponse } from './emptyResponse'; export type Alerts = { filter?: boolean; @@ -12,6 +14,7 @@ export type Alerts = { lastBanner?: string; banner?: boolean; showStreakMilestone?: boolean; + shouldShowFeedFeedback?: boolean; lastBootPopup?: Date; bootPopup?: boolean; }; @@ -48,3 +51,14 @@ export const UPDATE_LAST_BOOT_POPUP = gql` } } `; + +const UPDATE_FEED_FEEDBACK_REMINDER = ` + mutation UpdateFeedFeedbackReminder { + updateFeedFeedbackReminder { + _ + } + } +`; + +export const updateFeedFeedbackReminder = (): Promise => + request(graphqlUrl, UPDATE_FEED_FEEDBACK_REMINDER); diff --git a/packages/shared/src/hooks/feed/useFeedSurvey.ts b/packages/shared/src/hooks/feed/useFeedSurvey.ts new file mode 100644 index 0000000000..52a598d2fe --- /dev/null +++ b/packages/shared/src/hooks/feed/useFeedSurvey.ts @@ -0,0 +1,53 @@ +import { useEffect, useState } from 'react'; +import { useAnalyticsContext } from '../../contexts/AnalyticsContext'; +import { AnalyticsEvent, TargetId, TargetType } from '../../lib/analytics'; +import { updateFeedFeedbackReminder } from '../../graphql/alerts'; +import { useAlertsContext } from '../../contexts/AlertContext'; + +interface UseFeedSurvey { + submitted: boolean; + onSubmit: () => void; + onHide: () => void; +} + +interface UseFeedSurveyProps { + score: number; +} + +export const useFeedSurvey = ({ score }: UseFeedSurveyProps): UseFeedSurvey => { + const [submitted, setSubmitted] = useState(false); + const { trackEvent } = useAnalyticsContext(); + const { updateLocalBoot } = useAlertsContext(); + + const trackSurveyEvent = (event_name: AnalyticsEvent, extra?) => + trackEvent({ + target_type: TargetType.PromotionCard, + target_id: TargetId.FeedSurvey, + event_name, + extra, + }); + + const onSubmit = () => { + if (submitted) { + return; + } + + setSubmitted(true); + updateFeedFeedbackReminder(); + trackSurveyEvent(AnalyticsEvent.Click, { value: score }); + }; + + const onHide = () => { + updateFeedFeedbackReminder(); + trackSurveyEvent(AnalyticsEvent.DismissPromotion); + updateLocalBoot({ shouldShowFeedFeedback: false }); + }; + + useEffect(() => { + trackSurveyEvent(AnalyticsEvent.Impression); + // trackEvent is unstable, and we only need to track once + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return { submitted, onSubmit, onHide }; +}; diff --git a/packages/shared/src/hooks/useFeed.ts b/packages/shared/src/hooks/useFeed.ts index 8511aa5a96..2cbb52bd50 100644 --- a/packages/shared/src/hooks/useFeed.ts +++ b/packages/shared/src/hooks/useFeed.ts @@ -47,6 +47,7 @@ export type FeedItem = | PostItem | AdItem | MarketingCtaItem + | FeedItemBase | FeedItemBase | FeedItemBase | FeedItemBase; @@ -94,6 +95,7 @@ export interface UseFeedOptionalParams { options?: UseInfiniteQueryOptions; settings?: UseFeedSettingParams; showPublicSquadsEligibility?: boolean; + shouldShowSurvey?: boolean; } export default function useFeed( @@ -108,6 +110,7 @@ export default function useFeed( variables, options = {}, settings, + shouldShowSurvey, showPublicSquadsEligibility, } = params; const { user, tokenRefreshed } = useContext(AuthContext); @@ -191,6 +194,8 @@ export default function useFeed( }); } else if (withFirstIndex(settings.showAcquisitionForm)) { posts.splice(adSpot, 0, { type: FeedItemType.UserAcquisition }); + } else if (withFirstIndex(shouldShowSurvey)) { + posts.splice(adSpot, 0, { type: FeedItemType.FeedSurvey }); } else if (withFirstIndex(showPublicSquadsEligibility)) { posts.splice(adSpot, 0, { type: FeedItemType.PublicSquadEligibility, @@ -221,6 +226,7 @@ export default function useFeed( feedQuery.isFetching, settings.marketingCta, settings.showAcquisitionForm, + shouldShowSurvey, showPublicSquadsEligibility, isAdsQueryEnabled, adSpot, diff --git a/packages/shared/src/lib/analytics.ts b/packages/shared/src/lib/analytics.ts index 97026f6d75..95a0fa77d3 100644 --- a/packages/shared/src/lib/analytics.ts +++ b/packages/shared/src/lib/analytics.ts @@ -51,6 +51,7 @@ export enum Origin { } export enum AnalyticsEvent { + DismissPromotion = 'dismiss promotion', Click = 'click', CommentPost = 'comment post', StartSubmitArticle = 'start submit article', @@ -189,13 +190,14 @@ export enum TargetType { VerifyEmail = 'verify email', ResendVerificationCode = 'resend verification code', StreaksMilestone = 'streaks milestone', - MarketingCtaCard = 'promotion_card', + PromotionCard = 'promotion_card', MarketingCtaPopover = 'promotion_popover', Comment = 'comment', ReadingReminder = 'reading reminder', } export enum TargetId { + FeedSurvey = 'feed survey', SearchReferralBadge = 'search referral badge', InviteBanner = 'invite banner', InviteProfileMenu = 'invite in profile menu', diff --git a/packages/shared/src/lib/featureManagement.ts b/packages/shared/src/lib/featureManagement.ts index 99a018df24..205daaddec 100644 --- a/packages/shared/src/lib/featureManagement.ts +++ b/packages/shared/src/lib/featureManagement.ts @@ -54,6 +54,7 @@ const feature = { searchGoogle: new Feature('search_google', false), onboardingFlip: new Feature('onboarding_flip', false), improvedSharedPostCard: new Feature('improved_shared_post_card', false), + feedSettingsFeedback: new Feature('feed_settings_feedback', false), onboardingLinks: new Feature('onboarding_links', false), }; diff --git a/packages/shared/src/styles/custom.ts b/packages/shared/src/styles/custom.ts new file mode 100644 index 0000000000..8cbb49b5bf --- /dev/null +++ b/packages/shared/src/styles/custom.ts @@ -0,0 +1,12 @@ +// this file was created to contain all custom temporary colors (outside the guideline) +// and it is ideal to have this file to contain fewer colors as possible +// we should eventually convert the custom colors to be part of the guideline once it is deemed to be used frequently + +export const feedSurveyBg = + 'color-mix(in srgb, var(--theme-background-default), transparent 8%)'; + +export const feedSurveyBorder = + 'linear-gradient(180deg, var(--theme-accent-cheese-default) 0%, var(--theme-accent-bacon-default) 50%, var(--theme-accent-onion-default) 100%)'; + +export const feedSurveyTopBorder = + 'linear-gradient(90deg, var(--theme-accent-cheese-default) 0%, var(--theme-accent-bacon-default) 50%, var(--theme-accent-onion-default) 100%)'; diff --git a/packages/shared/tailwind/boxShadow.ts b/packages/shared/tailwind/boxShadow.ts index cc44d8f642..5a02932dba 100644 --- a/packages/shared/tailwind/boxShadow.ts +++ b/packages/shared/tailwind/boxShadow.ts @@ -32,6 +32,7 @@ const boxShadows = Object.keys(baseShadows).reduce( export default { ...boxShadows, + none: 'none', 2: 'var(--theme-shadow2)', 3: 'var(--theme-shadow3)', };