mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 17:11:49 +00:00
notebook: Add notepad CTA to empty notebook pages (#34471)
This commit is contained in:
parent
b90715a2e7
commit
3d4ce06605
@ -390,7 +390,7 @@ const UnauthenticatedNotebooksSection: React.FunctionComponent<UnauthenticatedMy
|
||||
)
|
||||
}
|
||||
|
||||
const NOTEPAD_ENABLED_EVENT = 'SearchNotepadEnabled'
|
||||
export const NOTEPAD_ENABLED_EVENT = 'SearchNotepadEnabled'
|
||||
const NOTEPAD_DISABLED_EVENT = 'SearchNotepadDisabled'
|
||||
|
||||
const ToggleNotepadButton: React.FunctionComponent<TelemetryProps> = ({ telemetryService }) => {
|
||||
|
||||
@ -6,12 +6,6 @@
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.spacer {
|
||||
// Allows scrolling past last blocks in the notebook
|
||||
// for easier editing.
|
||||
height: 80vh;
|
||||
}
|
||||
|
||||
.auto-save-indicator {
|
||||
font-size: 1rem !important;
|
||||
width: 1rem !important;
|
||||
@ -33,13 +27,61 @@
|
||||
flex: 3;
|
||||
overflow: hidden auto;
|
||||
min-width: #{$viewport-lg};
|
||||
|
||||
.content {
|
||||
max-width: #{$viewport-xl};
|
||||
padding: 0 1rem;
|
||||
}
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@media (--lg-breakpoint-down) {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.content {
|
||||
max-width: #{$viewport-xl};
|
||||
padding: 0 1rem;
|
||||
// Content should never shrink, but the spacer should take up the
|
||||
// remaining space on the page.
|
||||
flex: none;
|
||||
}
|
||||
|
||||
.spacer {
|
||||
max-width: #{$viewport-xl};
|
||||
// Allows scrolling past last blocks in the notebook
|
||||
// for easier editing. It will also ensure that there is enough space
|
||||
// between the notepad cta and the content
|
||||
margin-top: 10rem;
|
||||
// Spacer should never shrink. This makes sure that
|
||||
// (1) there is always space between the bottom of the notebookpage and the screen and
|
||||
// (2) the notepad CTA doesn't overlap with notebook content.
|
||||
flex: 1 0 auto;
|
||||
display: flex;
|
||||
// Aligns notepad CTA at the bottom of the page
|
||||
align-items: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
.notepad-cta {
|
||||
position: relative;
|
||||
bottom: 0;
|
||||
max-width: #{$viewport-md};
|
||||
margin: auto;
|
||||
margin-bottom: 1rem;
|
||||
|
||||
&--close-button {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
margin: 0.5rem;
|
||||
}
|
||||
|
||||
&--content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@media (--xs-breakpoint-down) {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import classNames from 'classnames'
|
||||
import BookOutlineIcon from 'mdi-react/BookOutlineIcon'
|
||||
import CheckCircleIcon from 'mdi-react/CheckCircleIcon'
|
||||
import CloseIcon from 'mdi-react/CloseIcon'
|
||||
import { RouteComponentProps } from 'react-router'
|
||||
import { Observable } from 'rxjs'
|
||||
import { catchError, delay, startWith, switchMap } from 'rxjs/operators'
|
||||
@ -11,16 +12,30 @@ import { asError, isErrorLike } from '@sourcegraph/common'
|
||||
import { StreamingSearchResultsListProps } from '@sourcegraph/search-ui'
|
||||
import { ExtensionsControllerProps } from '@sourcegraph/shared/src/extensions/controller'
|
||||
import { PlatformContextProps } from '@sourcegraph/shared/src/platform/context'
|
||||
import { useTemporarySetting } from '@sourcegraph/shared/src/settings/temporary/useTemporarySetting'
|
||||
import { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
|
||||
import { ThemeProps } from '@sourcegraph/shared/src/theme'
|
||||
import { LoadingSpinner, PageHeader, useEventObservable, useObservable, Alert } from '@sourcegraph/wildcard'
|
||||
import {
|
||||
LoadingSpinner,
|
||||
PageHeader,
|
||||
useEventObservable,
|
||||
useObservable,
|
||||
Alert,
|
||||
ProductStatusBadge,
|
||||
Button,
|
||||
Icon,
|
||||
} from '@sourcegraph/wildcard'
|
||||
|
||||
import { Block } from '..'
|
||||
import { AuthenticatedUser } from '../../auth'
|
||||
import { MarketingBlock } from '../../components/MarketingBlock'
|
||||
import { PageTitle } from '../../components/PageTitle'
|
||||
import { Timestamp } from '../../components/time/Timestamp'
|
||||
import { NotebookFields, NotebookInput, Scalars } from '../../graphql-operations'
|
||||
import { SearchStreamingProps } from '../../search'
|
||||
import { NotepadIcon } from '../../search/Notepad'
|
||||
import { ThemePreference } from '../../stores/themeState'
|
||||
import { useTheme } from '../../theme'
|
||||
import {
|
||||
fetchNotebook as _fetchNotebook,
|
||||
updateNotebook as _updateNotebook,
|
||||
@ -28,6 +43,7 @@ import {
|
||||
createNotebookStar as _createNotebookStar,
|
||||
deleteNotebookStar as _deleteNotebookStar,
|
||||
} from '../backend'
|
||||
import { NOTEPAD_ENABLED_EVENT } from '../listPage/NotebooksListPage'
|
||||
import { copyNotebook as _copyNotebook, CopyNotebookProps } from '../notebook'
|
||||
import { blockToGQLInput, convertNotebookTitleToFileName, GQLBlockToGQLInput } from '../serialize'
|
||||
|
||||
@ -91,6 +107,8 @@ export const NotebookPage: React.FunctionComponent<NotebookPageProps> = ({
|
||||
const [notebookTitle, setNotebookTitle] = useState('')
|
||||
const [updateQueue, setUpdateQueue] = useState<Partial<NotebookInput>[]>([])
|
||||
const outlineContainerElement = useRef<HTMLDivElement | null>(null)
|
||||
const [notepadCTASeen, setNotepadCTASeen] = useTemporarySetting('search.notepad.ctaSeen')
|
||||
const [notepadEnabled, setNotepadEnabled] = useTemporarySetting('search.notepad.enabled')
|
||||
|
||||
const exportedFileName = useMemo(
|
||||
() => `${notebookTitle ? convertNotebookTitleToFileName(notebookTitle) : 'notebook'}.snb.md`,
|
||||
@ -172,6 +190,15 @@ export const NotebookPage: React.FunctionComponent<NotebookPageProps> = ({
|
||||
[notebookTitle, copyNotebook]
|
||||
)
|
||||
|
||||
const showNotepadCTA = useMemo(
|
||||
() =>
|
||||
!notepadEnabled &&
|
||||
!notepadCTASeen &&
|
||||
isNotebookLoaded(latestNotebook) &&
|
||||
latestNotebook.blocks.length === 0,
|
||||
[latestNotebook, notepadCTASeen, notepadEnabled]
|
||||
)
|
||||
|
||||
return (
|
||||
<div className={classNames('w-100', styles.searchNotebookPage)}>
|
||||
<PageTitle title={notebookTitle || 'Notebook'} />
|
||||
@ -289,11 +316,68 @@ export const NotebookPage: React.FunctionComponent<NotebookPageProps> = ({
|
||||
extensionsController={extensionsController}
|
||||
outlineContainerElement={outlineContainerElement.current}
|
||||
/>
|
||||
<div className={styles.spacer} />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className={styles.spacer}>
|
||||
{showNotepadCTA && (
|
||||
<NotepadCTA
|
||||
onEnable={() => {
|
||||
telemetryService.log(NOTEPAD_ENABLED_EVENT)
|
||||
setNotepadCTASeen(true)
|
||||
setNotepadEnabled(true)
|
||||
}}
|
||||
onClose={() => setNotepadCTASeen(true)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
interface NotepadCTAProps {
|
||||
onEnable: () => void
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
const NotepadCTA: React.FunctionComponent<NotepadCTAProps> = ({ onEnable, onClose }) => {
|
||||
const assetsRoot = window.context?.assetsRoot || ''
|
||||
const isLightTheme = useTheme().enhancedThemePreference === ThemePreference.Light
|
||||
|
||||
return (
|
||||
<MarketingBlock wrapperClassName={styles.notepadCta}>
|
||||
<aside className={styles.notepadCtaContent}>
|
||||
<Button
|
||||
arial-label="Hide"
|
||||
variant="icon"
|
||||
onClick={onClose}
|
||||
size="sm"
|
||||
className={styles.notepadCtaCloseButton}
|
||||
>
|
||||
<Icon as={CloseIcon} />
|
||||
</Button>
|
||||
<img
|
||||
className="flex-shrink-0 mr-3"
|
||||
src={`${assetsRoot}/img/notepad-illustration-${isLightTheme ? 'light' : 'dark'}.svg`}
|
||||
alt=""
|
||||
/>
|
||||
<div>
|
||||
<h3 className="d-inline-block">
|
||||
<NotepadIcon /> Enable notepad
|
||||
</h3>{' '}
|
||||
<ProductStatusBadge status="beta" />
|
||||
<p>
|
||||
The notepad adds a toolbar to the bottom right of search results and file pages to help you
|
||||
create notebooks from your code navigation activities.
|
||||
</p>
|
||||
<p>
|
||||
<Button variant="primary" onClick={onEnable} size="sm">
|
||||
Enable notepad
|
||||
</Button>
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
</MarketingBlock>
|
||||
)
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user