feat: add features package

This commit is contained in:
Karol Sójko
2022-07-05 14:58:29 +02:00
parent e335d0d2c2
commit 44d3e96468
69 changed files with 2214 additions and 28 deletions

View File

@@ -0,0 +1,25 @@
export enum ComponentAction {
SetSize = 'set-size',
StreamItems = 'stream-items',
StreamContextItem = 'stream-context-item',
SaveItems = 'save-items',
SelectItem = 'select-item',
AssociateItem = 'associate-item',
DeassociateItem = 'deassociate-item',
ClearSelection = 'clear-selection',
CreateItem = 'create-item',
CreateItems = 'create-items',
DeleteItems = 'delete-items',
SetComponentData = 'set-component-data',
ToggleActivateComponent = 'toggle-activate-component',
RequestPermissions = 'request-permissions',
PresentConflictResolution = 'present-conflict-resolution',
DuplicateItem = 'duplicate-item',
ComponentRegistered = 'component-registered',
ActivateThemes = 'themes',
Reply = 'reply',
ThemesActivated = 'themes-activated',
KeyDown = 'key-down',
KeyUp = 'key-up',
Click = 'click',
}

View File

@@ -0,0 +1,5 @@
export enum ComponentArea {
Editor = 'editor-editor',
Themes = 'themes',
EditorStack = 'editor-stack',
}

View File

@@ -0,0 +1,4 @@
export enum ComponentFlag {
New = 'New',
Deprecated = 'Deprecated',
}

View File

@@ -0,0 +1,7 @@
import { ContentType } from '@standardnotes/common'
import { ComponentAction } from './ComponentAction'
export type ComponentPermission = {
name: ComponentAction
content_types?: ContentType[]
}

View File

@@ -0,0 +1,8 @@
export enum NoteType {
Authentication = 'authentication',
Code = 'code',
Markdown = 'markdown',
RichText = 'rich-text',
Spreadsheet = 'spreadsheet',
Task = 'task',
}

View File

@@ -0,0 +1,7 @@
export type ThemeDockIcon = {
type: 'svg' | 'circle'
background_color: string
foreground_color: string
border_color: string
source?: string
}

View File

@@ -0,0 +1,78 @@
import { ComponentPermission } from '../Component/ComponentPermission'
import { ContentType, RoleName, SubscriptionName } from '@standardnotes/common'
import { ComponentArea } from '../Component/ComponentArea'
import { PermissionName } from '../Permission/PermissionName'
import { FeatureIdentifier } from './FeatureIdentifier'
import { ComponentFlag } from '../Component/ComponentFlag'
import { NoteType } from '../Component/NoteType'
import { ThemeDockIcon } from '../Component/ThemeDockIcon'
type RoleFields = {
/** Server populated */
role_name?: RoleName
/** Statically populated. Non-influencing; used as a reference by other static consumers (such as email service) */
availableInSubscriptions: SubscriptionName[]
}
export type BaseFeatureDescription = RoleFields & {
deletion_warning?: string
deprecated?: boolean
deprecation_message?: string
description?: string
expires_at?: number
flags?: ComponentFlag[]
identifier: FeatureIdentifier
marketing_url?: string
name?: string
no_expire?: boolean
no_mobile?: boolean
thumbnail_url?: string
permission_name: PermissionName
}
export type ServerFeatureDescription = RoleFields & {
name?: string
identifier: FeatureIdentifier
permission_name: PermissionName
}
export type ClientFeatureDescription = RoleFields & {
identifier: FeatureIdentifier
permission_name: PermissionName
description: string
name: string
}
export type ComponentFeatureDescription = BaseFeatureDescription & {
/** The relative path of the index.html file or the main css file if theme, within the component folder itself */
index_path: string
content_type: ContentType
area: ComponentArea
}
export type ThirdPartyFeatureDescription = ComponentFeatureDescription & {
url: string
}
export type IframeComponentFeatureDescription = ComponentFeatureDescription & {
component_permissions: ComponentPermission[]
}
export type EditorFeatureDescription = IframeComponentFeatureDescription & {
file_type: 'txt' | 'html' | 'md' | 'json'
/** Whether an editor is interchangable with another editor that has the same file_type */
interchangeable: boolean
note_type: NoteType
spellcheckControl?: boolean
}
export type ThemeFeatureDescription = ComponentFeatureDescription & {
/** Some themes can be layered on top of other themes */
layerable?: boolean
dock_icon?: ThemeDockIcon
}
export type FeatureDescription = BaseFeatureDescription &
Partial<ComponentFeatureDescription & EditorFeatureDescription & ThemeFeatureDescription>

View File

@@ -0,0 +1,53 @@
export enum FeatureIdentifier {
AccountSwitcher = 'com.standardnotes.account-switcher',
CloudLink = 'org.standardnotes.cloudlink',
DailyDropboxBackup = 'org.standardnotes.daily-dropbox-backup',
DailyEmailBackup = 'org.standardnotes.daily-email-backup',
DailyGDriveBackup = 'org.standardnotes.daily-gdrive-backup',
DailyOneDriveBackup = 'org.standardnotes.daily-onedrive-backup',
Files = 'org.standardnotes.files',
FilesBeta = 'org.standardnotes.files-beta',
FilesLowStorageTier = 'org.standardnotes.files-low-storage-tier',
FilesMaximumStorageTier = 'org.standardnotes.files-max-storage-tier',
ListedCustomDomain = 'org.standardnotes.listed-custom-domain',
NoteHistory30Days = 'org.standardnotes.note-history-30',
NoteHistory365Days = 'org.standardnotes.note-history-365',
NoteHistoryUnlimited = 'org.standardnotes.note-history-unlimited',
SignInAlerts = 'com.standardnotes.sign-in-alerts',
SmartFilters = 'org.standardnotes.smart-filters',
TagNesting = 'org.standardnotes.tag-nesting',
TwoFactorAuth = 'org.standardnotes.two-factor-auth',
AutobiographyTheme = 'org.standardnotes.theme-autobiography',
DynamicTheme = 'org.standardnotes.theme-dynamic',
FocusedTheme = 'org.standardnotes.theme-focus',
FocusMode = 'org.standardnotes.focus-mode',
FuturaTheme = 'org.standardnotes.theme-futura',
MidnightTheme = 'org.standardnotes.theme-midnight',
SolarizedDarkTheme = 'org.standardnotes.theme-solarized-dark',
TitaniumTheme = 'org.standardnotes.theme-titanium',
AdvancedChecklist = 'org.standardnotes.advanced-checklist',
CodeEditor = 'org.standardnotes.code-editor',
MarkdownProEditor = 'org.standardnotes.advanced-markdown-editor',
MarkdownVisualEditor = 'org.standardnotes.markdown-visual-editor',
PlainTextEditor = 'org.standardnotes.plain-text-editor',
PlusEditor = 'org.standardnotes.plus-editor',
SheetsEditor = 'org.standardnotes.standard-sheets',
TaskEditor = 'org.standardnotes.simple-task-editor',
TokenVaultEditor = 'org.standardnotes.token-vault',
DeprecatedBoldEditor = 'org.standardnotes.bold-editor',
DeprecatedMarkdownBasicEditor = 'org.standardnotes.simple-markdown-editor',
DeprecatedMarkdownMathEditor = 'org.standardnotes.fancy-markdown-editor',
DeprecatedMarkdownMinimistEditor = 'org.standardnotes.minimal-markdown-editor',
DeprecatedFoldersComponent = 'org.standardnotes.folders',
DeprecatedFileSafe = 'org.standardnotes.file-safe',
}
/**
* Identifier for standalone filesafe instance offered as legacy installable via extensions-server
*/
export const LegacyFileSafeIdentifier = 'org.standardnotes.legacy.file-safe'
export const ExperimentalFeatures = [FeatureIdentifier.AdvancedChecklist]

View File

@@ -0,0 +1,19 @@
import { SubscriptionName } from '@standardnotes/common'
import { GetFeatures, GetFeaturesForSubscription } from './Features'
describe('features', () => {
it('all features should have availableInSubscriptions populated', () => {
const features = GetFeatures()
for (const feature of features) {
expect(feature.availableInSubscriptions.length).toBeGreaterThan(0)
}
})
it('gets features for plus plan', () => {
const features = GetFeaturesForSubscription(SubscriptionName.PlusPlan)
for (const feature of features) {
expect(feature.availableInSubscriptions.includes(SubscriptionName.PlusPlan))
}
})
})

View File

@@ -0,0 +1,28 @@
import { FeatureDescription } from './FeatureDescription'
import { FeatureIdentifier } from './FeatureIdentifier'
import { editors } from '../Lists/Editors'
import { themes } from '../Lists/Themes'
import { serverFeatures } from '../Lists/ServerFeatures'
import { clientFeatures } from '../Lists/ClientFeatures'
import { GetDeprecatedFeatures } from '../Lists/DeprecatedFeatures'
import { experimentalFeatures } from '../Lists/ExperimentalFeatures'
import { SubscriptionName } from '@standardnotes/common'
export function GetFeatures(): FeatureDescription[] {
return [
...themes(),
...editors(),
...serverFeatures(),
...clientFeatures(),
...experimentalFeatures(),
...GetDeprecatedFeatures(),
]
}
export function GetFeaturesForSubscription(subscription: SubscriptionName): FeatureDescription[] {
return GetFeatures().filter((feature) => feature.availableInSubscriptions.includes(subscription))
}
export function FindNativeFeature(identifier: FeatureIdentifier): FeatureDescription | undefined {
return GetFeatures().find((f) => f.identifier === identifier)
}

View File

@@ -0,0 +1,58 @@
import { ClientFeatureDescription } from '../Feature/FeatureDescription'
import { PermissionName } from '../Permission/PermissionName'
import { FeatureIdentifier } from '../Feature/FeatureIdentifier'
import { SubscriptionName } from '@standardnotes/common'
export function clientFeatures(): ClientFeatureDescription[] {
return [
{
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Tag Nesting',
identifier: FeatureIdentifier.TagNesting,
permission_name: PermissionName.TagNesting,
description: 'Organize your tags into folders.',
},
{
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Smart Filters',
identifier: FeatureIdentifier.SmartFilters,
permission_name: PermissionName.SmartFilters,
description: 'Create smart filters for viewing notes matching specific criteria.',
},
{
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Encrypted files (coming soon)',
identifier: FeatureIdentifier.Files,
permission_name: PermissionName.Files,
description: '',
},
{
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Encrypted files beta',
identifier: FeatureIdentifier.FilesBeta,
permission_name: PermissionName.FilesBeta,
description: '',
},
{
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Focus Mode',
identifier: FeatureIdentifier.FocusMode,
permission_name: PermissionName.FocusMode,
description: '',
},
{
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Listed Custom Domain',
identifier: FeatureIdentifier.ListedCustomDomain,
permission_name: PermissionName.ListedCustomDomain,
description: '',
},
{
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Multiple accounts',
identifier: FeatureIdentifier.AccountSwitcher,
permission_name: PermissionName.AccountSwitcher,
description: '',
},
]
}

View File

@@ -0,0 +1,7 @@
import { GetDeprecatedFeatures } from './DeprecatedFeatures'
it('all deprecated features should have deprecated flag true', async () => {
for (const feature of GetDeprecatedFeatures()) {
expect(feature.deprecated).toEqual(true)
}
})

View File

@@ -0,0 +1,110 @@
import { ContentType, SubscriptionName } from '@standardnotes/common'
import {
EditorFeatureDescription,
IframeComponentFeatureDescription,
FeatureDescription,
} from '../Feature/FeatureDescription'
import { PermissionName } from '../Permission/PermissionName'
import { FeatureIdentifier } from '../Feature/FeatureIdentifier'
import { NoteType } from '../Component/NoteType'
import { FillEditorComponentDefaults } from './Utilities/FillEditorComponentDefaults'
import { ComponentAction } from '../Component/ComponentAction'
import { ComponentArea } from '../Component/ComponentArea'
export function GetDeprecatedFeatures(): FeatureDescription[] {
const bold: EditorFeatureDescription = FillEditorComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Alternative Rich Text',
identifier: FeatureIdentifier.DeprecatedBoldEditor,
note_type: NoteType.RichText,
file_type: 'html',
component_permissions: [
{
name: ComponentAction.StreamContextItem,
content_types: [ContentType.Note],
},
{
name: ComponentAction.StreamItems,
content_types: [
ContentType.FilesafeCredentials,
ContentType.FilesafeFileMetadata,
ContentType.FilesafeIntegration,
],
},
],
spellcheckControl: true,
deprecated: true,
permission_name: PermissionName.BoldEditor,
description: 'A simple and peaceful rich editor that helps you write and think clearly.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/editors/bold.jpg',
})
const markdownBasic: EditorFeatureDescription = FillEditorComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Basic Markdown',
identifier: FeatureIdentifier.DeprecatedMarkdownBasicEditor,
note_type: NoteType.Markdown,
spellcheckControl: true,
file_type: 'md',
deprecated: true,
permission_name: PermissionName.MarkdownBasicEditor,
description: 'A Markdown editor with dynamic split-pane preview.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/editors/simple-markdown.jpg',
})
const markdownMinimist: EditorFeatureDescription = FillEditorComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Minimal Markdown',
identifier: FeatureIdentifier.DeprecatedMarkdownMinimistEditor,
note_type: NoteType.Markdown,
file_type: 'md',
index_path: 'index.html',
permission_name: PermissionName.MarkdownMinimistEditor,
spellcheckControl: true,
deprecated: true,
description: 'A minimal Markdown editor with live rendering and in-text search via Ctrl/Cmd + F',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/editors/min-markdown.jpg',
})
const markdownMath: EditorFeatureDescription = FillEditorComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Markdown with Math',
identifier: FeatureIdentifier.DeprecatedMarkdownMathEditor,
spellcheckControl: true,
permission_name: PermissionName.MarkdownMathEditor,
note_type: NoteType.Markdown,
file_type: 'md',
deprecated: true,
index_path: 'index.html',
description: 'A beautiful split-pane Markdown editor with synced-scroll, LaTeX support, and colorful syntax.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/editors/fancy-markdown.jpg',
})
const filesafe: IframeComponentFeatureDescription = FillEditorComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'FileSafe',
identifier: FeatureIdentifier.DeprecatedFileSafe,
component_permissions: [
{
name: ComponentAction.StreamContextItem,
content_types: [ContentType.Note],
},
{
name: ComponentAction.StreamItems,
content_types: [
ContentType.FilesafeCredentials,
ContentType.FilesafeFileMetadata,
ContentType.FilesafeIntegration,
],
},
],
permission_name: PermissionName.ComponentFilesafe,
area: ComponentArea.EditorStack,
deprecated: true,
description:
'Encrypted attachments for your notes using your Dropbox, Google Drive, or WebDAV server. Limited to 50MB per file.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/FileSafe-banner.png',
})
return [bold, markdownBasic, markdownMinimist, markdownMath, filesafe]
}

View File

@@ -0,0 +1,105 @@
import { SubscriptionName } from '@standardnotes/common'
import { EditorFeatureDescription } from '../Feature/FeatureDescription'
import { PermissionName } from '../Permission/PermissionName'
import { FeatureIdentifier } from '../Feature/FeatureIdentifier'
import { NoteType } from '../Component/NoteType'
import { FillEditorComponentDefaults } from './Utilities/FillEditorComponentDefaults'
export function editors(): EditorFeatureDescription[] {
const code: EditorFeatureDescription = FillEditorComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Code',
spellcheckControl: true,
identifier: FeatureIdentifier.CodeEditor,
permission_name: PermissionName.CodeEditor,
note_type: NoteType.Code,
file_type: 'txt',
interchangeable: true,
index_path: 'index.html',
description:
'Syntax highlighting and convenient keyboard shortcuts for over 120 programming' +
' languages. Ideal for code snippets and procedures.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/editors/code.jpg',
})
const plus: EditorFeatureDescription = FillEditorComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Rich Text',
note_type: NoteType.RichText,
file_type: 'html',
identifier: FeatureIdentifier.PlusEditor,
permission_name: PermissionName.PlusEditor,
spellcheckControl: true,
description:
'From highlighting to custom font sizes and colors, to tables and lists, this editor is perfect for crafting any document.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/editors/plus-editor.jpg',
})
const markdown: EditorFeatureDescription = FillEditorComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Markdown',
identifier: FeatureIdentifier.MarkdownProEditor,
note_type: NoteType.Markdown,
file_type: 'md',
permission_name: PermissionName.MarkdownProEditor,
spellcheckControl: true,
description:
'A fully featured Markdown editor that supports live preview, a styling toolbar, and split pane support.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/editors/adv-markdown.jpg',
})
const markdownAlt: EditorFeatureDescription = FillEditorComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Markdown Alternative',
identifier: FeatureIdentifier.MarkdownVisualEditor,
note_type: NoteType.Markdown,
file_type: 'md',
permission_name: PermissionName.MarkdownVisualEditor,
spellcheckControl: true,
description:
'A WYSIWYG-style Markdown editor that renders Markdown in preview-mode while you type without displaying any syntax.',
index_path: 'build/index.html',
})
const task: EditorFeatureDescription = FillEditorComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Checklist',
identifier: FeatureIdentifier.TaskEditor,
note_type: NoteType.Task,
spellcheckControl: true,
file_type: 'md',
interchangeable: false,
permission_name: PermissionName.TaskEditor,
description:
'A great way to manage short-term and long-term to-do"s. You can mark tasks as completed, change their order, and edit the text naturally in place.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/editors/task-editor.jpg',
})
const tokenvault: EditorFeatureDescription = FillEditorComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Authenticator',
note_type: NoteType.Authentication,
file_type: 'json',
interchangeable: false,
identifier: FeatureIdentifier.TokenVaultEditor,
permission_name: PermissionName.TokenVaultEditor,
description:
'Encrypt and protect your 2FA secrets for all your internet accounts. Authenticator handles your 2FA secrets so that you never lose them again, or have to start over when you get a new device.',
thumbnail_url: 'https://standard-notes.s3.amazonaws.com/screenshots/models/editors/token-vault.png',
})
const spreadsheets: EditorFeatureDescription = FillEditorComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Spreadsheet',
identifier: FeatureIdentifier.SheetsEditor,
note_type: NoteType.Spreadsheet,
file_type: 'json',
interchangeable: false,
permission_name: PermissionName.SheetsEditor,
description:
'A powerful spreadsheet editor with formatting and formula support. Not recommended for large data sets, as encryption of such data may decrease editor performance.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/editors/spreadsheets.png',
})
return [code, plus, markdown, markdownAlt, task, tokenvault, spreadsheets]
}

View File

@@ -0,0 +1,23 @@
import { SubscriptionName } from '@standardnotes/common'
import { NoteType } from '../Component/NoteType'
import { PermissionName } from '../Permission/PermissionName'
import { EditorFeatureDescription, FeatureDescription } from '../Feature/FeatureDescription'
import { FeatureIdentifier } from '../Feature/FeatureIdentifier'
import { FillEditorComponentDefaults } from './Utilities/FillEditorComponentDefaults'
export function experimentalFeatures(): FeatureDescription[] {
const advancedChecklist: EditorFeatureDescription = FillEditorComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Advanced Checklist [Alpha]',
identifier: FeatureIdentifier.AdvancedChecklist,
note_type: NoteType.Task,
spellcheckControl: true,
file_type: 'json',
interchangeable: false,
permission_name: PermissionName.AdvancedChecklist,
description: 'A task editor with grouping functionality.',
index_path: 'build/index.html',
})
return [advancedChecklist]
}

View File

@@ -0,0 +1,64 @@
import { ServerFeatureDescription } from '../Feature/FeatureDescription'
import { PermissionName } from '../Permission/PermissionName'
import { FeatureIdentifier } from '../Feature/FeatureIdentifier'
import { SubscriptionName } from '@standardnotes/common'
export function serverFeatures(): ServerFeatureDescription[] {
return [
{
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Two factor authentication',
identifier: FeatureIdentifier.TwoFactorAuth,
permission_name: PermissionName.TwoFactorAuth,
},
{
availableInSubscriptions: [SubscriptionName.ProPlan],
name: 'Unlimited note history',
identifier: FeatureIdentifier.NoteHistoryUnlimited,
permission_name: PermissionName.NoteHistoryUnlimited,
},
{
availableInSubscriptions: [SubscriptionName.PlusPlan],
name: '365 days note history',
identifier: FeatureIdentifier.NoteHistory365Days,
permission_name: PermissionName.NoteHistory365Days,
},
{
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Email backups',
identifier: FeatureIdentifier.DailyEmailBackup,
permission_name: PermissionName.DailyEmailBackup,
},
{
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Sign-in email alerts',
identifier: FeatureIdentifier.SignInAlerts,
permission_name: PermissionName.SignInAlerts,
},
{
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
identifier: FeatureIdentifier.DailyDropboxBackup,
permission_name: PermissionName.DailyDropboxBackup,
},
{
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
identifier: FeatureIdentifier.DailyGDriveBackup,
permission_name: PermissionName.DailyGDriveBackup,
},
{
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
identifier: FeatureIdentifier.DailyOneDriveBackup,
permission_name: PermissionName.DailyOneDriveBackup,
},
{
availableInSubscriptions: [SubscriptionName.ProPlan],
identifier: FeatureIdentifier.FilesMaximumStorageTier,
permission_name: PermissionName.FilesMaximumStorageTier,
},
{
availableInSubscriptions: [SubscriptionName.PlusPlan],
identifier: FeatureIdentifier.FilesLowStorageTier,
permission_name: PermissionName.FilesLowStorageTier,
},
]
}

View File

@@ -0,0 +1,109 @@
import { ThemeFeatureDescription } from '../Feature/FeatureDescription'
import { PermissionName } from '../Permission/PermissionName'
import { FeatureIdentifier } from '../Feature/FeatureIdentifier'
import { FillThemeComponentDefaults } from './Utilities/FillThemeComponentDefaults'
import { SubscriptionName } from '@standardnotes/common'
export function themes(): ThemeFeatureDescription[] {
const midnight: ThemeFeatureDescription = FillThemeComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Midnight',
identifier: FeatureIdentifier.MidnightTheme,
permission_name: PermissionName.MidnightTheme,
description: 'Elegant utilitarianism.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/themes/midnight-with-mobile.jpg',
dock_icon: {
type: 'circle',
background_color: '#086DD6',
foreground_color: '#ffffff',
border_color: '#086DD6',
},
})
const futura: ThemeFeatureDescription = FillThemeComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Futura',
identifier: FeatureIdentifier.FuturaTheme,
permission_name: PermissionName.FuturaTheme,
description: 'Calm and relaxed. Take some time off.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/themes/futura-with-mobile.jpg',
dock_icon: {
type: 'circle',
background_color: '#fca429',
foreground_color: '#ffffff',
border_color: '#fca429',
},
})
const solarizedDark: ThemeFeatureDescription = FillThemeComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Solarized Dark',
identifier: FeatureIdentifier.SolarizedDarkTheme,
permission_name: PermissionName.SolarizedDarkTheme,
description: 'The perfect theme for any time.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/themes/solarized-dark.jpg',
dock_icon: {
type: 'circle',
background_color: '#2AA198',
foreground_color: '#ffffff',
border_color: '#2AA198',
},
})
const autobiography: ThemeFeatureDescription = FillThemeComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Autobiography',
identifier: FeatureIdentifier.AutobiographyTheme,
permission_name: PermissionName.AutobiographyTheme,
description: 'A theme for writers and readers.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/themes/autobiography.jpg',
dock_icon: {
type: 'circle',
background_color: '#9D7441',
foreground_color: '#ECE4DB',
border_color: '#9D7441',
},
})
const focus: ThemeFeatureDescription = FillThemeComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Focus',
identifier: FeatureIdentifier.FocusedTheme,
permission_name: PermissionName.FocusedTheme,
description: 'For when you need to go in.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/themes/focus-with-mobile.jpg',
dock_icon: {
type: 'circle',
background_color: '#a464c2',
foreground_color: '#ffffff',
border_color: '#a464c2',
},
})
const titanium: ThemeFeatureDescription = FillThemeComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Titanium',
identifier: FeatureIdentifier.TitaniumTheme,
permission_name: PermissionName.TitaniumTheme,
description: 'Light on the eyes, heavy on the spirit.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/themes/titanium-with-mobile.jpg',
dock_icon: {
type: 'circle',
background_color: '#6e2b9e',
foreground_color: '#ffffff',
border_color: '#6e2b9e',
},
})
const dynamic: ThemeFeatureDescription = FillThemeComponentDefaults({
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
name: 'Dynamic Panels',
identifier: FeatureIdentifier.DynamicTheme,
permission_name: PermissionName.ThemeDynamic,
layerable: true,
no_mobile: true,
description: 'A smart theme that minimizes the tags and notes panels when they are not in use.',
})
return [midnight, futura, solarizedDark, autobiography, focus, titanium, dynamic]
}

View File

@@ -0,0 +1,34 @@
import { ComponentAction } from '../../Component/ComponentAction'
import { ContentType } from '@standardnotes/common'
import { EditorFeatureDescription } from '../../Feature/FeatureDescription'
import { ComponentArea } from '../../Component/ComponentArea'
export type RequiredEditorFields = Pick<EditorFeatureDescription, 'availableInSubscriptions'>
export function FillEditorComponentDefaults(
component: Partial<EditorFeatureDescription> & RequiredEditorFields,
): EditorFeatureDescription {
if (!component.index_path) {
component.index_path = 'dist/index.html'
}
if (!component.component_permissions) {
component.component_permissions = [
{
name: ComponentAction.StreamContextItem,
content_types: [ContentType.Note],
},
]
}
component.content_type = ContentType.Component
if (!component.area) {
component.area = ComponentArea.Editor
}
if (component.interchangeable == undefined) {
component.interchangeable = true
}
return component as EditorFeatureDescription
}

View File

@@ -0,0 +1,21 @@
import { ContentType } from '@standardnotes/common'
import { ThemeFeatureDescription } from '../../Feature/FeatureDescription'
import { ComponentArea } from '../../Component/ComponentArea'
type RequiredThemeFields = Pick<ThemeFeatureDescription, 'availableInSubscriptions'>
export function FillThemeComponentDefaults(
theme: Partial<ThemeFeatureDescription> & RequiredThemeFields,
): ThemeFeatureDescription {
if (!theme.index_path) {
theme.index_path = 'dist/dist.css'
}
theme.content_type = ContentType.Theme
if (!theme.area) {
theme.area = ComponentArea.Themes
}
return theme as ThemeFeatureDescription
}

View File

@@ -0,0 +1,8 @@
import { Uuid } from '@standardnotes/common'
import { PermissionName } from './PermissionName'
export type Permission = {
uuid: Uuid
name: PermissionName
}

View File

@@ -0,0 +1,42 @@
export enum PermissionName {
AccountSwitcher = 'app:account-switcher',
AdvancedChecklist = 'editor:advanced-checklist',
AutobiographyTheme = 'theme:autobiography',
BoldEditor = 'editor:bold',
CloudLink = 'component:cloud-link',
CodeEditor = 'editor:code-editor',
ComponentFilesafe = 'component:filesafe',
ComponentFolders = 'component:folders',
DailyDropboxBackup = 'server:daily-dropbox-backup',
DailyEmailBackup = 'server:daily-email-backup',
DailyGDriveBackup = 'server:daily-gdrive-backup',
DailyOneDriveBackup = 'server:daily-onedrive-backup',
FilesBeta = 'app:files-beta',
Files = 'app:files',
FilesMaximumStorageTier = 'server:files-max-storage-tier',
FilesLowStorageTier = 'server:files-low-storage-tier',
FocusedTheme = 'theme:focused',
FocusMode = 'app:focus-mode',
FuturaTheme = 'theme:futura',
ListedCustomDomain = 'listed:custom-domain',
MarkdownBasicEditor = 'editor:markdown-basic',
MarkdownMathEditor = 'editor:markdown-math',
MarkdownMinimistEditor = 'editor:markdown-minimist',
MarkdownProEditor = 'editor:markdown-pro',
MarkdownVisualEditor = 'editor:markdown-visual',
MidnightTheme = 'theme:midnight',
NoteHistory30Days = 'server:note-history-30-days',
NoteHistory365Days = 'server:note-history-365-days',
NoteHistoryUnlimited = 'server:note-history-unlimited',
PlusEditor = 'editor:plus',
SheetsEditor = 'editor:sheets',
SignInAlerts = 'server:sign-in-alerts',
SmartFilters = 'app:smart-filters',
SolarizedDarkTheme = 'theme:solarized-dark',
TagNesting = 'app:tag-nesting',
TaskEditor = 'editor:task-editor',
ThemeDynamic = 'theme:dynamic',
TitaniumTheme = 'theme:titanium',
TokenVaultEditor = 'editor:token-vault',
TwoFactorAuth = 'server:two-factor-auth',
}

View File

@@ -0,0 +1,13 @@
export * from './Feature/FeatureDescription'
export * from './Feature/FeatureIdentifier'
export * from './Feature/Features'
export * from './Permission/Permission'
export * from './Permission/PermissionName'
export * from './Component/ComponentAction'
export * from './Component/ComponentArea'
export * from './Component/ComponentFlag'
export * from './Component/ComponentPermission'
export * from './Component/NoteType'
export * from './Component/ThemeDockIcon'

View File

@@ -0,0 +1 @@
export * from './Domain'