feat: add Super note type to list of note types (#2086)

This commit is contained in:
Mo
2022-12-05 09:38:42 -06:00
committed by GitHub
parent 1d22365086
commit caf2c4a876
20 changed files with 148 additions and 87 deletions

View File

@@ -28,6 +28,7 @@ const ChangeEditorButton: FunctionComponent<Props> = ({
})
const [selectedEditorIcon, selectedEditorIconTint] = getIconAndTintForNoteType(
note?.noteType || selectedEditor?.package_info.note_type,
true,
)
const [isClickOutsideDisabled, setIsClickOutsideDisabled] = useState(false)

View File

@@ -12,6 +12,7 @@ import { reloadFont } from '../NoteView/FontFunctions'
import { PremiumFeatureIconClass, PremiumFeatureIconName } from '../Icon/PremiumFeatureIcon'
import { SuperNoteImporter } from '../NoteView/SuperEditor/SuperNoteImporter'
import MenuRadioButtonItem from '../Menu/MenuRadioButtonItem'
import { Pill } from '../Preferences/PreferencesComponents/Content'
type ChangeEditorMenuProps = {
application: WebApplication
@@ -188,17 +189,24 @@ const ChangeEditorMenu: FunctionComponent<ChangeEditorMenuProps> = ({
const onClickEditorItem = () => {
selectItem(item).catch(console.error)
}
return (
<MenuRadioButtonItem
key={item.name}
onClick={onClickEditorItem}
className={'flex-row-reverse py-2'}
className={'flex-row-reversed py-2'}
checked={item.isEntitled ? isSelected(item) : false}
info={item.description}
>
<div className="flex flex-grow items-center justify-between">
<div className={`flex items-center ${group.featured ? 'font-bold' : ''}`}>
{group.icon && <Icon type={group.icon} className={`mr-2 ${group.iconClassName}`} />}
{item.name}
{item.isLabs && (
<Pill className="py-0.5 px-1.5" style="success">
Labs
</Pill>
)}
</div>
{!item.isEntitled && (
<Icon type={PremiumFeatureIconName} className={PremiumFeatureIconClass} />

View File

@@ -22,6 +22,7 @@ import { classNames } from '@standardnotes/utils'
import NoSubscriptionBanner from '@/Components/NoSubscriptionBanner/NoSubscriptionBanner'
import MenuRadioButtonItem from '@/Components/Menu/MenuRadioButtonItem'
import MenuSwitchButtonItem from '@/Components/Menu/MenuSwitchButtonItem'
import { Pill } from '@/Components/Preferences/PreferencesComponents/Content'
const DailyEntryModeEnabled = true
@@ -365,9 +366,9 @@ const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
<div className="flex flex-col pr-5">
<div className="flex flex-row items-center">
<div className="text-base font-semibold uppercase text-text lg:text-xs">Daily Notebook</div>
<div className="ml-2 rounded bg-warning px-1.5 py-[1px] text-[10px] font-bold text-warning-contrast">
<Pill className="py-0 px-1.5" style="success">
Labs
</div>
</Pill>
</div>
<div className="mt-1">Capture new notes daily with a calendar-based layout</div>
</div>

View File

@@ -1,20 +1,60 @@
import { FOCUSABLE_BUT_NOT_TABBABLE } from '@/Constants/Constants'
import { classNames } from '@standardnotes/snjs'
import { PlatformedKeyboardShortcut } from '@standardnotes/ui-services'
import { ComponentPropsWithoutRef, ForwardedRef, forwardRef, ReactNode } from 'react'
import {
ComponentPropsWithoutRef,
ForwardedRef,
forwardRef,
MouseEventHandler,
ReactNode,
useCallback,
useState,
} from 'react'
import Icon from '../Icon/Icon'
import { KeyboardShortcutIndicator } from '../KeyboardShortcutIndicator/KeyboardShortcutIndicator'
import RadioIndicator from '../Radio/RadioIndicator'
import MenuListItem from './MenuListItem'
const Tooltip = ({ text }: { text: string }) => {
const [mobileVisible, setMobileVisible] = useState(false)
const onClickMobile: MouseEventHandler<HTMLDivElement> = useCallback(
(event) => {
event.preventDefault()
event.stopPropagation()
setMobileVisible(!mobileVisible)
},
[mobileVisible],
)
return (
<div className="relative">
<div className={classNames('peer flex h-5 w-5 items-center justify-center rounded-full')} onClick={onClickMobile}>
<Icon type={'help'} className="text-neutral" size="large" />
<span className="sr-only">Note sync status</span>
</div>
<div
className={classNames(
'hidden',
'absolute top-full right-0 w-60 translate-x-2 translate-y-1 select-none rounded border border-border shadow-main',
'bg-default py-1.5 px-3 text-left peer-hover:block peer-focus:block',
)}
>
{text}
</div>
</div>
)
}
type Props = {
checked: boolean
children: ReactNode
shortcut?: PlatformedKeyboardShortcut
info?: string
} & ComponentPropsWithoutRef<'button'>
const MenuRadioButtonItem = forwardRef(
(
{ checked, disabled, tabIndex, children, shortcut, className, ...props }: Props,
{ checked, disabled, tabIndex, children, shortcut, className, info, ...props }: Props,
ref: ForwardedRef<HTMLButtonElement>,
) => {
return (
@@ -37,6 +77,7 @@ const MenuRadioButtonItem = forwardRef(
{shortcut && <KeyboardShortcutIndicator className="mr-2" shortcut={shortcut} />}
<RadioIndicator disabled={disabled} checked={checked} className="flex-shrink-0" />
{children}
{info && <Tooltip text={info} />}
</button>
</MenuListItem>
)

View File

@@ -5,4 +5,6 @@ export type EditorMenuItem = {
component?: SNComponent
isEntitled: boolean
noteType: NoteType
isLabs?: boolean
description?: string
}

View File

@@ -24,8 +24,8 @@ const General: FunctionComponent<Props> = ({ viewControllerManager, application,
<Defaults application={application} />
<Tools application={application} />
<SmartViews application={application} featuresController={viewControllerManager.featuresController} />
<LabsPane application={application} />
<Moments application={application} />
<LabsPane application={application} />
<Advanced
application={application}
viewControllerManager={viewControllerManager}

View File

@@ -80,7 +80,7 @@ const Moments: FunctionComponent<Props> = ({ application }: Props) => {
<div className="flex items-center justify-between">
<div className="flex items-start">
<Title>Moments</Title>
<Pill style={'warning'}>Labs</Pill>
<Pill style={'success'}>Labs</Pill>
<Pill style={'info'}>Professional</Pill>
</div>
<Switch onChange={toggle} checked={momentsEnabled} />

View File

@@ -58,7 +58,7 @@ const PasscodeLock = ({ application, viewControllerManager }: Props) => {
}
const reloadDesktopAutoLockInterval = useCallback(async () => {
const interval = await application.getAutolockService()!.getAutoLockInterval()
const interval = await application.getAutolockService()?.getAutoLockInterval()
setSelectedAutoLockInterval(interval)
}, [application])
@@ -86,7 +86,7 @@ const PasscodeLock = ({ application, viewControllerManager }: Props) => {
return
}
await application.getAutolockService()!.setAutoLockInterval(interval)
await application.getAutolockService()?.setAutoLockInterval(interval)
reloadDesktopAutoLockInterval().catch(console.error)
}
@@ -184,6 +184,12 @@ const PasscodeLock = ({ application, viewControllerManager }: Props) => {
setPasscodeConfirmation(undefined)
}
const autolockService = application.getAutolockService()
if (!autolockService) {
return null
}
return (
<>
<PreferencesGroup>
@@ -248,25 +254,22 @@ const PasscodeLock = ({ application, viewControllerManager }: Props) => {
<Title>Autolock</Title>
<Text className="mb-3">The autolock timer begins when the window or tab loses focus.</Text>
<div className="flex flex-row items-center">
{application
.getAutolockService()!
.getAutoLockIntervalOptions()
.map((option) => {
return (
<a
key={option.value}
className={classNames(
'mr-3 cursor-pointer rounded',
option.value === selectedAutoLockInterval
? 'bg-info px-1.5 py-0.5 text-info-contrast'
: 'text-info',
)}
onClick={() => selectDesktopAutoLockInterval(option.value)}
>
{option.label}
</a>
)
})}
{autolockService.getAutoLockIntervalOptions().map((option) => {
return (
<a
key={option.value}
className={classNames(
'mr-3 cursor-pointer rounded',
option.value === selectedAutoLockInterval
? 'bg-info px-1.5 py-0.5 text-info-contrast'
: 'text-info',
)}
onClick={() => selectDesktopAutoLockInterval(option.value)}
>
{option.label}
</a>
)
})}
</div>
</PreferencesSegment>
</PreferencesGroup>

View File

@@ -31,7 +31,7 @@ const PremiumFeaturesModal: FunctionComponent<Props> = ({
return (
<AlertDialog leastDestructiveRef={ctaButtonRef} className="p-0">
<div tabIndex={-1} className="sn-component">
<div tabIndex={-1} className="sn-component bg-default">
<div tabIndex={0} className="max-w-89 rounded bg-default p-4 shadow-main">
{type === PremiumFeatureModalType.UpgradePrompt && (
<UpgradePrompt

View File

@@ -29,6 +29,7 @@ export const SYNC_TIMEOUT_NO_DEBOUNCE = 100
type EditorMetadata = {
name: string
icon: IconType
subtleIcon?: IconType
iconClassName: string
iconTintNumber: number
}
@@ -36,8 +37,9 @@ type EditorMetadata = {
export const SuperEditorMetadata: EditorMetadata = {
name: 'Super',
icon: 'file-doc',
subtleIcon: 'format-align-left',
iconClassName: 'text-accessory-tint-4',
iconTintNumber: 4,
iconTintNumber: 1,
}
export const PlainEditorMetadata: EditorMetadata = {

View File

@@ -4,7 +4,7 @@ export enum FeatureTrunkName {
Super,
}
export const FeatureTrunkStatus: Record<FeatureTrunkName, boolean> = {
const FeatureTrunkStatus: Record<FeatureTrunkName, boolean> = {
[FeatureTrunkName.Super]: isDev && true,
}

View File

@@ -7,6 +7,7 @@ import { DropdownItem } from '@/Components/Dropdown/DropdownItem'
export type EditorOption = DropdownItem & {
value: FeatureIdentifier
isLabs?: boolean
}
export function noteTypeForEditorOptionValue(value: EditorOption['value'], application: WebApplication): NoteType {
@@ -45,14 +46,13 @@ export function getDropdownItemsForAllEditors(application: WebApplication): Edit
options.push(plaintextOption)
if (application.features.isExperimentalFeatureEnabled(FeatureIdentifier.SuperEditor)) {
options.push({
icon: SuperEditorMetadata.icon,
iconClassName: SuperEditorMetadata.iconClassName,
label: SuperEditorMetadata.name,
value: FeatureIdentifier.SuperEditor,
})
}
options.push({
icon: SuperEditorMetadata.icon,
iconClassName: SuperEditorMetadata.iconClassName,
label: SuperEditorMetadata.name,
value: FeatureIdentifier.SuperEditor,
isLabs: true,
})
options.sort((a, b) => {
return a.label.toLowerCase() < b.label.toLowerCase() ? -1 : 1

View File

@@ -2,7 +2,7 @@ import { PlainEditorMetadata, SuperEditorMetadata } from '@/Constants/Constants'
import { NoteType } from '@standardnotes/features'
import { IconType } from '@standardnotes/models'
export function getIconAndTintForNoteType(noteType?: NoteType): [IconType, number] {
export function getIconAndTintForNoteType(noteType?: NoteType, subtle?: boolean): [IconType, number] {
switch (noteType) {
case NoteType.RichText:
return ['rich-text', 1]
@@ -17,7 +17,10 @@ export function getIconAndTintForNoteType(noteType?: NoteType): [IconType, numbe
case NoteType.Code:
return ['code', 4]
case NoteType.Super:
return [SuperEditorMetadata.icon, SuperEditorMetadata.iconTintNumber]
return [
subtle ? (SuperEditorMetadata.subtleIcon as IconType) : SuperEditorMetadata.icon,
SuperEditorMetadata.iconTintNumber,
]
default:
return [PlainEditorMetadata.icon, PlainEditorMetadata.iconTintNumber]
}

View File

@@ -72,7 +72,7 @@ const insertInstalledComponentsInMap = (
})
}
const createGroupsFromMap = (map: NoteTypeToEditorRowsMap, application: WebApplication): EditorMenuGroup[] => {
const createGroupsFromMap = (map: NoteTypeToEditorRowsMap, _application: WebApplication): EditorMenuGroup[] => {
const groups: EditorMenuGroup[] = [
{
icon: 'plain-text',
@@ -80,6 +80,13 @@ const createGroupsFromMap = (map: NoteTypeToEditorRowsMap, application: WebAppli
title: 'Plain text',
items: map[NoteType.Plain],
},
{
icon: SuperEditorMetadata.icon,
iconClassName: SuperEditorMetadata.iconClassName,
title: SuperEditorMetadata.name,
items: map[NoteType.Super],
featured: true,
},
{
icon: 'rich-text',
iconClassName: 'text-accessory-tint-1',
@@ -124,16 +131,6 @@ const createGroupsFromMap = (map: NoteTypeToEditorRowsMap, application: WebAppli
},
]
if (application.features.isExperimentalFeatureEnabled(FeatureIdentifier.SuperEditor)) {
groups.splice(1, 0, {
icon: SuperEditorMetadata.icon,
iconClassName: SuperEditorMetadata.iconClassName,
title: SuperEditorMetadata.name,
items: map[NoteType.Super],
featured: true,
})
}
return groups
}
@@ -146,7 +143,16 @@ const createBaselineMap = (application: WebApplication): NoteTypeToEditorRowsMap
noteType: NoteType.Plain,
},
],
[NoteType.Super]: [],
[NoteType.Super]: [
{
name: SuperEditorMetadata.name,
isEntitled: application.features.getFeatureStatus(FeatureIdentifier.SuperEditor) === FeatureStatus.Entitled,
noteType: NoteType.Super,
isLabs: true,
description:
'A new way to edit notes. Type / to bring up the block selection menu, or @ to embed images or link other tags and notes. Type - then space to start a list, or [] then space to start a checklist. Drag and drop an image or file to embed it in your note.',
},
],
[NoteType.RichText]: [],
[NoteType.Markdown]: [],
[NoteType.Task]: [],
@@ -156,14 +162,6 @@ const createBaselineMap = (application: WebApplication): NoteTypeToEditorRowsMap
[NoteType.Unknown]: [],
}
if (application.features.isExperimentalFeatureEnabled(FeatureIdentifier.SuperEditor)) {
map[NoteType.Super].push({
name: SuperEditorMetadata.name,
isEntitled: true,
noteType: NoteType.Super,
})
}
return map
}