From 91ba14a749fa5bf71d69e5b7d58c58854d123ce2 Mon Sep 17 00:00:00 2001 From: Kasper Peulen Date: Mon, 10 Jul 2023 11:58:16 +0200 Subject: [PATCH 1/9] Add UI for notification toggle and link sharing to 'Whats New' --- code/lib/core-events/src/index.ts | 2 + code/lib/manager-api/src/modules/whatsnew.ts | 5 + code/ui/manager/src/globals/exports.ts | 1 + code/ui/manager/src/settings/whats_new.tsx | 107 ++++++++++++++++-- .../src/settings/whats_new_footer.stories.tsx | 22 ++++ 5 files changed, 130 insertions(+), 7 deletions(-) create mode 100644 code/ui/manager/src/settings/whats_new_footer.stories.tsx diff --git a/code/lib/core-events/src/index.ts b/code/lib/core-events/src/index.ts index 64a452dc11f2..ce13b5385ca8 100644 --- a/code/lib/core-events/src/index.ts +++ b/code/lib/core-events/src/index.ts @@ -68,6 +68,7 @@ enum events { REQUEST_WHATS_NEW_DATA = 'requestWhatsNewData', RESULT_WHATS_NEW_DATA = 'resultWhatsNewData', SET_WHATS_NEW_CACHE = 'setWhatsNewCache', + TOGGLE_WHATS_NEW_NOTIFICATIONS = 'toggleWhatsNewNotifications', } // Enables: `import Events from ...` @@ -118,6 +119,7 @@ export const { REQUEST_WHATS_NEW_DATA, RESULT_WHATS_NEW_DATA, SET_WHATS_NEW_CACHE, + TOGGLE_WHATS_NEW_NOTIFICATIONS, } = events; // Used to break out of the current render without showing a redbox diff --git a/code/lib/manager-api/src/modules/whatsnew.ts b/code/lib/manager-api/src/modules/whatsnew.ts index b970d0e96bac..9633c4f73dd3 100644 --- a/code/lib/manager-api/src/modules/whatsnew.ts +++ b/code/lib/manager-api/src/modules/whatsnew.ts @@ -4,6 +4,7 @@ import { REQUEST_WHATS_NEW_DATA, RESULT_WHATS_NEW_DATA, SET_WHATS_NEW_CACHE, + TOGGLE_WHATS_NEW_NOTIFICATIONS, } from '@storybook/core-events'; import type { ModuleFn } from '../index'; @@ -14,6 +15,7 @@ export type SubState = { export type SubAPI = { isWhatsNewUnread(): boolean; whatsNewHasBeenRead(): void; + toggleWhatsNewNotifications(): void; }; const WHATS_NEW_NOTIFICATION_ID = 'whats-new'; @@ -39,6 +41,9 @@ export const init: ModuleFn = ({ fullAPI, store }) => { fullAPI.clearNotification(WHATS_NEW_NOTIFICATION_ID); } }, + toggleWhatsNewNotifications() { + fullAPI.emit(TOGGLE_WHATS_NEW_NOTIFICATIONS); + }, }; function getLatestWhatsNewPost(): Promise { diff --git a/code/ui/manager/src/globals/exports.ts b/code/ui/manager/src/globals/exports.ts index 473867f750c0..43b7c50f5191 100644 --- a/code/ui/manager/src/globals/exports.ts +++ b/code/ui/manager/src/globals/exports.ts @@ -163,6 +163,7 @@ export default { 'STORY_SPECIFIED', 'STORY_THREW_EXCEPTION', 'STORY_UNCHANGED', + 'TOGGLE_WHATS_NEW_NOTIFICATIONS', 'UPDATE_GLOBALS', 'UPDATE_QUERY_PARAMS', 'UPDATE_STORY_ARGS', diff --git a/code/ui/manager/src/settings/whats_new.tsx b/code/ui/manager/src/settings/whats_new.tsx index 4f0b5072259e..1dbadd82608a 100644 --- a/code/ui/manager/src/settings/whats_new.tsx +++ b/code/ui/manager/src/settings/whats_new.tsx @@ -1,8 +1,9 @@ -import type { FC, ComponentProps } from 'react'; -import React, { useEffect, useState, Fragment } from 'react'; -import { styled } from '@storybook/theming'; -import { Icons, Loader } from '@storybook/components'; +import type { ComponentProps, FC } from 'react'; +import React, { Fragment, useEffect, useState } from 'react'; +import { styled, useTheme } from '@storybook/theming'; +import { IconButton, Icons, Loader } from '@storybook/components'; import { useStorybookApi } from '@storybook/manager-api'; +import { global } from '@storybook/global'; const Centered = styled.div({ top: '50%', @@ -26,6 +27,74 @@ const Message = styled.div(({ theme }) => ({ lineHeight: `16px`, })); +const Container = styled.div(({ theme }) => ({ + position: 'absolute', + width: '100%', + bottom: '40px', + background: theme.background.bar, + fontSize: `13px`, + borderTop: '1px solid', + borderColor: theme.appBorderColor, + padding: '8px 12px', + display: 'flex', + justifyContent: 'space-between', +})); + +const ToggleNotificationButton = styled(IconButton)(({ theme }) => ({ + fontWeight: theme.typography.weight.regular, + color: theme.color.mediumdark, + margin: 0, +})); + +const CopyButton = styled(IconButton)(() => ({ + margin: 0, + padding: 0, + borderRadius: 0, +})); + +export const WhatsNewFooter = ({ + isNotificationsDisabled, + onToggleNotifications, + onCopyLink, +}: { + isNotificationsDisabled: boolean; + onToggleNotifications?: () => void; + onCopyLink?: () => void; +}) => { + const theme = useTheme(); + const [copyText, setCopyText] = useState('Copy Link'); + const copyLink = () => { + onCopyLink(); + setCopyText('Copied!'); + setTimeout(() => setCopyText('Copy Link'), 4000); + }; + + return ( + +
+ +
Share this with your team.
+ + {copyText} + +
+ + {isNotificationsDisabled ? ( + <> + +  Show notifications + + ) : ( + <> + +  Hide notifications + + )} + +
+ ); +}; + const Iframe = styled.iframe<{ isLoaded: boolean }>( { position: 'absolute', @@ -37,7 +106,7 @@ const Iframe = styled.iframe<{ isLoaded: boolean }>( margin: 0, padding: 0, width: '100%', - height: 'calc(100% - 40px)', + height: 'calc(100% - 80px)', }, ({ isLoaded }) => ({ visibility: isLoaded ? 'visible' : 'hidden' }) ); @@ -72,15 +141,31 @@ export interface WhatsNewProps { isLoaded: boolean; onLoad: () => void; url?: string; + onCopyLink?: () => void; + onToggleNotifications?: () => void; } -const PureWhatsNewScreen: FC = ({ didHitMaxWaitTime, isLoaded, onLoad, url }) => ( +const PureWhatsNewScreen: FC = ({ + didHitMaxWaitTime, + isLoaded, + onLoad, + url, + onCopyLink, + onToggleNotifications, +}) => ( {!isLoaded && !didHitMaxWaitTime && } {didHitMaxWaitTime ? ( ) : ( -