feat(web): tailwind css (#1147)

This commit is contained in:
Aman Harwara
2022-06-28 02:50:52 +05:30
committed by GitHub
parent 0ead805412
commit b80038f607
201 changed files with 1824 additions and 2699 deletions

Binary file not shown.

View File

@@ -37,7 +37,7 @@ const GroupSummary: React.FC<GroupSummaryProps> = ({ groups }) => {
return ( return (
<p data-testid="group-summary" key={`group-${group.name}`} className="mb-1"> <p data-testid="group-summary" key={`group-${group.name}`} className="mb-1">
{truncateText(group.name, MAX_GROUP_DESCRIPTION_LENGTH)} {truncateText(group.name, MAX_GROUP_DESCRIPTION_LENGTH)}
<span className="px-2 neutral"> <span className="px-2 text-neutral">
{totalCompletedTasks}/{totalTasks} {totalCompletedTasks}/{totalTasks}
</span> </span>
</p> </p>

View File

@@ -69,7 +69,7 @@ panel-resizer {
/* Required for BrowserWindow titleBarStyle: 'hiddenInset' */ /* Required for BrowserWindow titleBarStyle: 'hiddenInset' */
.mac-desktop #navigation, .mac-desktop #navigation,
.mac-desktop #navigation .section-title-bar, .mac-desktop #navigation .section-title-bar,
.mac-desktop #notes-title-bar, .mac-desktop #items-title-bar,
.mac-desktop #editor-title-bar, .mac-desktop #editor-title-bar,
.mac-desktop #lock-screen { .mac-desktop #lock-screen {
-webkit-app-region: drag; -webkit-app-region: drag;

View File

@@ -23,7 +23,7 @@ export class SKAlert {
buttonsString() { buttonsString() {
const genButton = function (buttonDesc: AlertButton, index: number) { const genButton = function (buttonDesc: AlertButton, index: number) {
return ` return `
<button id='button-${index}' class='sn-button small ${buttonDesc.style}'> <button id='button-${index}' class='font-bold px-2.5 py-2 text-xs text-info-contrast bg-${buttonDesc.style}'>
<div class='sk-label'>${buttonDesc.text}</div> <div class='sk-label'>${buttonDesc.text}</div>
</button> </button>
` `

View File

@@ -0,0 +1,68 @@
:root {
--sn-stylekit-neutral-color: #989898;
--sn-stylekit-neutral-contrast-color: #ffffff;
--sn-stylekit-info-color: #086dd6;
--sn-stylekit-info-color-darkened: #065cb5;
--sn-stylekit-info-contrast-color: #ffffff;
--sn-stylekit-info-backdrop-color: #2b6fcf0f;
--sn-stylekit-success-color: #007662;
--sn-stylekit-success-contrast-color: #ffffff;
--sn-stylekit-warning-color: #ebad00;
--sn-stylekit-warning-contrast-color: #ffffff;
--sn-stylekit-danger-color: #cc2128;
--sn-stylekit-danger-contrast-color: #ffffff;
--sn-stylekit-shadow-color: #c8c8c8;
--sn-stylekit-background-color: #ffffff;
// For borders inside background-color
--sn-stylekit-border-color: #dfe1e4;
--sn-stylekit-foreground-color: #000000;
// Colors for layers placed on top of non-prefixed background, border, and foreground
--sn-stylekit-contrast-background-color: #f6f6f6;
--sn-stylekit-contrast-foreground-color: #2e2e2e;
--sn-stylekit-contrast-border-color: #e3e3e3; // For borders inside contrast-background-color
// Alternative set of background and contrast options
--sn-stylekit-secondary-background-color: #f6f6f6;
--sn-stylekit-secondary-foreground-color: #2e2e2e;
--sn-stylekit-secondary-border-color: #e3e3e3;
--sn-stylekit-secondary-contrast-background-color: #e3e3e3;
--sn-stylekit-secondary-contrast-foreground-color: #2e2e2e;
--sn-stylekit-secondary-contrast-border-color: #a2a2a2;
--sn-stylekit-editor-background-color: var(--sn-stylekit-background-color);
--sn-stylekit-editor-foreground-color: var(--sn-stylekit-foreground-color);
--sn-stylekit-paragraph-text-color: #454545;
--sn-stylekit-input-placeholder-color: #a8a8a8;
--sn-stylekit-input-border-color: #e3e3e3;
--sn-stylekit-scrollbar-thumb-color: #dfdfdf;
--sn-stylekit-scrollbar-track-border-color: #e7e7e7;
--sn-stylekit-theme-type: light;
--sn-stylekit-theme-name: sn-light;
--sn-stylekit-passive-color-0: #515357;
--sn-stylekit-passive-color-1: #72767e;
--sn-stylekit-passive-color-2: #bbbec4;
--sn-stylekit-passive-color-3: #dfe1e4;
--sn-stylekit-passive-color-4: #eeeff1;
--sn-stylekit-passive-color-4-opacity-variant: #bbbec43d;
--sn-stylekit-passive-color-5: #f4f5f7;
--sn-stylekit-passive-color-6: #e5e5e5;
--sn-stylekit-passive-color-super-light: #f9f9f9;
--sn-stylekit-accessory-tint-color-1: #086dd6;
--sn-stylekit-accessory-tint-color-2: #ea6595;
--sn-stylekit-accessory-tint-color-3: #ebad00;
--sn-stylekit-accessory-tint-color-4: #7049cf;
--sn-stylekit-accessory-tint-color-5: #1aa772;
--sn-stylekit-accessory-tint-color-6: #f28c52;
}

View File

@@ -131,7 +131,8 @@
} }
.sk-panel-section-subtitle { .sk-panel-section-subtitle {
@extend .sk-label; font-size: var(--sn-stylekit-font-size-p);
font-weight: bold;
font-size: var(--sn-stylekit-font-size-h5); font-size: var(--sn-stylekit-font-size-h5);
margin-bottom: 2px; margin-bottom: 2px;

View File

@@ -1,4 +1,5 @@
@import 'normalize'; @import 'normalize';
@import 'colors';
:root { :root {
--sn-stylekit-base-font-size: 0.8125rem; --sn-stylekit-base-font-size: 0.8125rem;
@@ -13,53 +14,6 @@
--sn-stylekit-font-size-h2: 0.975rem; --sn-stylekit-font-size-h2: 0.975rem;
--sn-stylekit-font-size-h1: 1.05625rem; --sn-stylekit-font-size-h1: 1.05625rem;
--sn-stylekit-neutral-color: #989898;
--sn-stylekit-neutral-contrast-color: #ffffff;
--sn-stylekit-info-color: #086DD6;
--sn-stylekit-info-color-darkened: #065cb5;
--sn-stylekit-info-contrast-color: #ffffff;
--sn-stylekit-info-backdrop-color: #2b6fcf0f;
--sn-stylekit-success-color: #007662;
--sn-stylekit-success-contrast-color: #ffffff;
--sn-stylekit-warning-color: #EBAD00;
--sn-stylekit-warning-contrast-color: #ffffff;
--sn-stylekit-danger-color: #cc2128;
--sn-stylekit-danger-contrast-color: #ffffff;
--sn-stylekit-shadow-color: #c8c8c8;
--sn-stylekit-background-color: #ffffff;
// For borders inside background-color
--sn-stylekit-border-color: #dfe1e4;
--sn-stylekit-foreground-color: #000000;
// Colors for layers placed on top of non-prefixed background, border, and foreground
--sn-stylekit-contrast-background-color: #f6f6f6;
--sn-stylekit-contrast-foreground-color: #2e2e2e;
--sn-stylekit-contrast-border-color: #e3e3e3; // For borders inside contrast-background-color
// Alternative set of background and contrast options
--sn-stylekit-secondary-background-color: #f6f6f6;
--sn-stylekit-secondary-foreground-color: #2e2e2e;
--sn-stylekit-secondary-border-color: #e3e3e3;
--sn-stylekit-secondary-contrast-background-color: #e3e3e3;
--sn-stylekit-secondary-contrast-foreground-color: #2e2e2e;
--sn-stylekit-secondary-contrast-border-color: #a2a2a2;
--sn-stylekit-editor-background-color: var(--sn-stylekit-background-color);
--sn-stylekit-editor-foreground-color: var(--sn-stylekit-foreground-color);
--sn-stylekit-paragraph-text-color: #454545;
--sn-stylekit-input-placeholder-color: #a8a8a8;
--sn-stylekit-input-border-color: #e3e3e3;
--sn-stylekit-scrollbar-thumb-color: #dfdfdf;
--sn-stylekit-scrollbar-track-border-color: #e7e7e7;
--sn-stylekit-menu-border: none; --sn-stylekit-menu-border: none;
--sn-stylekit-general-border-radius: 2px; --sn-stylekit-general-border-radius: 2px;
@@ -70,26 +24,6 @@
--sn-stylekit-sans-serif-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', --sn-stylekit-sans-serif-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu',
'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', var(--sn-stylekit-simplified-chinese-font), sans-serif; 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', var(--sn-stylekit-simplified-chinese-font), sans-serif;
--sn-stylekit-editor-font-family: var(--sn-stylekit-sans-serif-font); --sn-stylekit-editor-font-family: var(--sn-stylekit-sans-serif-font);
--sn-stylekit-theme-type: light;
--sn-stylekit-theme-name: sn-light;
--sn-stylekit-passive-color-0: #515357;
--sn-stylekit-passive-color-1: #72767e;
--sn-stylekit-passive-color-2: #bbbec4;
--sn-stylekit-passive-color-3: #dfe1e4;
--sn-stylekit-passive-color-4: #eeeff1;
--sn-stylekit-passive-color-4-opacity-variant: #bbbec43d;
--sn-stylekit-passive-color-5: #f4f5f7;
--sn-stylekit-passive-color-6: #e5e5e5;
--sn-stylekit-passive-color-super-light: #f9f9f9;
--sn-stylekit-accessory-tint-color-1: #086dd6;
--sn-stylekit-accessory-tint-color-2: #ea6595;
--sn-stylekit-accessory-tint-color-3: #ebad00;
--sn-stylekit-accessory-tint-color-4: #7049cf;
--sn-stylekit-accessory-tint-color-5: #1aa772;
--sn-stylekit-accessory-tint-color-6: #f28c52;
} }
.sn-component { .sn-component {

View File

@@ -12,23 +12,23 @@ const prefersReducedMotion = () => {
const colorForToastType = (type: ToastType) => { const colorForToastType = (type: ToastType) => {
switch (type) { switch (type) {
case ToastType.Success: case ToastType.Success:
return 'color-success' return 'text-success'
case ToastType.Error: case ToastType.Error:
return 'color-danger' return 'text-danger'
default: default:
return 'color-info' return 'text-info'
} }
} }
const iconForToastType = (type: ToastType) => { const iconForToastType = (type: ToastType) => {
switch (type) { switch (type) {
case ToastType.Success: case ToastType.Success:
return <CheckCircleFilledIcon className={colorForToastType(type)} /> return <CheckCircleFilledIcon className={`w-5 h-5 ${colorForToastType(type)}`} />
case ToastType.Error: case ToastType.Error:
return <ClearCircleFilledIcon className={colorForToastType(type)} /> return <ClearCircleFilledIcon className={`w-5 h-5 ${colorForToastType(type)}`} />
case ToastType.Progress: case ToastType.Progress:
case ToastType.Loading: case ToastType.Loading:
return <div className="sk-spinner w-4 h-4 spinner-info" /> return <div className="animate-spin border border-solid border-info border-r-transparent rounded-full w-4 h-4" />
default: default:
return null return null
} }
@@ -92,7 +92,7 @@ export const Toast = forwardRef(({ toast, index }: Props, ref: ForwardedRef<HTML
> >
<div className={`flex items-center w-full ${hasActions ? 'p-2 pl-3' : hasProgress ? 'px-3 py-2.5' : 'p-3'}`}> <div className={`flex items-center w-full ${hasActions ? 'p-2 pl-3' : hasProgress ? 'px-3 py-2.5' : 'p-3'}`}>
{icon ? <div className="flex flex-shrink-0 items-center justify-center sn-icon mr-2">{icon}</div> : null} {icon ? <div className="flex flex-shrink-0 items-center justify-center sn-icon mr-2">{icon}</div> : null}
<div className="text-sm">{toast.message}</div> <div className="text-sm text-text">{toast.message}</div>
{hasActions && ( {hasActions && (
<div className="ml-4"> <div className="ml-4">
{toast.actions?.map((action, index) => ( {toast.actions?.map((action, index) => (
@@ -116,9 +116,9 @@ export const Toast = forwardRef(({ toast, index }: Props, ref: ForwardedRef<HTML
)} )}
</div> </div>
{hasProgress && ( {hasProgress && (
<div className="toast-progress-bar"> <div className="rounded w-full bg-default overflow-hidden rounded-tl-none rounded-tr-none">
<div <div
className="toast-progress-bar__value" className="rounded h-2 bg-info rounded-tl-none transition-[width] duration-100"
role="progressbar" role="progressbar"
style={{ style={{
width: `${toast.progress}%`, width: `${toast.progress}%`,

View File

@@ -11,7 +11,7 @@ export const ToastContainer: FunctionComponent = () => {
} }
return ( return (
<div className="flex flex-col items-end fixed z-index-toast bottom-6 right-6"> <div className="flex flex-col items-end fixed z-toast bottom-6 right-6">
{toasts.map((toast, index) => ( {toasts.map((toast, index) => (
<ToastTimer toast={toast} index={index} key={toast.id} /> <ToastTimer toast={toast} index={index} key={toast.id} />
))} ))}

View File

@@ -28,6 +28,7 @@
"@types/react": "^17.0.42", "@types/react": "^17.0.42",
"@types/react-dom": "^18.0.5", "@types/react-dom": "^18.0.5",
"@types/wicg-file-system-access": "^2020.9.5", "@types/wicg-file-system-access": "^2020.9.5",
"autoprefixer": "^10.4.7",
"babel-loader": "^8.2.5", "babel-loader": "^8.2.5",
"circular-dependency-plugin": "^5.2.2", "circular-dependency-plugin": "^5.2.2",
"css-loader": "*", "css-loader": "*",
@@ -43,9 +44,12 @@
"mini-css-extract-plugin": "^2.6.0", "mini-css-extract-plugin": "^2.6.0",
"node-sass": "*", "node-sass": "*",
"npm-check-updates": "*", "npm-check-updates": "*",
"postcss": "^8.4.14",
"postcss-loader": "^7.0.0",
"prettier": "*", "prettier": "*",
"sass-loader": "*", "sass-loader": "*",
"svg-jest": "^1.0.1", "svg-jest": "^1.0.1",
"tailwindcss": "^3.1.4",
"ts-jest": "^27.1.4", "ts-jest": "^27.1.4",
"ts-loader": "^9.2.8", "ts-loader": "^9.2.8",
"typescript": "*", "typescript": "*",

View File

@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

View File

@@ -58,8 +58,8 @@ const AccountMenu: FunctionComponent<Props> = ({
return ( return (
<div ref={ref} id="account-menu" className="sn-component"> <div ref={ref} id="account-menu" className="sn-component">
<div <div
className={`sn-account-menu sn-dropdown ${ className={`z-footer-bar-item-panel bottom-full left-0 cursor-auto bg-default rounded shadow-main ${
shouldAnimateCloseMenu ? 'slide-up-animation' : 'sn-dropdown--animated' shouldAnimateCloseMenu ? 'slide-up-animation' : 'transition-transform duration-150 slide-down-animation'
} min-w-80 max-h-120 max-w-xs flex flex-col py-2 overflow-y-auto absolute`} } min-w-80 max-h-120 max-w-xs flex flex-col py-2 overflow-y-auto absolute`}
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
> >

View File

@@ -98,12 +98,12 @@ const AdvancedOptions: FunctionComponent<Props> = ({
return ( return (
<> <>
<button <button
className="sn-dropdown-item focus:bg-info-backdrop focus:shadow-none font-bold" className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full text-sm focus:bg-info-backdrop focus:shadow-none font-bold"
onClick={toggleShowAdvanced} onClick={toggleShowAdvanced}
> >
<div className="flex items-center"> <div className="flex items-center">
Advanced options Advanced options
<Icon type="chevron-down" className="color-passive-1 ml-1" /> <Icon type="chevron-down" className="text-passive-1 ml-1" />
</div> </div>
</button> </button>
{showAdvanced ? ( {showAdvanced ? (
@@ -119,7 +119,7 @@ const AdvancedOptions: FunctionComponent<Props> = ({
onChange={handleIsPrivateWorkspaceChange} onChange={handleIsPrivateWorkspaceChange}
/> />
<a href="https://standardnotes.com/help/80" target="_blank" rel="noopener noreferrer" title="Learn more"> <a href="https://standardnotes.com/help/80" target="_blank" rel="noopener noreferrer" title="Learn more">
<Icon type="info" className="color-neutral" /> <Icon type="info" className="text-neutral" />
</a> </a>
</div> </div>
@@ -127,7 +127,7 @@ const AdvancedOptions: FunctionComponent<Props> = ({
<> <>
<DecoratedInput <DecoratedInput
className={'mb-2'} className={'mb-2'}
left={[<Icon type="server" className="color-neutral" />]} left={[<Icon type="server" className="text-neutral" />]}
type="text" type="text"
placeholder="Userphrase" placeholder="Userphrase"
value={privateWorkspaceUserphrase} value={privateWorkspaceUserphrase}
@@ -136,7 +136,7 @@ const AdvancedOptions: FunctionComponent<Props> = ({
/> />
<DecoratedInput <DecoratedInput
className={'mb-2'} className={'mb-2'}
left={[<Icon type="folder" className="color-neutral" />]} left={[<Icon type="folder" className="text-neutral" />]}
type="text" type="text"
placeholder="Name" placeholder="Name"
value={privateWorkspaceName} value={privateWorkspaceName}
@@ -161,7 +161,7 @@ const AdvancedOptions: FunctionComponent<Props> = ({
rel="noopener noreferrer" rel="noopener noreferrer"
title="Learn more" title="Learn more"
> >
<Icon type="info" className="color-neutral" /> <Icon type="info" className="text-neutral" />
</a> </a>
</div> </div>
)} )}
@@ -175,7 +175,7 @@ const AdvancedOptions: FunctionComponent<Props> = ({
/> />
<DecoratedInput <DecoratedInput
type="text" type="text"
left={[<Icon type="server" className="color-neutral" />]} left={[<Icon type="server" className="text-neutral" />]}
placeholder="https://api.standardnotes.com" placeholder="https://api.standardnotes.com"
value={server} value={server}
onChange={handleSyncServerChange} onChange={handleSyncServerChange}

View File

@@ -105,34 +105,35 @@ const ConfirmPassword: FunctionComponent<Props> = ({
<IconButton <IconButton
icon="arrow-left" icon="arrow-left"
title="Go back" title="Go back"
className="flex mr-2 color-neutral p-0" className="flex mr-2 text-neutral p-0"
onClick={handleGoBack} onClick={handleGoBack}
focusable={true} focusable={true}
disabled={isRegistering} disabled={isRegistering}
/> />
<div className="sn-account-menu-headline">Confirm password</div> <div className="font-bold text-base">Confirm password</div>
</div> </div>
<div className="px-3 mb-3 text-sm"> <div className="px-3 mb-3 text-sm">
Because your notes are encrypted using your password,{' '} Because your notes are encrypted using your password,{' '}
<span className="color-danger">Standard Notes does not have a password reset option</span>. If you forget your <span className="text-danger">Standard Notes does not have a password reset option</span>. If you forget your
password, you will permanently lose access to your data. password, you will permanently lose access to your data.
</div> </div>
<form onSubmit={handleConfirmFormSubmit} className="px-3 mb-1"> <form onSubmit={handleConfirmFormSubmit} className="px-3 mb-1">
<DecoratedPasswordInput <DecoratedPasswordInput
className="mb-2" className="mb-2"
disabled={isRegistering} disabled={isRegistering}
left={[<Icon type="password" className="color-neutral" />]} left={[<Icon type="password" className="text-neutral" />]}
onChange={handlePasswordChange} onChange={handlePasswordChange}
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
placeholder="Confirm password" placeholder="Confirm password"
ref={passwordInputRef} ref={passwordInputRef}
value={confirmPassword} value={confirmPassword}
/> />
{error ? <div className="color-danger my-2">{error}</div> : null} {error ? <div className="text-danger my-2">{error}</div> : null}
<Button <Button
className="btn-w-full mt-1 mb-3" primary
fullWidth
className="mt-1 mb-3"
label={isRegistering ? 'Creating account...' : 'Create account & sign in'} label={isRegistering ? 'Creating account...' : 'Create account & sign in'}
variant="primary"
onClick={handleConfirmFormSubmit} onClick={handleConfirmFormSubmit}
disabled={isRegistering} disabled={isRegistering}
/> />

View File

@@ -9,6 +9,7 @@ import DecoratedPasswordInput from '@/Components/Input/DecoratedPasswordInput'
import Icon from '@/Components/Icon/Icon' import Icon from '@/Components/Icon/Icon'
import IconButton from '@/Components/Button/IconButton' import IconButton from '@/Components/Button/IconButton'
import AdvancedOptions from './AdvancedOptions' import AdvancedOptions from './AdvancedOptions'
import HorizontalSeparator from '../Shared/HorizontalSeparator'
type Props = { type Props = {
viewControllerManager: ViewControllerManager viewControllerManager: ViewControllerManager
@@ -105,17 +106,17 @@ const CreateAccount: FunctionComponent<Props> = ({
<IconButton <IconButton
icon="arrow-left" icon="arrow-left"
title="Go back" title="Go back"
className="flex mr-2 color-neutral p-0" className="flex mr-2 text-neutral p-0"
onClick={handleClose} onClick={handleClose}
focusable={true} focusable={true}
/> />
<div className="sn-account-menu-headline">Create account</div> <div className="font-bold text-base">Create account</div>
</div> </div>
<form onSubmit={handleRegisterFormSubmit} className="px-3 mb-1"> <form onSubmit={handleRegisterFormSubmit} className="px-3 mb-1">
<DecoratedInput <DecoratedInput
className="mb-2" className="mb-2"
disabled={isPrivateWorkspace} disabled={isPrivateWorkspace}
left={[<Icon type="email" className="color-neutral" />]} left={[<Icon type="email" className="text-neutral" />]}
onChange={handleEmailChange} onChange={handleEmailChange}
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
placeholder="Email" placeholder="Email"
@@ -125,16 +126,16 @@ const CreateAccount: FunctionComponent<Props> = ({
/> />
<DecoratedPasswordInput <DecoratedPasswordInput
className="mb-2" className="mb-2"
left={[<Icon type="password" className="color-neutral" />]} left={[<Icon type="password" className="text-neutral" />]}
onChange={handlePasswordChange} onChange={handlePasswordChange}
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
placeholder="Password" placeholder="Password"
ref={passwordInputRef} ref={passwordInputRef}
value={password} value={password}
/> />
<Button className="btn-w-full mt-1" label="Next" variant="primary" onClick={handleRegisterFormSubmit} /> <Button className="mt-1" label="Next" primary onClick={handleRegisterFormSubmit} fullWidth={true} />
</form> </form>
<div className="h-1px my-2 bg-border"></div> <HorizontalSeparator classes="my-2" />
<AdvancedOptions <AdvancedOptions
application={application} application={application}
viewControllerManager={viewControllerManager} viewControllerManager={viewControllerManager}

View File

@@ -13,6 +13,7 @@ import { MenuItemType } from '@/Components/Menu/MenuItemType'
import WorkspaceSwitcherOption from './WorkspaceSwitcher/WorkspaceSwitcherOption' import WorkspaceSwitcherOption from './WorkspaceSwitcher/WorkspaceSwitcherOption'
import { ApplicationGroup } from '@/Application/ApplicationGroup' import { ApplicationGroup } from '@/Application/ApplicationGroup'
import { formatLastSyncDate } from '@/Utils/FormatLastSyncDate' import { formatLastSyncDate } from '@/Utils/FormatLastSyncDate'
import Spinner from '@/Components/Spinner/Spinner'
type Props = { type Props = {
viewControllerManager: ViewControllerManager viewControllerManager: ViewControllerManager
@@ -22,7 +23,7 @@ type Props = {
closeMenu: () => void closeMenu: () => void
} }
const iconClassName = 'color-neutral mr-2' const iconClassName = 'text-neutral mr-2'
const GeneralAccountMenu: FunctionComponent<Props> = ({ const GeneralAccountMenu: FunctionComponent<Props> = ({
application, application,
@@ -89,34 +90,34 @@ const GeneralAccountMenu: FunctionComponent<Props> = ({
return ( return (
<> <>
<div className="flex items-center justify-between px-3 mt-1 mb-1"> <div className="flex items-center justify-between px-3 mt-1 mb-1">
<div className="sn-account-menu-headline">Account</div> <div className="font-bold text-base">Account</div>
<div className="flex cursor-pointer" onClick={closeMenu}> <div className="flex cursor-pointer" onClick={closeMenu}>
<Icon type="close" className="color-neutral" /> <Icon type="close" className="text-neutral" />
</div> </div>
</div> </div>
{user ? ( {user ? (
<> <>
<div className="px-3 mb-3 color-foreground text-sm"> <div className="px-3 mb-3 text-foreground text-sm">
<div>You're signed in as:</div> <div>You're signed in as:</div>
<div className="my-0.5 font-bold wrap">{user.email}</div> <div className="my-0.5 font-bold wrap">{user.email}</div>
<span className="color-neutral">{application.getHost()}</span> <span className="text-neutral">{application.getHost()}</span>
</div> </div>
<div className="flex items-start justify-between px-3 mb-3"> <div className="flex items-start justify-between px-3 mb-2">
{isSyncingInProgress ? ( {isSyncingInProgress ? (
<div className="flex items-center color-info font-semibold"> <div className="flex items-center text-info text-sm font-semibold">
<div className="sk-spinner w-5 h-5 mr-2 spinner-info"></div> <Spinner className="w-5 h-5 mr-2" />
Syncing... Syncing...
</div> </div>
) : ( ) : (
<div className="flex items-start"> <div className="flex items-start">
<Icon type="check-circle" className="mr-2 success" /> <Icon type="check-circle" className="mr-2 text-success" />
<div> <div>
<div className="font-semibold success">Last synced:</div> <div className="font-semibold text-success text-sm">Last synced:</div>
<div className="color-text">{lastSyncDate}</div> <div className="text-text text-sm">{lastSyncDate}</div>
</div> </div>
</div> </div>
)} )}
<div className="flex cursor-pointer color-passive-1" onClick={doSynchronization}> <div className="flex cursor-pointer text-passive-1" onClick={doSynchronization}>
<Icon type="sync" /> <Icon type="sync" />
</div> </div>
</div> </div>
@@ -124,13 +125,13 @@ const GeneralAccountMenu: FunctionComponent<Props> = ({
) : ( ) : (
<> <>
<div className="px-3 mb-1"> <div className="px-3 mb-1">
<div className="mb-3 color-foreground"> <div className="mb-3 text-foreground text-sm">
Youre offline. Sign in to sync your notes and preferences across all your devices and enable end-to-end Youre offline. Sign in to sync your notes and preferences across all your devices and enable end-to-end
encryption. encryption.
</div> </div>
<div className="flex items-center color-passive-1"> <div className="flex items-center text-passive-1">
<Icon type="cloud-off" className="mr-2" /> <Icon type="cloud-off" className="mr-2" />
<span className="font-semibold">Offline</span> <span className="font-semibold text-sm">Offline</span>
</div> </div>
</div> </div>
</> </>
@@ -169,7 +170,7 @@ const GeneralAccountMenu: FunctionComponent<Props> = ({
<Icon type="help" className={iconClassName} /> <Icon type="help" className={iconClassName} />
Help &amp; feedback Help &amp; feedback
</div> </div>
<span className="color-neutral">v{application.version}</span> <span className="text-neutral">v{application.version}</span>
</MenuItem> </MenuItem>
{user ? ( {user ? (
<> <>

View File

@@ -11,6 +11,7 @@ import DecoratedPasswordInput from '@/Components/Input/DecoratedPasswordInput'
import Icon from '@/Components/Icon/Icon' import Icon from '@/Components/Icon/Icon'
import IconButton from '@/Components/Button/IconButton' import IconButton from '@/Components/Button/IconButton'
import AdvancedOptions from './AdvancedOptions' import AdvancedOptions from './AdvancedOptions'
import HorizontalSeparator from '../Shared/HorizontalSeparator'
type Props = { type Props = {
viewControllerManager: ViewControllerManager viewControllerManager: ViewControllerManager
@@ -143,17 +144,17 @@ const SignInPane: FunctionComponent<Props> = ({ application, viewControllerManag
<IconButton <IconButton
icon="arrow-left" icon="arrow-left"
title="Go back" title="Go back"
className="flex mr-2 color-neutral p-0" className="flex mr-2 text-neutral p-0"
onClick={() => setMenuPane(AccountMenuPane.GeneralMenu)} onClick={() => setMenuPane(AccountMenuPane.GeneralMenu)}
focusable={true} focusable={true}
disabled={isSigningIn} disabled={isSigningIn}
/> />
<div className="sn-account-menu-headline">Sign in</div> <div className="font-bold text-base">Sign in</div>
</div> </div>
<div className="px-3 mb-1"> <div className="px-3 mb-1">
<DecoratedInput <DecoratedInput
className={`mb-2 ${error ? 'border-danger' : null}`} className={`mb-2 ${error ? 'border-danger' : null}`}
left={[<Icon type="email" className="color-neutral" />]} left={[<Icon type="email" className="text-neutral" />]}
type="email" type="email"
placeholder="Email" placeholder="Email"
value={email} value={email}
@@ -166,7 +167,7 @@ const SignInPane: FunctionComponent<Props> = ({ application, viewControllerManag
<DecoratedPasswordInput <DecoratedPasswordInput
className={`mb-2 ${error ? 'border-danger' : null}`} className={`mb-2 ${error ? 'border-danger' : null}`}
disabled={isSigningIn} disabled={isSigningIn}
left={[<Icon type="password" className="color-neutral" />]} left={[<Icon type="password" className="text-neutral" />]}
onChange={handlePasswordChange} onChange={handlePasswordChange}
onFocus={resetInvalid} onFocus={resetInvalid}
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
@@ -174,13 +175,14 @@ const SignInPane: FunctionComponent<Props> = ({ application, viewControllerManag
ref={passwordInputRef} ref={passwordInputRef}
value={password} value={password}
/> />
{error ? <div className="color-danger my-2">{error}</div> : null} {error ? <div className="text-danger my-2">{error}</div> : null}
<Button <Button
className="btn-w-full mt-1 mb-3" className="mt-1 mb-3"
label={isSigningIn ? 'Signing in...' : 'Sign in'} label={isSigningIn ? 'Signing in...' : 'Sign in'}
variant="primary" primary
onClick={handleSignInFormSubmit} onClick={handleSignInFormSubmit}
disabled={isSigningIn} disabled={isSigningIn}
fullWidth={true}
/> />
<Checkbox <Checkbox
name="is-ephemeral" name="is-ephemeral"
@@ -199,7 +201,7 @@ const SignInPane: FunctionComponent<Props> = ({ application, viewControllerManag
/> />
) : null} ) : null}
</div> </div>
<div className="h-1px my-2 bg-border"></div> <HorizontalSeparator classes="my-2" />
<AdvancedOptions <AdvancedOptions
viewControllerManager={viewControllerManager} viewControllerManager={viewControllerManager}
application={application} application={application}

View File

@@ -58,7 +58,7 @@ const WorkspaceMenuItem: FunctionComponent<Props> = ({
return ( return (
<MenuItem <MenuItem
type={MenuItemType.RadioButton} type={MenuItemType.RadioButton}
className="sn-dropdown-item py-2 focus:bg-info-backdrop focus:shadow-none" className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-2 text-left w-full focus:bg-info-backdrop focus:shadow-none text-sm"
onClick={onClick} onClick={onClick}
checked={descriptor.primary} checked={descriptor.primary}
> >
@@ -76,7 +76,7 @@ const WorkspaceMenuItem: FunctionComponent<Props> = ({
<div>{descriptor.label}</div> <div>{descriptor.label}</div>
)} )}
{descriptor.primary && !hideOptions && ( {descriptor.primary && !hideOptions && (
<div> <div className="flex items-center">
<a <a
role="button" role="button"
className="w-5 h-5 p-0 mr-3 border-0 bg-transparent hover:bg-contrast cursor-pointer" className="w-5 h-5 p-0 mr-3 border-0 bg-transparent hover:bg-contrast cursor-pointer"
@@ -85,7 +85,7 @@ const WorkspaceMenuItem: FunctionComponent<Props> = ({
setIsRenaming((isRenaming) => !isRenaming) setIsRenaming((isRenaming) => !isRenaming)
}} }}
> >
<Icon type="pencil" className="sn-icon--mid color-neutral" /> <Icon type="pencil" className="text-neutral" size="medium" />
</a> </a>
<a <a
role="button" role="button"
@@ -95,7 +95,7 @@ const WorkspaceMenuItem: FunctionComponent<Props> = ({
onDelete() onDelete()
}} }}
> >
<Icon type="trash" className="sn-icon--mid color-danger" /> <Icon type="trash" className="text-danger" size="medium" />
</a> </a>
</div> </div>
)} )}

View File

@@ -78,13 +78,13 @@ const WorkspaceSwitcherMenu: FunctionComponent<Props> = ({
void mainApplicationGroup.unloadCurrentAndCreateNewDescriptor() void mainApplicationGroup.unloadCurrentAndCreateNewDescriptor()
}} }}
> >
<Icon type="user-add" className="color-neutral mr-2" /> <Icon type="user-add" className="text-neutral mr-2" />
Add another workspace Add another workspace
</MenuItem> </MenuItem>
{!hideWorkspaceOptions && ( {!hideWorkspaceOptions && (
<MenuItem type={MenuItemType.IconButton} onClick={signoutAll}> <MenuItem type={MenuItemType.IconButton} onClick={signoutAll}>
<Icon type="signOut" className="color-neutral mr-2" /> <Icon type="signOut" className="text-neutral mr-2" />
Sign out all workspaces Sign out all workspaces
</MenuItem> </MenuItem>
)} )}

View File

@@ -6,6 +6,8 @@ import { observer } from 'mobx-react-lite'
import { FunctionComponent, useCallback, useEffect, useRef, useState } from 'react' import { FunctionComponent, useCallback, useEffect, useRef, useState } from 'react'
import Icon from '@/Components/Icon/Icon' import Icon from '@/Components/Icon/Icon'
import WorkspaceSwitcherMenu from './WorkspaceSwitcherMenu' import WorkspaceSwitcherMenu from './WorkspaceSwitcherMenu'
import MenuItem from '@/Components/Menu/MenuItem'
import { MenuItemType } from '@/Components/Menu/MenuItemType'
type Props = { type Props = {
mainApplicationGroup: ApplicationGroup mainApplicationGroup: ApplicationGroup
@@ -43,21 +45,25 @@ const WorkspaceSwitcherOption: FunctionComponent<Props> = ({ mainApplicationGrou
return ( return (
<> <>
<button <MenuItem
ref={buttonRef}
className="sn-dropdown-item justify-between focus:bg-info-backdrop focus:shadow-none"
tabIndex={FOCUSABLE_BUT_NOT_TABBABLE} tabIndex={FOCUSABLE_BUT_NOT_TABBABLE}
role="menuitem" ref={buttonRef}
type={MenuItemType.IconButton}
onClick={toggleMenu} onClick={toggleMenu}
className="justify-between"
> >
<div className="flex items-center"> <div className="flex items-center">
<Icon type="user-switch" className="color-neutral mr-2" /> <Icon type="user-switch" className="text-neutral mr-2" />
Switch workspace Switch workspace
</div> </div>
<Icon type="chevron-right" className="color-neutral" /> <Icon type="chevron-right" className="text-neutral" />
</button> </MenuItem>
{isOpen && ( {isOpen && (
<div ref={menuRef} className="sn-dropdown max-h-120 min-w-68 py-2 fixed overflow-y-auto" style={menuStyle}> <div
ref={menuRef}
className="bg-default rounded shadow-main max-h-120 min-w-68 py-2 fixed overflow-y-auto"
style={menuStyle}
>
<WorkspaceSwitcherMenu <WorkspaceSwitcherMenu
mainApplicationGroup={mainApplicationGroup} mainApplicationGroup={mainApplicationGroup}
viewControllerManager={viewControllerManager} viewControllerManager={viewControllerManager}

View File

@@ -84,7 +84,7 @@ class ApplicationGroupView extends Component<Props, State> {
<DialogContent <DialogContent
aria-label="Switching workspace" aria-label="Switching workspace"
className={ className={
'challenge-modal flex flex-col items-center bg-default p-8 rounded relative shadow-overlay-light border-1 border-solid border-main' 'challenge-modal flex flex-col items-center bg-default p-8 rounded relative shadow-overlay-light border border-solid border-border'
} }
> >
{message} {message}

View File

@@ -270,12 +270,14 @@ const AttachedFilesButton: FunctionComponent<Props> = ({
} }
}} }}
ref={buttonRef} ref={buttonRef}
className={`sn-icon-button border-contrast ${attachedFilesCount > 0 ? 'py-1 px-3' : ''}`} className={`flex justify-center items-center min-w-8 h-8 bg-text-padding hover:bg-contrast focus:bg-contrast text-neutral border border-solid border-border rounded-full cursor-pointer ${
attachedFilesCount > 0 ? 'py-1 px-3' : ''
}`}
onBlur={closeOnBlur} onBlur={closeOnBlur}
> >
<VisuallyHidden>Attached files</VisuallyHidden> <VisuallyHidden>Attached files</VisuallyHidden>
<Icon type="attachment-file" className="block" /> <Icon type="attachment-file" className="block" />
{attachedFilesCount > 0 && <span className="ml-2">{attachedFilesCount}</span>} {attachedFilesCount > 0 && <span className="text-sm ml-2">{attachedFilesCount}</span>}
</DisclosureButton> </DisclosureButton>
<DisclosurePanel <DisclosurePanel
onKeyDown={(event) => { onKeyDown={(event) => {
@@ -289,7 +291,7 @@ const AttachedFilesButton: FunctionComponent<Props> = ({
...position, ...position,
maxHeight, maxHeight,
}} }}
className="sn-dropdown sn-dropdown--animated min-w-80 max-h-120 max-w-xs flex flex-col overflow-y-auto fixed" className="bg-default rounded shadow-main transition-transform duration-150 slide-down-animation min-w-80 max-h-120 max-w-xs flex flex-col overflow-y-auto fixed"
onBlur={closeOnBlur} onBlur={closeOnBlur}
> >
{open && ( {open && (

View File

@@ -78,12 +78,12 @@ const AttachedFilesPopover: FunctionComponent<Props> = ({
border: isDraggingFiles ? '2px dashed var(--sn-stylekit-info-color)' : '', border: isDraggingFiles ? '2px dashed var(--sn-stylekit-info-color)' : '',
}} }}
> >
<div className="flex border-0 border-b-1 border-solid border-main"> <div className="flex border-b border-solid border-border">
<button <button
id={PopoverTabs.AttachedFiles} id={PopoverTabs.AttachedFiles}
className={`bg-default border-0 cursor-pointer px-3 py-2.5 relative focus:bg-info-backdrop focus:shadow-bottom ${ className={`bg-default border-0 cursor-pointer px-3 py-2.5 relative focus:bg-info-backdrop focus:shadow-bottom text-sm ${
currentTab === PopoverTabs.AttachedFiles ? 'color-info font-medium shadow-bottom' : 'color-text' currentTab === PopoverTabs.AttachedFiles ? 'text-info font-medium shadow-bottom' : 'text-text'
} ${attachedTabDisabled ? 'color-neutral cursor-not-allowed' : ''}`} } ${attachedTabDisabled ? 'text-neutral cursor-not-allowed' : ''}`}
onClick={() => { onClick={() => {
setCurrentTab(PopoverTabs.AttachedFiles) setCurrentTab(PopoverTabs.AttachedFiles)
}} }}
@@ -94,8 +94,8 @@ const AttachedFilesPopover: FunctionComponent<Props> = ({
</button> </button>
<button <button
id={PopoverTabs.AllFiles} id={PopoverTabs.AllFiles}
className={`bg-default border-0 cursor-pointer px-3 py-2.5 relative focus:bg-info-backdrop focus:shadow-bottom ${ className={`bg-default border-0 cursor-pointer px-3 py-2.5 relative focus:bg-info-backdrop focus:shadow-bottom text-sm ${
currentTab === PopoverTabs.AllFiles ? 'color-info font-medium shadow-bottom' : 'color-text' currentTab === PopoverTabs.AllFiles ? 'text-info font-medium shadow-bottom' : 'text-text'
}`} }`}
onClick={() => { onClick={() => {
setCurrentTab(PopoverTabs.AllFiles) setCurrentTab(PopoverTabs.AllFiles)
@@ -107,11 +107,11 @@ const AttachedFilesPopover: FunctionComponent<Props> = ({
</div> </div>
<div className="min-h-0 max-h-110 overflow-y-auto"> <div className="min-h-0 max-h-110 overflow-y-auto">
{filteredList.length > 0 || searchQuery.length > 0 ? ( {filteredList.length > 0 || searchQuery.length > 0 ? (
<div className="sticky top-0 left-0 p-3 bg-default border-0 border-b-1 border-solid border-main"> <div className="sticky top-0 left-0 p-3 bg-default border-b border-solid border-border">
<div className="relative"> <div className="relative">
<input <input
type="text" type="text"
className="color-text w-full rounded py-1.5 px-3 text-input bg-default border-solid border-1 border-main" className="text-text w-full rounded py-1.5 px-3 text-sm bg-default border-solid border border-border"
placeholder="Search files..." placeholder="Search files..."
value={searchQuery} value={searchQuery}
onInput={(e) => { onInput={(e) => {
@@ -129,7 +129,7 @@ const AttachedFilesPopover: FunctionComponent<Props> = ({
}} }}
onBlur={closeOnBlur} onBlur={closeOnBlur}
> >
<Icon type="clear-circle-filled" className="color-neutral" /> <Icon type="clear-circle-filled" className="text-neutral" />
</button> </button>
)} )}
</div> </div>
@@ -161,20 +161,20 @@ const AttachedFilesPopover: FunctionComponent<Props> = ({
? 'No files attached to this note' ? 'No files attached to this note'
: 'No files found in this account'} : 'No files found in this account'}
</div> </div>
<Button variant="normal" onClick={handleAttachFilesClick} onBlur={closeOnBlur}> <Button onClick={handleAttachFilesClick} onBlur={closeOnBlur}>
{currentTab === PopoverTabs.AttachedFiles ? 'Attach' : 'Upload'} files {currentTab === PopoverTabs.AttachedFiles ? 'Attach' : 'Upload'} files
</Button> </Button>
<div className="text-xs color-passive-0 mt-3">Or drop your files here</div> <div className="text-xs text-passive-0 mt-3">Or drop your files here</div>
</div> </div>
)} )}
</div> </div>
{filteredList.length > 0 && ( {filteredList.length > 0 && (
<button <button
className="sn-dropdown-item py-3 border-0 border-t-1px border-solid border-main focus:bg-info-backdrop" className="flex items-center cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-3 text-left w-full focus:bg-info-backdrop focus:shadow-none text-sm border-0 border-t border-solid border-border"
onClick={handleAttachFilesClick} onClick={handleAttachFilesClick}
onBlur={closeOnBlur} onBlur={closeOnBlur}
> >
<Icon type="add" className="mr-2 color-neutral" /> <Icon type="add" className="mr-2 text-neutral" />
{currentTab === PopoverTabs.AttachedFiles ? 'Attach' : 'Upload'} files {currentTab === PopoverTabs.AttachedFiles ? 'Attach' : 'Upload'} files
</button> </button>
)} )}

View File

@@ -91,7 +91,7 @@ const PopoverFileItem: FunctionComponent<PopoverFileItemProps> = ({
{isRenamingFile ? ( {isRenamingFile ? (
<input <input
type="text" type="text"
className="text-input px-1.5 py-1 mb-1 border-1 border-solid border-main bg-transparent color-foreground" className="text-input px-1.5 py-1 mb-1 border border-solid border-border bg-transparent text-foreground"
value={fileName} value={fileName}
ref={fileNameInputRef} ref={fileNameInputRef}
onInput={handleFileNameInput} onInput={handleFileNameInput}
@@ -100,13 +100,13 @@ const PopoverFileItem: FunctionComponent<PopoverFileItemProps> = ({
/> />
) : ( ) : (
<div className="text-sm mb-1 break-word"> <div className="text-sm mb-1 break-word">
<span className="vertical-middle">{file.name}</span> <span className="align-middle">{file.name}</span>
{file.protected && ( {file.protected && (
<Icon type="lock-filled" className="sn-icon--small ml-2 color-neutral vertical-middle" /> <Icon type="lock-filled" className="ml-2 text-neutral inline align-middle" size="small" />
)} )}
</div> </div>
)} )}
<div className="text-xs color-passive-0"> <div className="text-xs text-passive-0">
{file.created_at.toLocaleString()} · {formatSizeToReadableString(file.decryptedSize)} {file.created_at.toLocaleString()} · {formatSizeToReadableString(file.decryptedSize)}
</div> </div>
</div> </div>

View File

@@ -7,6 +7,7 @@ import Switch from '@/Components/Switch/Switch'
import { useCloseOnBlur } from '@/Hooks/useCloseOnBlur' import { useCloseOnBlur } from '@/Hooks/useCloseOnBlur'
import { PopoverFileSubmenuProps } from './PopoverFileItemProps' import { PopoverFileSubmenuProps } from './PopoverFileItemProps'
import { PopoverFileItemActionType } from './PopoverFileItemAction' import { PopoverFileItemActionType } from './PopoverFileItemAction'
import HorizontalSeparator from '../Shared/HorizontalSeparator'
const PopoverFileSubmenu: FunctionComponent<PopoverFileSubmenuProps> = ({ const PopoverFileSubmenu: FunctionComponent<PopoverFileSubmenuProps> = ({
file, file,
@@ -67,7 +68,7 @@ const PopoverFileSubmenu: FunctionComponent<PopoverFileSubmenuProps> = ({
onBlur={closeOnBlur} onBlur={closeOnBlur}
className="w-7 h-7 p-1 rounded-full border-0 bg-transparent hover:bg-contrast cursor-pointer" className="w-7 h-7 p-1 rounded-full border-0 bg-transparent hover:bg-contrast cursor-pointer"
> >
<Icon type="more" className="color-neutral" /> <Icon type="more" className="text-neutral" />
</DisclosureButton> </DisclosureButton>
<DisclosurePanel <DisclosurePanel
ref={menuRef} ref={menuRef}
@@ -75,25 +76,27 @@ const PopoverFileSubmenu: FunctionComponent<PopoverFileSubmenuProps> = ({
...menuStyle, ...menuStyle,
position: 'fixed', position: 'fixed',
}} }}
className="sn-dropdown flex flex-col max-h-120 min-w-60 py-1 fixed overflow-y-auto" className={`${
isMenuOpen ? 'flex' : 'hidden'
} flex-col bg-default rounded shadow-main max-h-120 min-w-60 py-1 fixed overflow-y-auto`}
> >
{isMenuOpen && ( {isMenuOpen && (
<> <>
<button <button
onBlur={closeOnBlur} onBlur={closeOnBlur}
className="sn-dropdown-item focus:bg-info-backdrop" className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full focus:shadow-none text-sm focus:bg-info-backdrop"
onClick={() => { onClick={() => {
previewHandler(file) previewHandler(file)
closeMenu() closeMenu()
}} }}
> >
<Icon type="file" className="mr-2 color-neutral" /> <Icon type="file" className="mr-2 text-neutral" />
Preview file Preview file
</button> </button>
{isAttachedToNote ? ( {isAttachedToNote ? (
<button <button
onBlur={closeOnBlur} onBlur={closeOnBlur}
className="sn-dropdown-item focus:bg-info-backdrop" className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full focus:shadow-none text-sm focus:bg-info-backdrop"
onClick={() => { onClick={() => {
handleFileAction({ handleFileAction({
type: PopoverFileItemActionType.DetachFileToNote, type: PopoverFileItemActionType.DetachFileToNote,
@@ -102,13 +105,13 @@ const PopoverFileSubmenu: FunctionComponent<PopoverFileSubmenuProps> = ({
closeMenu() closeMenu()
}} }}
> >
<Icon type="link-off" className="mr-2 color-neutral" /> <Icon type="link-off" className="mr-2 text-neutral" />
Detach from note Detach from note
</button> </button>
) : ( ) : (
<button <button
onBlur={closeOnBlur} onBlur={closeOnBlur}
className="sn-dropdown-item focus:bg-info-backdrop" className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full focus:shadow-none text-sm focus:bg-info-backdrop"
onClick={() => { onClick={() => {
handleFileAction({ handleFileAction({
type: PopoverFileItemActionType.AttachFileToNote, type: PopoverFileItemActionType.AttachFileToNote,
@@ -117,13 +120,13 @@ const PopoverFileSubmenu: FunctionComponent<PopoverFileSubmenuProps> = ({
closeMenu() closeMenu()
}} }}
> >
<Icon type="link" className="mr-2 color-neutral" /> <Icon type="link" className="mr-2 text-neutral" />
Attach to note Attach to note
</button> </button>
)} )}
<div className="min-h-1px my-1 bg-border"></div> <HorizontalSeparator classes="my-1" />
<button <button
className="sn-dropdown-item justify-between focus:bg-info-backdrop" className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full focus:shadow-none text-sm justify-between focus:bg-info-backdrop"
onClick={() => { onClick={() => {
handleFileAction({ handleFileAction({
type: PopoverFileItemActionType.ToggleFileProtection, type: PopoverFileItemActionType.ToggleFileProtection,
@@ -136,7 +139,7 @@ const PopoverFileSubmenu: FunctionComponent<PopoverFileSubmenuProps> = ({
onBlur={closeOnBlur} onBlur={closeOnBlur}
> >
<span className="flex items-center"> <span className="flex items-center">
<Icon type="password" className="mr-2 color-neutral" /> <Icon type="password" className="mr-2 text-neutral" />
Password protection Password protection
</span> </span>
<Switch <Switch
@@ -145,10 +148,10 @@ const PopoverFileSubmenu: FunctionComponent<PopoverFileSubmenuProps> = ({
checked={isFileProtected} checked={isFileProtected}
/> />
</button> </button>
<div className="min-h-1px my-1 bg-border"></div> <HorizontalSeparator classes="my-1" />
<button <button
onBlur={closeOnBlur} onBlur={closeOnBlur}
className="sn-dropdown-item focus:bg-info-backdrop" className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full focus:shadow-none text-sm focus:bg-info-backdrop"
onClick={() => { onClick={() => {
handleFileAction({ handleFileAction({
type: PopoverFileItemActionType.DownloadFile, type: PopoverFileItemActionType.DownloadFile,
@@ -157,22 +160,22 @@ const PopoverFileSubmenu: FunctionComponent<PopoverFileSubmenuProps> = ({
closeMenu() closeMenu()
}} }}
> >
<Icon type="download" className="mr-2 color-neutral" /> <Icon type="download" className="mr-2 text-neutral" />
Download Download
</button> </button>
<button <button
onBlur={closeOnBlur} onBlur={closeOnBlur}
className="sn-dropdown-item focus:bg-info-backdrop" className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full focus:shadow-none text-sm focus:bg-info-backdrop"
onClick={() => { onClick={() => {
setIsRenamingFile(true) setIsRenamingFile(true)
}} }}
> >
<Icon type="pencil" className="mr-2 color-neutral" /> <Icon type="pencil" className="mr-2 text-neutral" />
Rename Rename
</button> </button>
<button <button
onBlur={closeOnBlur} onBlur={closeOnBlur}
className="sn-dropdown-item focus:bg-info-backdrop" className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full focus:shadow-none text-sm focus:bg-info-backdrop"
onClick={() => { onClick={() => {
handleFileAction({ handleFileAction({
type: PopoverFileItemActionType.DeleteFile, type: PopoverFileItemActionType.DeleteFile,
@@ -181,9 +184,14 @@ const PopoverFileSubmenu: FunctionComponent<PopoverFileSubmenuProps> = ({
closeMenu() closeMenu()
}} }}
> >
<Icon type="trash" className="mr-2 color-danger" /> <Icon type="trash" className="mr-2 text-danger" />
<span className="color-danger">Delete permanently</span> <span className="text-danger">Delete permanently</span>
</button> </button>
<div className="px-3 py-1 text-xs text-neutral font-medium">
<div>
<span className="font-semibold">File ID:</span> {file.uuid}
</div>
</div>
</> </>
)} )}
</DisclosurePanel> </DisclosurePanel>

View File

@@ -7,9 +7,9 @@ type Props = {
} }
const styles = { const styles = {
base: 'px-2 py-1.5 text-center rounded-full cursor-pointer transition border-1 border-solid active:border-info active:bg-info active:color-neutral-contrast', base: 'px-2 py-1 text-center rounded-full cursor-pointer transition border border-solid active:border-info active:bg-info active:text-neutral-contrast',
unselected: 'color-neutral border-secondary', unselected: 'text-neutral border-secondary-border',
selected: 'border-info bg-info color-neutral-contrast', selected: 'border-info bg-info text-neutral-contrast',
} }
const Bubble: FunctionComponent<Props> = ({ label, selected, onSelect }) => ( const Bubble: FunctionComponent<Props> = ({ label, selected, onSelect }) => (

View File

@@ -1,52 +1,99 @@
import { Ref, forwardRef, ReactNode, ComponentPropsWithoutRef } from 'react' import { Ref, forwardRef, ReactNode, ComponentPropsWithoutRef } from 'react'
const baseClass = 'rounded px-4 py-1.75 font-bold text-sm fit-content' type ButtonStyle = 'default' | 'contrast' | 'neutral' | 'info' | 'warning' | 'danger' | 'success'
type ButtonVariant = 'normal' | 'primary' const getColorsForNormalVariant = (style: ButtonStyle) => {
switch (style) {
const getClassName = (variant: ButtonVariant, danger: boolean, disabled: boolean) => { case 'default':
const borders = variant === 'normal' ? 'border-solid border-main border-1' : 'no-border' return 'bg-default text-text'
const cursor = disabled ? 'cursor-not-allowed' : 'cursor-pointer' case 'contrast':
return 'bg-default text-contrast'
let colors = variant === 'normal' ? 'bg-default color-text' : 'bg-info color-info-contrast' case 'neutral':
return 'bg-default text-neutral'
let focusHoverStates = case 'info':
variant === 'normal' return 'bg-default text-info'
? 'focus:bg-contrast focus:outline-none hover:bg-contrast' case 'warning':
: 'hover:brightness-130 focus:outline-none focus:brightness-130' return 'bg-default text-warning'
case 'danger':
if (danger) { return 'bg-default text-danger'
colors = variant === 'normal' ? 'bg-default color-danger' : 'bg-danger color-info-contrast' case 'success':
return 'bg-default text-success'
} }
}
const getColorsForPrimaryVariant = (style: ButtonStyle) => {
switch (style) {
case 'default':
return 'bg-default text-foreground'
case 'contrast':
return 'bg-contrast text-text'
case 'neutral':
return 'bg-neutral text-neutral-contrast'
case 'info':
return 'bg-info text-info-contrast'
case 'warning':
return 'bg-warning text-warning-contrast'
case 'danger':
return 'bg-danger text-danger-contrast'
case 'success':
return 'bg-success text-success-contrast'
}
}
const getClassName = (
primary: boolean,
style: ButtonStyle,
disabled: boolean,
fullWidth?: boolean,
small?: boolean,
isRounded?: boolean,
) => {
const borders = primary ? 'no-border' : 'border-solid border-border border'
const cursor = disabled ? 'cursor-not-allowed' : 'cursor-pointer'
const width = fullWidth ? 'w-full' : 'w-fit'
const padding = small ? 'px-3 py-1.5' : 'px-4 py-1.5'
const textSize = small ? 'text-xs' : 'text-sm'
const rounded = isRounded ? 'rounded' : ''
let colors = primary ? getColorsForPrimaryVariant(style) : getColorsForNormalVariant(style)
let focusHoverStates = primary
? 'hover:brightness-125 focus:outline-none focus:brightness-125'
: 'focus:bg-contrast focus:outline-none hover:bg-contrast'
if (disabled) { if (disabled) {
colors = variant === 'normal' ? 'bg-default color-passive-2' : 'bg-passive-2 color-info-contrast' colors = primary ? 'bg-passive-2 text-info-contrast' : 'bg-default text-passive-2'
focusHoverStates = focusHoverStates = primary
variant === 'normal' ? 'focus:brightness-100 focus:outline-none hover:brightness-100'
? 'focus:bg-default focus:outline-none hover:bg-default' : 'focus:bg-default focus:outline-none hover:bg-default'
: 'focus:brightness-default focus:outline-none hover:brightness-default'
} }
return `${baseClass} ${colors} ${borders} ${focusHoverStates} ${cursor}` return `${rounded} font-bold ${width} ${padding} ${textSize} ${colors} ${borders} ${focusHoverStates} ${cursor}`
} }
interface ButtonProps extends ComponentPropsWithoutRef<'button'> { interface ButtonProps extends ComponentPropsWithoutRef<'button'> {
children?: ReactNode children?: ReactNode
className?: string className?: string
variant?: ButtonVariant primary?: boolean
dangerStyle?: boolean colorStyle?: ButtonStyle
label?: string label?: string
fullWidth?: boolean
small?: boolean
rounded?: boolean
} }
const Button = forwardRef( const Button = forwardRef(
( (
{ {
variant = 'normal', primary = false,
label, label,
className = '', className = '',
dangerStyle: danger = false, colorStyle = primary ? 'info' : 'default',
disabled = false, disabled = false,
children, children,
fullWidth,
small,
rounded = true,
...props ...props
}: ButtonProps, }: ButtonProps,
ref: Ref<HTMLButtonElement>, ref: Ref<HTMLButtonElement>,
@@ -54,7 +101,7 @@ const Button = forwardRef(
return ( return (
<button <button
type="button" type="button"
className={`${getClassName(variant, danger, disabled)} ${className}`} className={`${getClassName(primary, colorStyle, disabled, fullWidth, small, rounded)} ${className}`}
disabled={disabled} disabled={disabled}
ref={ref} ref={ref}
{...props} {...props}

View File

@@ -18,7 +18,12 @@ const RoundIconButton: FunctionComponent<Props> = ({ onClick, type, className, i
} }
const classes = type === 'primary' ? 'info ' : '' const classes = type === 'primary' ? 'info ' : ''
return ( return (
<button className={`sn-icon-button ${classes} ${className ?? ''}`} onClick={click}> <button
className={`text-neutral min-w-8 h-8 flex justify-center items-center border-solid border border-border bg-clip-padding m-0 bg-transparent cursor-pointer rounded-full hover:text-text focus:text-text hover:bg-contrast focus:bg-contrast focus:outline-none focus:ring-info ${classes} ${
className ?? ''
}`}
onClick={click}
>
<Icon type={iconType} /> <Icon type={iconType} />
</button> </button>
) )

View File

@@ -186,7 +186,7 @@ const ChallengeModal: FunctionComponent<Props> = ({
aria-label="Challenge modal" aria-label="Challenge modal"
className={`challenge-modal flex flex-col items-center bg-default p-8 rounded relative ${ className={`challenge-modal flex flex-col items-center bg-default p-8 rounded relative ${
challenge.reason !== ChallengeReason.ApplicationUnlock challenge.reason !== ChallengeReason.ApplicationUnlock
? 'shadow-overlay-light border-1 border-solid border-main' ? 'shadow-overlay-light border border-solid border-border'
: 'focus:shadow-none' : 'focus:shadow-none'
}`} }`}
> >
@@ -196,7 +196,7 @@ const ChallengeModal: FunctionComponent<Props> = ({
aria-label="Close modal" aria-label="Close modal"
className="flex p-1 bg-transparent border-0 cursor-pointer absolute top-4 right-4" className="flex p-1 bg-transparent border-0 cursor-pointer absolute top-4 right-4"
> >
<Icon type="close" className="color-neutral" /> <Icon type="close" className="text-neutral" />
</button> </button>
)} )}
<ProtectedIllustration className="w-30 h-30 mb-4" /> <ProtectedIllustration className="w-30 h-30 mb-4" />
@@ -224,7 +224,7 @@ const ChallengeModal: FunctionComponent<Props> = ({
/> />
))} ))}
</form> </form>
<Button variant="primary" disabled={isProcessing} className="min-w-76 mt-1 mb-3.5" onClick={submit}> <Button primary disabled={isProcessing} className="min-w-76 mt-1 mb-3.5" onClick={submit}>
{isProcessing ? 'Generating Keys...' : 'Submit'} {isProcessing ? 'Generating Keys...' : 'Submit'}
</Button> </Button>
{shouldShowForgotPasscode && ( {shouldShowForgotPasscode && (
@@ -250,7 +250,7 @@ const ChallengeModal: FunctionComponent<Props> = ({
}) })
}} }}
> >
<Icon type="help" className="mr-2 color-neutral" /> <Icon type="help" className="mr-2 text-neutral" />
Forgot passcode? Forgot passcode?
</Button> </Button>
)} )}

View File

@@ -38,8 +38,8 @@ const ChallengeModalPrompt: FunctionComponent<Props> = ({ prompt, values, index,
return ( return (
<label <label
key={option.label} key={option.label}
className={`cursor-pointer px-2 py-1.5 rounded ${ className={`cursor-pointer px-2 py-1.5 rounded focus-within:ring-2 focus-within:ring-info ${
selected ? 'bg-default color-foreground font-semibold' : 'color-passive-0 hover:bg-passive-3' selected ? 'bg-default text-foreground font-semibold' : 'text-passive-0 hover:bg-passive-3'
}`} }`}
> >
<input <input
@@ -76,7 +76,7 @@ const ChallengeModalPrompt: FunctionComponent<Props> = ({ prompt, values, index,
onChange={(value) => onValueChange(value, prompt)} onChange={(value) => onValueChange(value, prompt)}
/> />
)} )}
{isInvalid && <div className="text-sm color-danger mt-2">Invalid authentication, please try again.</div>} {isInvalid && <div className="text-sm text-danger mt-2">Invalid authentication, please try again.</div>}
</div> </div>
) )
} }

View File

@@ -48,11 +48,15 @@ const LockscreenWorkspaceSwitcher: FunctionComponent<Props> = ({ mainApplication
return ( return (
<div ref={containerRef}> <div ref={containerRef}>
<Button ref={buttonRef} onClick={toggleMenu} className="flex items-center justify-center min-w-76 mt-2"> <Button ref={buttonRef} onClick={toggleMenu} className="flex items-center justify-center min-w-76 mt-2">
<Icon type="user-switch" className="color-neutral mr-2" /> <Icon type="user-switch" className="text-neutral mr-2" />
Switch workspace Switch workspace
</Button> </Button>
{isOpen && ( {isOpen && (
<div ref={menuRef} className="sn-dropdown max-h-120 min-w-68 py-2 fixed overflow-y-auto" style={menuStyle}> <div
ref={menuRef}
className="bg-default rounded-md shadow-main max-h-120 min-w-68 py-2 fixed overflow-y-auto"
style={menuStyle}
>
<WorkspaceSwitcherMenu <WorkspaceSwitcherMenu
mainApplicationGroup={mainApplicationGroup} mainApplicationGroup={mainApplicationGroup}
viewControllerManager={viewControllerManager} viewControllerManager={viewControllerManager}

View File

@@ -72,7 +72,7 @@ const ChangeEditorButton: FunctionComponent<Props> = ({
}} }}
onBlur={closeOnBlur} onBlur={closeOnBlur}
ref={buttonRef} ref={buttonRef}
className="sn-icon-button border-contrast" className="flex justify-center items-center min-w-8 h-8 hover:bg-contrast focus:bg-contrast text-neutral border border-solid border-border rounded-full cursor-pointer"
> >
<VisuallyHidden>Change note type</VisuallyHidden> <VisuallyHidden>Change note type</VisuallyHidden>
<Icon type="dashboard" className="block" /> <Icon type="dashboard" className="block" />
@@ -89,7 +89,7 @@ const ChangeEditorButton: FunctionComponent<Props> = ({
...position, ...position,
maxHeight, maxHeight,
}} }}
className="sn-dropdown sn-dropdown--animated min-w-68 max-h-120 max-w-xs flex flex-col overflow-y-auto fixed" className="bg-default rounded shadow-main transition-transform duration-150 slide-down-animation min-w-68 max-h-120 max-w-xs flex flex-col overflow-y-auto fixed"
onBlur={closeOnBlur} onBlur={closeOnBlur}
> >
{isOpen && ( {isOpen && (

View File

@@ -183,7 +183,7 @@ const ChangeEditorMenu: FunctionComponent<ChangeEditorMenuProps> = ({
return ( return (
<Fragment key={groupId}> <Fragment key={groupId}>
<div className={`py-1 border-0 border-t-1px border-solid border-main ${index === 0 ? 'border-t-0' : ''}`}> <div className={`py-1 border-0 border-t border-solid border-border ${index === 0 ? 'border-t-0' : ''}`}>
{group.items.map((item) => { {group.items.map((item) => {
const onClickEditorItem = () => { const onClickEditorItem = () => {
selectEditor(item).catch(console.error) selectEditor(item).catch(console.error)
@@ -193,11 +193,9 @@ const ChangeEditorMenu: FunctionComponent<ChangeEditorMenuProps> = ({
key={item.name} key={item.name}
type={MenuItemType.RadioButton} type={MenuItemType.RadioButton}
onClick={onClickEditorItem} onClick={onClickEditorItem}
className={ className={'py-2 flex-row-reverse'}
'sn-dropdown-item py-2 text-input focus:bg-info-backdrop focus:shadow-none flex-row-reverse'
}
onBlur={closeOnBlur} onBlur={closeOnBlur}
checked={isSelectedEditor(item)} checked={item.isEntitled ? isSelectedEditor(item) : undefined}
> >
<div className="flex flex-grow items-center justify-between"> <div className="flex flex-grow items-center justify-between">
<div className="flex items-center"> <div className="flex items-center">

View File

@@ -75,49 +75,49 @@ export const createEditorMenuGroups = (application: WebApplication, editors: SNC
const editorMenuGroups: EditorMenuGroup[] = [ const editorMenuGroups: EditorMenuGroup[] = [
{ {
icon: 'plain-text', icon: 'plain-text',
iconClassName: 'color-accessory-tint-1', iconClassName: 'text-accessory-tint-1',
title: 'Plain text', title: 'Plain text',
items: editorItems.plain, items: editorItems.plain,
}, },
{ {
icon: 'rich-text', icon: 'rich-text',
iconClassName: 'color-accessory-tint-1', iconClassName: 'text-accessory-tint-1',
title: 'Rich text', title: 'Rich text',
items: editorItems['rich-text'], items: editorItems['rich-text'],
}, },
{ {
icon: 'markdown', icon: 'markdown',
iconClassName: 'color-accessory-tint-2', iconClassName: 'text-accessory-tint-2',
title: 'Markdown text', title: 'Markdown text',
items: editorItems.markdown, items: editorItems.markdown,
}, },
{ {
icon: 'tasks', icon: 'tasks',
iconClassName: 'color-accessory-tint-3', iconClassName: 'text-accessory-tint-3',
title: 'Todo', title: 'Todo',
items: editorItems.task, items: editorItems.task,
}, },
{ {
icon: 'code', icon: 'code',
iconClassName: 'color-accessory-tint-4', iconClassName: 'text-accessory-tint-4',
title: 'Code', title: 'Code',
items: editorItems.code, items: editorItems.code,
}, },
{ {
icon: 'spreadsheets', icon: 'spreadsheets',
iconClassName: 'color-accessory-tint-5', iconClassName: 'text-accessory-tint-5',
title: 'Spreadsheet', title: 'Spreadsheet',
items: editorItems.spreadsheet, items: editorItems.spreadsheet,
}, },
{ {
icon: 'authenticator', icon: 'authenticator',
iconClassName: 'color-accessory-tint-6', iconClassName: 'text-accessory-tint-6',
title: 'Authentication', title: 'Authentication',
items: editorItems.authentication, items: editorItems.authentication,
}, },
{ {
icon: 'editor', icon: 'editor',
iconClassName: 'color-neutral', iconClassName: 'text-neutral',
title: 'Others', title: 'Others',
items: editorItems.others, items: editorItems.others,
}, },

View File

@@ -10,7 +10,7 @@ type CheckboxProps = {
const Checkbox: FunctionComponent<CheckboxProps> = ({ name, checked, onChange, disabled, label }) => { const Checkbox: FunctionComponent<CheckboxProps> = ({ name, checked, onChange, disabled, label }) => {
return ( return (
<label htmlFor={name} className="flex items-center fit-content mb-2"> <label htmlFor={name} className="flex items-center fit-content mb-2 text-sm">
<input <input
className="mr-2" className="mr-2"
type="checkbox" type="checkbox"

View File

@@ -1,4 +1,5 @@
import { FunctionComponent } from 'react' import { FunctionComponent } from 'react'
import Button from '@/Components/Button/Button'
type Props = { type Props = {
deprecationMessage: string | undefined deprecationMessage: string | undefined
@@ -8,16 +9,18 @@ type Props = {
const IsDeprecated: FunctionComponent<Props> = ({ deprecationMessage, dismissDeprecationMessage }) => { const IsDeprecated: FunctionComponent<Props> = ({ deprecationMessage, dismissDeprecationMessage }) => {
return ( return (
<div className={'sn-component'}> <div className={'sn-component'}>
<div className={'sk-app-bar no-edges no-top-edge dynamic-height'}> <div className="flex justify-between items-center w-full min-h-[1.625rem] py-2.5 px-2 bg-contrast text-text border-b border-border select-none">
<div className={'left'}> <div className={'left'}>
<div className={'sk-app-bar-item'}> <div className={'sk-app-bar-item'}>
<div className={'sk-label warning'}>{deprecationMessage || 'This extension is deprecated.'}</div> <div className="font-bold text-xs text-warning">
{deprecationMessage || 'This extension is deprecated.'}
</div>
</div> </div>
</div> </div>
<div className={'right'}> <div className={'right'}>
<div className={'sk-app-bar-item'} onClick={dismissDeprecationMessage}> <Button primary onClick={dismissDeprecationMessage} small>
<button className={'sn-button small info'}>Dismiss</button> Dismiss
</div> </Button>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,5 +1,7 @@
import { FeatureStatus } from '@standardnotes/snjs' import { FeatureStatus } from '@standardnotes/snjs'
import { FunctionComponent } from 'react' import { FunctionComponent } from 'react'
import Button from '@/Components/Button/Button'
import IndicatorCircle from '../IndicatorCircle/IndicatorCircle'
type Props = { type Props = {
expiredDate: string expiredDate: string
@@ -24,24 +26,20 @@ const statusString = (featureStatus: FeatureStatus, expiredDate: string, compone
const IsExpired: FunctionComponent<Props> = ({ expiredDate, featureStatus, componentName, manageSubscription }) => { const IsExpired: FunctionComponent<Props> = ({ expiredDate, featureStatus, componentName, manageSubscription }) => {
return ( return (
<div className={'sn-component'}> <div className={'sn-component'}>
<div className={'sk-app-bar no-edges no-top-edge dynamic-height'}> <div className="flex justify-between items-center w-full min-h-[1.625rem] py-2.5 px-2 bg-contrast text-text border-b border-border select-none">
<div className={'left'}> <div className={'left'}>
<div className={'sk-app-bar-item'}> <div className="flex items-center">
<div className={'sk-app-bar-item-column'}> <IndicatorCircle style="danger" />
<div className={'sk-circle danger small'} /> <div className="ml-2">
</div> <strong>{statusString(featureStatus, expiredDate, componentName)}</strong>
<div className={'sk-app-bar-item-column'}> <div className={'sk-p'}>{componentName} is in a read-only state.</div>
<div>
<strong>{statusString(featureStatus, expiredDate, componentName)}</strong>
<div className={'sk-p'}>{componentName} is in a read-only state.</div>
</div>
</div> </div>
</div> </div>
</div> </div>
<div className={'right'}> <div className={'right'}>
<div className={'sk-app-bar-item'} onClick={() => manageSubscription()}> <Button onClick={manageSubscription} primary colorStyle="success" small>
<button className={'sn-button small success'}>Manage Subscription</button> Manage subscription
</div> </Button>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,4 +1,5 @@
import { FunctionComponent } from 'react' import { FunctionComponent } from 'react'
import Button from '@/Components/Button/Button'
type Props = { type Props = {
componentName: string componentName: string
@@ -8,16 +9,16 @@ type Props = {
const IssueOnLoading: FunctionComponent<Props> = ({ componentName, reloadIframe }) => { const IssueOnLoading: FunctionComponent<Props> = ({ componentName, reloadIframe }) => {
return ( return (
<div className={'sn-component'}> <div className={'sn-component'}>
<div className={'sk-app-bar no-edges no-top-edge dynamic-height'}> <div className="flex justify-between items-center w-full min-h-[1.625rem] py-2.5 px-2 bg-contrast text-text border-b border-border select-none">
<div className={'left'}> <div className={'left'}>
<div className={'sk-app-bar-item'}> <div className={'sk-app-bar-item'}>
<div className={'sk-label.warning'}>There was an issue loading {componentName}.</div> <div className={'sk-label.warning'}>There was an issue loading {componentName}.</div>
</div> </div>
</div> </div>
<div className={'right'}> <div className={'right'}>
<div className={'sk-app-bar-item'} onClick={reloadIframe}> <Button primary onClick={reloadIframe} small>
<button className={'sn-button small info'}>Reload</button> Reload
</div> </Button>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -7,14 +7,14 @@ const OfflineRestricted: FunctionComponent = () => {
<div className={'sk-panel-content'}> <div className={'sk-panel-content'}>
<div className={'sk-panel-section stretch'}> <div className={'sk-panel-section stretch'}>
<div className={'sk-panel-column'} /> <div className={'sk-panel-column'} />
<div className={'sk-h1 sk-bold'}>You have restricted this component to not use a hosted version.</div> <div className="font-bold text-base">You have restricted this component to not use a hosted version.</div>
<div className={'sk-subtitle'}>Locally-installed components are not available in the web application.</div> <div className={'sk-subtitle'}>Locally-installed components are not available in the web application.</div>
<div className={'sk-panel-row'} /> <div className={'sk-panel-row'} />
<div className={'sk-panel-row'}> <div className={'sk-panel-row'}>
<div className={'sk-panel-column'}> <div className={'sk-panel-column'}>
<div className={'sk-p'}>To continue, choose from the following options:</div> <div className={'sk-p'}>To continue, choose from the following options:</div>
<ul> <ul className="list-disc pl-8 mt-3">
<li className={'sk-p'}> <li className="sk-p mb-1">
Enable the Hosted option for this component by opening the Preferences {'>'} General {'>'} Advanced Enable the Hosted option for this component by opening the Preferences {'>'} General {'>'} Advanced
Settings menu and toggling 'Use hosted when local is unavailable' under this component's options. Settings menu and toggling 'Use hosted when local is unavailable' under this component's options.
Then press Reload. Then press Reload.

View File

@@ -6,6 +6,7 @@ import { ViewControllerManager } from '@/Services/ViewControllerManager'
import { observer } from 'mobx-react-lite' import { observer } from 'mobx-react-lite'
import { ApplicationGroup } from '@/Application/ApplicationGroup' import { ApplicationGroup } from '@/Application/ApplicationGroup'
import { isDesktopApplication } from '@/Utils' import { isDesktopApplication } from '@/Utils'
import Button from '@/Components/Button/Button'
type Props = { type Props = {
application: WebApplication application: WebApplication
@@ -31,7 +32,7 @@ const ConfirmSignoutModal: FunctionComponent<Props> = ({ application, viewContro
const showWorkspaceWarning = workspaces.length > 1 && isDesktopApplication() const showWorkspaceWarning = workspaces.length > 1 && isDesktopApplication()
return ( return (
<AlertDialog onDismiss={closeDialog} leastDestructiveRef={cancelRef}> <AlertDialog onDismiss={closeDialog} leastDestructiveRef={cancelRef} className="p-0 max-w-[600px]">
<div className="sk-modal-content"> <div className="sk-modal-content">
<div className="sn-component"> <div className="sn-component">
<div className="sk-panel"> <div className="sk-panel">
@@ -40,11 +41,11 @@ const ConfirmSignoutModal: FunctionComponent<Props> = ({ application, viewContro
<AlertDialogLabel className="sk-h3 sk-panel-section-title">Sign out workspace?</AlertDialogLabel> <AlertDialogLabel className="sk-h3 sk-panel-section-title">Sign out workspace?</AlertDialogLabel>
<AlertDialogDescription className="sk-panel-row"> <AlertDialogDescription className="sk-panel-row">
<div> <div>
<p className="color-foreground">{STRING_SIGN_OUT_CONFIRMATION}</p> <p className="text-foreground">{STRING_SIGN_OUT_CONFIRMATION}</p>
{showWorkspaceWarning && ( {showWorkspaceWarning && (
<> <>
<br /> <br />
<p className="color-foreground"> <p className="text-foreground">
<strong>Note: </strong> <strong>Note: </strong>
Because you have other workspaces signed in, this sign out may leave logs and other metadata Because you have other workspaces signed in, this sign out may leave logs and other metadata
of your session on this device. For a more robust sign out that performs a hard clear of all of your session on this device. For a more robust sign out that performs a hard clear of all
@@ -82,12 +83,15 @@ const ConfirmSignoutModal: FunctionComponent<Props> = ({ application, viewContro
</div> </div>
)} )}
<div className="flex my-1 mt-4"> <div className="flex my-1 mt-4 gap-2">
<button className="sn-button small neutral" ref={cancelRef} onClick={closeDialog}> <Button primary small colorStyle="neutral" rounded={false} ref={cancelRef} onClick={closeDialog}>
Cancel Cancel
</button> </Button>
<button <Button
className="sn-button small danger ml-2" primary
small
colorStyle="danger"
rounded={false}
onClick={() => { onClick={() => {
if (deleteLocalBackups) { if (deleteLocalBackups) {
application.signOutAndDeleteLocalBackups().catch(console.error) application.signOutAndDeleteLocalBackups().catch(console.error)
@@ -98,7 +102,7 @@ const ConfirmSignoutModal: FunctionComponent<Props> = ({ application, viewContro
}} }}
> >
{application.hasAccount() ? 'Sign Out' : 'Delete Workspace'} {application.hasAccount() ? 'Sign Out' : 'Delete Workspace'}
</button> </Button>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -66,7 +66,7 @@ const ContentList: FunctionComponent<Props> = ({
return ( return (
<div <div
className="infinite-scroll border-solid border-0 border-t-1px border-main focus:shadow-none focus:outline-none" className="infinite-scroll border-solid border-t border-border focus:shadow-none focus:outline-none"
id={ElementIds.ContentList} id={ElementIds.ContentList}
onScroll={onScroll} onScroll={onScroll}
onKeyDown={onKeyDown} onKeyDown={onKeyDown}

View File

@@ -255,8 +255,8 @@ const ContentListView: FunctionComponent<Props> = ({
/> />
</div> </div>
</div> </div>
{completedFullSync && !renderedItems.length ? <p className="empty-items-list faded">No items.</p> : null} {completedFullSync && !renderedItems.length ? <p className="empty-items-list opacity-50">No items.</p> : null}
{!completedFullSync && !renderedItems.length ? <p className="empty-items-list faded">Loading...</p> : null} {!completedFullSync && !renderedItems.length ? <p className="empty-items-list opacity-50">Loading...</p> : null}
{renderedItems.length ? ( {renderedItems.length ? (
<ContentList <ContentList
items={renderedItems} items={renderedItems}

View File

@@ -53,8 +53,8 @@ const FileListItem: FunctionComponent<DisplayableListItemProps> = ({
return ( return (
<div <div
className={`content-list-item flex items-stretch w-full cursor-pointer ${ className={`content-list-item flex items-stretch w-full cursor-pointer text-text ${
selected && 'selected border-0 border-l-2px border-solid border-info' selected && 'selected border-l-2px border-solid border-info'
}`} }`}
id={item.uuid} id={item.uuid}
onClick={onClick} onClick={onClick}
@@ -70,8 +70,8 @@ const FileListItem: FunctionComponent<DisplayableListItemProps> = ({
) : ( ) : (
<div className="pr-4" /> <div className="pr-4" />
)} )}
<div className="flex-grow min-w-0 py-4 px-0 border-0 border-b-1 border-solid border-main"> <div className="flex-grow min-w-0 py-4 px-0 border-b border-solid border-border">
<div className="flex items-start justify-between font-semibold text-base leading-1.3 overflow-hidden"> <div className="flex items-start justify-between font-semibold text-base leading-[1.3] overflow-hidden">
<div className="break-word mr-2">{item.title}</div> <div className="break-word mr-2">{item.title}</div>
</div> </div>
<ListItemMetadata item={item} hideDate={hideDate} sortBy={sortBy} /> <ListItemMetadata item={item} hideDate={hideDate} sortBy={sortBy} />

View File

@@ -45,16 +45,16 @@ const ContentListHeader = ({
}, []) }, [])
return ( return (
<div className="section-title-bar-header"> <div className="section-title-bar-header gap-1">
<div className="flex flex-col"> <div className="flex flex-col flex-grow">
<div className="text-lg font-semibold title">{panelTitle}</div> <div className="text-lg font-semibold text-text">{panelTitle}</div>
{optionsSubtitle && <div className="text-xs color-passive-0">{optionsSubtitle}</div>} {optionsSubtitle && <div className="text-xs text-passive-0">{optionsSubtitle}</div>}
</div> </div>
<div className="flex"> <div className="flex">
<div className="relative" ref={displayOptionsContainerRef}> <div className="relative" ref={displayOptionsContainerRef}>
<Disclosure open={showDisplayOptionsMenu} onChange={toggleDisplayOptionsMenu}> <Disclosure open={showDisplayOptionsMenu} onChange={toggleDisplayOptionsMenu}>
<StyledDisplayOptionsButton pressed={showDisplayOptionsMenu} ref={displayOptionsButtonRef}> <StyledDisplayOptionsButton $pressed={showDisplayOptionsMenu} ref={displayOptionsButtonRef}>
<Icon type="sort-descending" className="w-5 h-5" /> <Icon type="sort-descending" />
</StyledDisplayOptionsButton> </StyledDisplayOptionsButton>
<DisclosurePanel> <DisclosurePanel>
{showDisplayOptionsMenu && displayOptionsMenuPosition && ( {showDisplayOptionsMenu && displayOptionsMenuPosition && (
@@ -72,12 +72,12 @@ const ContentListHeader = ({
</Disclosure> </Disclosure>
</div> </div>
<button <button
className="flex justify-center items-center min-w-8 h-8 ml-3 bg-info hover:brightness-130 color-info-contrast border-1 border-solid border-transparent rounded-full cursor-pointer" className="flex justify-center items-center min-w-8 h-8 ml-3 bg-info hover:brightness-125 text-info-contrast border border-solid border-transparent rounded-full cursor-pointer"
title={addButtonLabel} title={addButtonLabel}
aria-label={addButtonLabel} aria-label={addButtonLabel}
onClick={addNewItem} onClick={addNewItem}
> >
<Icon type="add" className="w-5 h-5" /> <Icon type="add" />
</button> </button>
</div> </div>
</div> </div>

View File

@@ -99,15 +99,15 @@ const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
return ( return (
<Menu <Menu
className={ className={
'py-1 sn-dropdown sn-dropdown--animated min-w-70 overflow-y-auto \ 'py-1 bg-default rounded shadow-main transition-transform duration-150 slide-down-animation min-w-70 overflow-y-auto \
border-1 border-solid border-main text-sm z-index-dropdown-menu \ border border-solid border-border text-sm z-index-dropdown-menu \
flex flex-col' flex flex-col'
} }
a11yLabel="Notes list options menu" a11yLabel="Notes list options menu"
closeMenu={closeDisplayOptionsMenu} closeMenu={closeDisplayOptionsMenu}
isOpen={isOpen} isOpen={isOpen}
> >
<div className="px-3 my-1 text-xs font-semibold color-text uppercase">Sort by</div> <div className="px-3 my-1 text-xs font-semibold text-text uppercase">Sort by</div>
<MenuItem <MenuItem
className="py-2" className="py-2"
type={MenuItemType.RadioButton} type={MenuItemType.RadioButton}
@@ -118,9 +118,9 @@ const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
<span>Date modified</span> <span>Date modified</span>
{sortBy === CollectionSort.UpdatedAt ? ( {sortBy === CollectionSort.UpdatedAt ? (
sortReverse ? ( sortReverse ? (
<Icon type="arrows-sort-up" className="color-neutral" /> <Icon type="arrows-sort-up" className="text-neutral" />
) : ( ) : (
<Icon type="arrows-sort-down" className="color-neutral" /> <Icon type="arrows-sort-down" className="text-neutral" />
) )
) : null} ) : null}
</div> </div>
@@ -135,9 +135,9 @@ const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
<span>Creation date</span> <span>Creation date</span>
{sortBy === CollectionSort.CreatedAt ? ( {sortBy === CollectionSort.CreatedAt ? (
sortReverse ? ( sortReverse ? (
<Icon type="arrows-sort-up" className="color-neutral" /> <Icon type="arrows-sort-up" className="text-neutral" />
) : ( ) : (
<Icon type="arrows-sort-down" className="color-neutral" /> <Icon type="arrows-sort-down" className="text-neutral" />
) )
) : null} ) : null}
</div> </div>
@@ -152,15 +152,15 @@ const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
<span>Title</span> <span>Title</span>
{sortBy === CollectionSort.Title ? ( {sortBy === CollectionSort.Title ? (
sortReverse ? ( sortReverse ? (
<Icon type="arrows-sort-up" className="color-neutral" /> <Icon type="arrows-sort-up" className="text-neutral" />
) : ( ) : (
<Icon type="arrows-sort-down" className="color-neutral" /> <Icon type="arrows-sort-down" className="text-neutral" />
) )
) : null} ) : null}
</div> </div>
</MenuItem> </MenuItem>
<MenuItemSeparator /> <MenuItemSeparator />
<div className="px-3 py-1 text-xs font-semibold color-text uppercase">View</div> <div className="px-3 py-1 text-xs font-semibold text-text uppercase">View</div>
{!isFilesSmartView && ( {!isFilesSmartView && (
<MenuItem <MenuItem
type={MenuItemType.SwitchButton} type={MenuItemType.SwitchButton}
@@ -195,8 +195,8 @@ const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
> >
Show icon Show icon
</MenuItem> </MenuItem>
<div className="h-1px my-2 bg-border"></div> <MenuItemSeparator />
<div className="px-3 py-1 text-xs font-semibold color-text uppercase">Other</div> <div className="px-3 py-1 text-xs font-semibold text-text uppercase">Other</div>
<MenuItem <MenuItem
type={MenuItemType.SwitchButton} type={MenuItemType.SwitchButton}
className="py-1 hover:bg-contrast focus:bg-info-backdrop" className="py-1 hover:bg-contrast focus:bg-info-backdrop"

View File

@@ -3,11 +3,11 @@ import styled from 'styled-components'
const StyledDisplayOptionsButton = styled(DisclosureButton).attrs(() => ({ const StyledDisplayOptionsButton = styled(DisclosureButton).attrs(() => ({
className: className:
'flex justify-center items-center min-w-8 h-8 bg-color-padding hover:bg-contrast focus:bg-contrast color-neutral border-1 border-solid border-main rounded-full cursor-pointer', 'flex justify-center items-center min-w-8 h-8 bg-text-padding hover:bg-contrast focus:bg-contrast text-neutral border border-solid border-border rounded-full cursor-pointer',
}))<{ }))<{
pressed: boolean $pressed: boolean
}>` }>`
background-color: ${(props) => (props.pressed ? 'var(--sn-stylekit-contrast-background-color)' : 'transparent')}; background-color: ${(props) => (props.$pressed ? 'var(--sn-stylekit-contrast-background-color)' : 'transparent')};
` `
export default StyledDisplayOptionsButton export default StyledDisplayOptionsButton

View File

@@ -10,7 +10,7 @@ type Props = {
const ListItemConflictIndicator: FunctionComponent<Props> = ({ item }) => { const ListItemConflictIndicator: FunctionComponent<Props> = ({ item }) => {
return item.conflictOf ? ( return item.conflictOf ? (
<div className="flex flex-wrap items-center mt-0.5"> <div className="flex flex-wrap items-center mt-0.5">
<div className={'py-1 px-1.5 rounded mr-1 mt-2 bg-danger color-danger-contrast'}> <div className={'py-1 px-1.5 rounded mr-1 mt-2 bg-danger text-danger-contrast'}>
<div className="text-xs font-bold text-center">Conflicted Copy</div> <div className="text-xs font-bold text-center">Conflicted Copy</div>
</div> </div>
</div> </div>

View File

@@ -14,30 +14,30 @@ type Props = {
const ListItemFlagIcons: FunctionComponent<Props> = ({ item, hasFiles = false }) => { const ListItemFlagIcons: FunctionComponent<Props> = ({ item, hasFiles = false }) => {
return ( return (
<div className="flex items-start p-4 pl-0 border-0 border-b-1 border-solid border-main"> <div className="flex items-start p-4 pl-0 border-b border-solid border-border">
{item.locked && ( {item.locked && (
<span className="flex items-center" title="Editing Disabled"> <span className="flex items-center" title="Editing Disabled">
<Icon ariaLabel="Editing Disabled" type="pencil-off" className="sn-icon--small color-info" /> <Icon ariaLabel="Editing Disabled" type="pencil-off" className="text-info" size="small" />
</span> </span>
)} )}
{item.trashed && ( {item.trashed && (
<span className="flex items-center ml-1.5" title="Trashed"> <span className="flex items-center ml-1.5" title="Trashed">
<Icon ariaLabel="Trashed" type="trash-filled" className="sn-icon--small color-danger" /> <Icon ariaLabel="Trashed" type="trash-filled" className="text-danger" size="small" />
</span> </span>
)} )}
{item.archived && ( {item.archived && (
<span className="flex items-center ml-1.5" title="Archived"> <span className="flex items-center ml-1.5" title="Archived">
<Icon ariaLabel="Archived" type="archive" className="sn-icon--mid color-accessory-tint-3" /> <Icon ariaLabel="Archived" type="archive" className="text-accessory-tint-3" size="medium" />
</span> </span>
)} )}
{item.pinned && ( {item.pinned && (
<span className="flex items-center ml-1.5" title="Pinned"> <span className="flex items-center ml-1.5" title="Pinned">
<Icon ariaLabel="Pinned" type="pin-filled" className="sn-icon--small color-info" /> <Icon ariaLabel="Pinned" type="pin-filled" className="text-info" size="small" />
</span> </span>
)} )}
{hasFiles && ( {hasFiles && (
<span className="flex items-center ml-1.5" title="Files"> <span className="flex items-center ml-1.5" title="Files">
<Icon ariaLabel="Files" type="attachment-file" className="sn-icon--small color-info" /> <Icon ariaLabel="Files" type="attachment-file" className="text-info" size="small" />
</span> </span>
)} )}
</div> </div>

View File

@@ -20,7 +20,7 @@ const ListItemMetadata: FunctionComponent<Props> = ({ item, hideDate, sortBy })
} }
return ( return (
<div className="text-xs leading-1.4 mt-1 faded"> <div className="text-xs leading-1.4 mt-1 opacity-50">
{item.protected && <span>Protected {hideDate ? '' : ' • '}</span>} {item.protected && <span>Protected {hideDate ? '' : ' • '}</span>}
{!hideDate && showModifiedDate && <span>Modified {item.updatedAtString || 'Now'}</span>} {!hideDate && showModifiedDate && <span>Modified {item.updatedAtString || 'Now'}</span>}
{!hideDate && !showModifiedDate && <span>{item.createdAtString || 'Now'}</span>} {!hideDate && !showModifiedDate && <span>{item.createdAtString || 'Now'}</span>}

View File

@@ -16,10 +16,10 @@ const ListItemTags: FunctionComponent<Props> = ({ hideTags, tags }) => {
<div className="flex flex-wrap mt-1.5 text-xs gap-2"> <div className="flex flex-wrap mt-1.5 text-xs gap-2">
{tags.map((tag) => ( {tags.map((tag) => (
<span <span
className="inline-flex items-center py-1 px-1.5 bg-passive-4-opacity-variant color-foreground rounded-0.5" className="inline-flex items-center py-1 px-1.5 bg-passive-4-opacity-variant text-foreground rounded-sm"
key={tag.uuid} key={tag.uuid}
> >
<Icon type="hashtag" className="sn-icon--small color-passive-1 mr-1" /> <Icon type="hashtag" className="text-passive-1 mr-1" size="small" />
<span>{tag.title}</span> <span>{tag.title}</span>
</span> </span>
))} ))}

View File

@@ -45,8 +45,8 @@ const NoteListItem: FunctionComponent<DisplayableListItemProps> = ({
return ( return (
<div <div
className={`content-list-item flex items-stretch w-full cursor-pointer ${ className={`content-list-item flex items-stretch w-full cursor-pointer text-text ${
selected && 'selected border-0 border-l-2px border-solid border-info' selected && 'selected border-l-2 border-solid border-info'
}`} }`}
id={item.uuid} id={item.uuid}
onClick={() => { onClick={() => {
@@ -58,14 +58,14 @@ const NoteListItem: FunctionComponent<DisplayableListItemProps> = ({
}} }}
> >
{!hideIcon ? ( {!hideIcon ? (
<div className="flex flex-col items-center justify-between p-4 pr-3 mr-0"> <div className="flex flex-col items-center justify-between p-4 pr-4 mr-0">
<Icon ariaLabel={`Icon for ${editorName}`} type={icon} className={`color-accessory-tint-${tint}`} /> <Icon ariaLabel={`Icon for ${editorName}`} type={icon} className={`text-accessory-tint-${tint}`} />
</div> </div>
) : ( ) : (
<div className="pr-4" /> <div className="pr-4" />
)} )}
<div className="flex-grow min-w-0 py-4 px-0 border-0 border-b-1 border-solid border-main"> <div className="flex-grow min-w-0 py-4 px-0 border-b border-solid border-border">
<div className="flex items-start justify-between font-semibold text-base leading-1.3 overflow-hidden"> <div className="flex items-start justify-between font-semibold text-base leading-[1.3] overflow-hidden">
<div className="break-word mr-2">{item.title}</div> <div className="break-word mr-2">{item.title}</div>
</div> </div>
{!hidePreview && !item.hidePreview && !item.protected && ( {!hidePreview && !item.hidePreview && !item.protected && (

View File

@@ -1,9 +1,11 @@
import { ListboxArrow, ListboxButton, ListboxInput, ListboxList, ListboxOption, ListboxPopover } from '@reach/listbox' import { ListboxArrow, ListboxInput, ListboxList, ListboxPopover } from '@reach/listbox'
import '@reach/listbox/styles.css' import '@reach/listbox/styles.css'
import VisuallyHidden from '@reach/visually-hidden' import VisuallyHidden from '@reach/visually-hidden'
import { FunctionComponent } from 'react' import { FunctionComponent } from 'react'
import Icon from '@/Components/Icon/Icon' import Icon from '@/Components/Icon/Icon'
import { DropdownItem } from './DropdownItem' import { DropdownItem } from './DropdownItem'
import StyledListboxButton from './StyledListboxButton'
import StyledListboxOption from './StyledListboxOption'
type DropdownProps = { type DropdownProps = {
id: string id: string
@@ -25,16 +27,16 @@ const CustomDropdownButton: FunctionComponent<ListboxButtonProps> = ({
iconClassName = '', iconClassName = '',
}) => ( }) => (
<> <>
<div className="sn-dropdown-button-label"> <div className="flex items-center">
{icon ? ( {icon ? (
<div className="flex mr-2"> <div className="flex mr-2">
<Icon type={icon} className={`sn-icon--small ${iconClassName}`} /> <Icon type={icon} className={iconClassName} size="small" />
</div> </div>
) : null} ) : null}
<div className="dropdown-selected-label">{label}</div> <div className="dropdown-selected-label">{label}</div>
</div> </div>
<ListboxArrow className={`sn-dropdown-arrow ${isExpanded ? 'sn-dropdown-arrow-flipped' : ''}`}> <ListboxArrow className={`flex ${isExpanded ? 'rotate-180' : ''}`}>
<Icon type="menu-arrow-down" className="sn-icon--small color-passive-1" /> <Icon type="menu-arrow-down" className="text-passive-1" size="small" />
</ListboxArrow> </ListboxArrow>
</> </>
) )
@@ -52,8 +54,7 @@ const Dropdown: FunctionComponent<DropdownProps> = ({ id, label, items, value, o
<> <>
<VisuallyHidden id={labelId}>{label}</VisuallyHidden> <VisuallyHidden id={labelId}>{label}</VisuallyHidden>
<ListboxInput value={value} onChange={handleChange} aria-labelledby={labelId} disabled={disabled}> <ListboxInput value={value} onChange={handleChange} aria-labelledby={labelId} disabled={disabled}>
<ListboxButton <StyledListboxButton
className="sn-dropdown-button"
children={({ value, label, isExpanded }) => { children={({ value, label, isExpanded }) => {
const current = items.find((item) => item.value === value) const current = items.find((item) => item.value === value)
const icon = current ? current?.icon : null const icon = current ? current?.icon : null
@@ -71,20 +72,14 @@ const Dropdown: FunctionComponent<DropdownProps> = ({ id, label, items, value, o
<div className="sn-component"> <div className="sn-component">
<ListboxList> <ListboxList>
{items.map((item) => ( {items.map((item) => (
<ListboxOption <StyledListboxOption key={item.value} value={item.value} label={item.label} disabled={item.disabled}>
key={item.value}
className="sn-dropdown-item"
value={item.value}
label={item.label}
disabled={item.disabled}
>
{item.icon ? ( {item.icon ? (
<div className="flex mr-3"> <div className="flex mr-3">
<Icon type={item.icon} className={`sn-icon--small ${item.iconClassName ?? ''}`} /> <Icon type={item.icon} className={item.iconClassName ?? ''} size="small" />
</div> </div>
) : null} ) : null}
<div className="text-input">{item.label}</div> <div className="text-input">{item.label}</div>
</ListboxOption> </StyledListboxOption>
))} ))}
</ListboxList> </ListboxList>
</div> </div>

View File

@@ -0,0 +1,21 @@
import { ListboxButton } from '@reach/listbox'
import styled from 'styled-components'
const StyledListboxButton = styled(ListboxButton)`
&[data-reach-listbox-button] {
background-color: var(--sn-stylekit-background-color);
border-radius: 0.25rem;
border: 1px solid var(--sn-stylekit-border-color);
color: var(--sn-stylekit-contrast-foreground-color);
font-size: 0.875rem;
line-height: 1.25rem;
min-width: 13.75rem;
padding-bottom: 0.375rem;
padding-left: 0.875rem;
padding-right: 0.875rem;
padding-top: 0.375rem;
width: fit-content;
}
`
export default StyledListboxButton

View File

@@ -0,0 +1,38 @@
import { ListboxOption } from '@reach/listbox'
import styled from 'styled-components'
const StyledListboxOption = styled(ListboxOption)`
&[data-reach-listbox-option] {
align-items: center;
background-color: transparent;
border: none;
color: var(--sn-stylekit-contrast-foreground-color);
cursor: pointer;
display: flex;
font-size: 0.875rem;
padding-bottom: 0.375rem;
padding-left: 0.75rem;
padding-right: 0.75rem;
padding-top: 0.375rem;
text-align: left;
width: 100%;
&[data-current-selected] {
color: var(--sn-stylekit-info-color);
background-color: var(--sn-stylekit-info-backdrop-color);
}
&:hover {
background-color: var(--sn-stylekit-contrast-background-color);
color: var(--sn-stylekit-foreground-color);
}
&:focus {
background-color: var(--sn-stylekit-info-backdrop-color);
box-shadow: none;
outline: none;
}
}
`
export default StyledListboxOption

View File

@@ -86,7 +86,7 @@ const FileContextMenu: FunctionComponent<Props> = observer(({ filesController, s
return ( return (
<div <div
ref={contextMenuRef} ref={contextMenuRef}
className="sn-dropdown min-w-60 max-h-120 max-w-xs flex flex-col py-2 overflow-y-auto fixed" className="bg-default rounded shadow-main min-w-60 max-h-120 max-w-xs flex flex-col py-2 overflow-y-auto fixed"
style={{ style={{
...contextMenuStyle, ...contextMenuStyle,
maxHeight: contextMenuMaxHeight, maxHeight: contextMenuMaxHeight,

View File

@@ -6,6 +6,7 @@ import Switch from '@/Components/Switch/Switch'
import { observer } from 'mobx-react-lite' import { observer } from 'mobx-react-lite'
import { FilesController } from '@/Controllers/FilesController' import { FilesController } from '@/Controllers/FilesController'
import { SelectedItemsController } from '@/Controllers/SelectedItemsController' import { SelectedItemsController } from '@/Controllers/SelectedItemsController'
import HorizontalSeparator from '../Shared/HorizontalSeparator'
type Props = { type Props = {
closeMenu: () => void closeMenu: () => void
@@ -64,35 +65,47 @@ const FileMenuOptions: FunctionComponent<Props> = ({
return ( return (
<> <>
<button onBlur={closeOnBlur} className="sn-dropdown-item focus:bg-info-backdrop" onClick={onPreview}> <button
<Icon type="file" className="mr-2 color-neutral" /> onBlur={closeOnBlur}
className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full focus:bg-info-backdrop focus:shadow-none text-sm"
onClick={onPreview}
>
<Icon type="file" className="mr-2 text-neutral" />
Preview file Preview file
</button> </button>
{selectedFiles.length === 1 && ( {selectedFiles.length === 1 && (
<> <>
{isFileAttachedToNote ? ( {isFileAttachedToNote ? (
<button onBlur={closeOnBlur} className="sn-dropdown-item focus:bg-info-backdrop" onClick={onDetach}> <button
<Icon type="link-off" className="mr-2 color-neutral" /> onBlur={closeOnBlur}
className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full focus:bg-info-backdrop focus:shadow-none text-sm"
onClick={onDetach}
>
<Icon type="link-off" className="mr-2 text-neutral" />
Detach from note Detach from note
</button> </button>
) : shouldShowAttachOption ? ( ) : shouldShowAttachOption ? (
<button onBlur={closeOnBlur} className="sn-dropdown-item focus:bg-info-backdrop" onClick={onAttach}> <button
<Icon type="link" className="mr-2 color-neutral" /> onBlur={closeOnBlur}
className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full focus:bg-info-backdrop focus:shadow-none text-sm"
onClick={onAttach}
>
<Icon type="link" className="mr-2 text-neutral" />
Attach to note Attach to note
</button> </button>
) : null} ) : null}
</> </>
)} )}
<div className="min-h-1px my-1 bg-border"></div> <HorizontalSeparator classes="my-1" />
<button <button
className="sn-dropdown-item justify-between focus:bg-info-backdrop" className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full focus:bg-info-backdrop focus:shadow-none text-sm justify-between"
onClick={() => { onClick={() => {
void filesController.setProtectionForFiles(!hasProtectedFiles, selectionController.selectedFiles) void filesController.setProtectionForFiles(!hasProtectedFiles, selectionController.selectedFiles)
}} }}
onBlur={closeOnBlur} onBlur={closeOnBlur}
> >
<span className="flex items-center"> <span className="flex items-center">
<Icon type="password" className="mr-2 color-neutral" /> <Icon type="password" className="mr-2 text-neutral" />
Password protection Password protection
</span> </span>
<Switch <Switch
@@ -101,41 +114,41 @@ const FileMenuOptions: FunctionComponent<Props> = ({
checked={hasProtectedFiles} checked={hasProtectedFiles}
/> />
</button> </button>
<div className="min-h-1px my-1 bg-border"></div> <HorizontalSeparator classes="my-1" />
<button <button
onBlur={closeOnBlur} onBlur={closeOnBlur}
className="sn-dropdown-item focus:bg-info-backdrop" className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full focus:bg-info-backdrop focus:shadow-none text-sm"
onClick={() => { onClick={() => {
void filesController.downloadFiles(selectionController.selectedFiles) void filesController.downloadFiles(selectionController.selectedFiles)
}} }}
> >
<Icon type="download" className="mr-2 color-neutral" /> <Icon type="download" className="mr-2 text-neutral" />
Download Download
</button> </button>
{shouldShowRenameOption && ( {shouldShowRenameOption && (
<button <button
onBlur={closeOnBlur} onBlur={closeOnBlur}
className="sn-dropdown-item focus:bg-info-backdrop" className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full focus:bg-info-backdrop focus:shadow-none text-sm"
onClick={() => { onClick={() => {
renameToggleCallback?.(true) renameToggleCallback?.(true)
}} }}
> >
<Icon type="pencil" className="mr-2 color-neutral" /> <Icon type="pencil" className="mr-2 text-neutral" />
Rename Rename
</button> </button>
)} )}
<button <button
onBlur={closeOnBlur} onBlur={closeOnBlur}
className="sn-dropdown-item focus:bg-info-backdrop" className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full focus:bg-info-backdrop focus:shadow-none text-sm"
onClick={() => { onClick={() => {
void filesController.deleteFilesPermanently(selectionController.selectedFiles) void filesController.deleteFilesPermanently(selectionController.selectedFiles)
}} }}
> >
<Icon type="trash" className="mr-2 color-danger" /> <Icon type="trash" className="mr-2 text-danger" />
<span className="color-danger">Delete permanently</span> <span className="text-danger">Delete permanently</span>
</button> </button>
{selectedFiles.length === 1 && ( {selectedFiles.length === 1 && (
<div className="px-3 pt-1.5 pb-0.5 text-xs color-neutral font-medium"> <div className="px-3 pt-1.5 pb-0.5 text-xs text-neutral font-medium">
<div> <div>
<span className="font-semibold">File ID:</span> {selectedFiles[0].uuid} <span className="font-semibold">File ID:</span> {selectedFiles[0].uuid}
</div> </div>

View File

@@ -52,7 +52,7 @@ const FilesOptionsPanel = ({ filesController, selectionController }: Props) => {
}} }}
onBlur={closeOnBlur} onBlur={closeOnBlur}
ref={buttonRef} ref={buttonRef}
className="sn-icon-button border-contrast" className="flex justify-center items-center min-w-8 h-8 bg-text-padding hover:bg-contrast focus:bg-contrast text-neutral border border-solid border-border rounded-full cursor-pointer"
> >
<VisuallyHidden>Actions</VisuallyHidden> <VisuallyHidden>Actions</VisuallyHidden>
<Icon type="more" className="block" /> <Icon type="more" className="block" />
@@ -69,7 +69,9 @@ const FilesOptionsPanel = ({ filesController, selectionController }: Props) => {
...position, ...position,
maxHeight, maxHeight,
}} }}
className="sn-dropdown sn-dropdown--animated min-w-80 max-h-120 max-w-xs flex flex-col py-2 overflow-y-auto fixed" className={`${
open ? 'flex' : 'hidden'
} flex-col min-w-80 max-h-120 max-w-xs py-2 fixed bg-default rounded shadow-main transition-transform duration-150 slide-down-animation overflow-y-auto`}
onBlur={closeOnBlur} onBlur={closeOnBlur}
tabIndex={FOCUSABLE_BUT_NOT_TABBABLE} tabIndex={FOCUSABLE_BUT_NOT_TABBABLE}
> >

View File

@@ -2,6 +2,7 @@ import { WebApplication } from '@/Application/Application'
import { concatenateUint8Arrays } from '@/Utils' import { concatenateUint8Arrays } from '@/Utils'
import { FileItem } from '@standardnotes/snjs' import { FileItem } from '@standardnotes/snjs'
import { useEffect, useMemo, useState } from 'react' import { useEffect, useMemo, useState } from 'react'
import Spinner from '@/Components/Spinner/Spinner'
import FilePreviewError from './FilePreviewError' import FilePreviewError from './FilePreviewError'
import { isFileTypePreviewable } from './isFilePreviewable' import { isFileTypePreviewable } from './isFilePreviewable'
import PreviewComponent from './PreviewComponent' import PreviewComponent from './PreviewComponent'
@@ -59,7 +60,7 @@ const FilePreview = ({ file, application }: Props) => {
return isDownloading ? ( return isDownloading ? (
<div className="flex flex-col justify-center items-center flex-grow"> <div className="flex flex-col justify-center items-center flex-grow">
<div className="flex items-center"> <div className="flex items-center">
<div className="sk-spinner w-5 h-5 spinner-info mr-3"></div> <Spinner className="w-5 h-5 mr-3" />
<div className="text-base font-semibold">{downloadProgress}%</div> <div className="text-base font-semibold">{downloadProgress}%</div>
</div> </div>
<span className="mt-3">Loading file...</span> <span className="mt-3">Loading file...</span>

View File

@@ -17,12 +17,12 @@ const FilePreviewError = ({ file, filesController, isFilePreviewable, tryAgainCa
<div className="font-bold text-base mb-2">This file can't be previewed.</div> <div className="font-bold text-base mb-2">This file can't be previewed.</div>
{isFilePreviewable ? ( {isFilePreviewable ? (
<> <>
<div className="text-sm text-center color-passive-0 mb-4 max-w-35ch"> <div className="text-sm text-center text-passive-0 mb-4 max-w-35ch">
There was an error loading the file. Try again, or download the file and open it using another application. There was an error loading the file. Try again, or download the file and open it using another application.
</div> </div>
<div className="flex items-center"> <div className="flex items-center">
<Button <Button
variant="primary" primary
className="mr-3" className="mr-3"
onClick={() => { onClick={() => {
tryAgainCallback() tryAgainCallback()
@@ -31,7 +31,6 @@ const FilePreviewError = ({ file, filesController, isFilePreviewable, tryAgainCa
Try again Try again
</Button> </Button>
<Button <Button
variant="normal"
onClick={() => { onClick={() => {
filesController.downloadFile(file).catch(console.error) filesController.downloadFile(file).catch(console.error)
}} }}
@@ -42,11 +41,11 @@ const FilePreviewError = ({ file, filesController, isFilePreviewable, tryAgainCa
</> </>
) : ( ) : (
<> <>
<div className="text-sm text-center color-passive-0 mb-4 max-w-35ch"> <div className="text-sm text-center text-passive-0 mb-4 max-w-35ch">
To view this file, download it and open it using another application. To view this file, download it and open it using another application.
</div> </div>
<Button <Button
variant="primary" primary
onClick={() => { onClick={() => {
filesController.downloadFile(file).catch(console.error) filesController.downloadFile(file).catch(console.error)
}} }}

View File

@@ -9,7 +9,7 @@ type Props = {
const FilePreviewInfoPanel: FunctionComponent<Props> = ({ file }) => { const FilePreviewInfoPanel: FunctionComponent<Props> = ({ file }) => {
return ( return (
<div className="flex flex-col min-w-70 p-4 border-0 border-l-1px border-solid border-main"> <div className="flex flex-col min-w-70 p-4 border-0 border-l border-solid border-border">
<div className="flex items-center mb-4"> <div className="flex items-center mb-4">
<Icon type="info" className="mr-2" /> <Icon type="info" className="mr-2" />
<div className="font-semibold">File information</div> <div className="font-semibold">File information</div>

View File

@@ -78,16 +78,10 @@ const FilePreviewModal: FunctionComponent<Props> = observer(({ application, view
> >
<DialogContent <DialogContent
aria-label="File preview modal" aria-label="File preview modal"
className="flex flex-col rounded shadow-overlay" className="flex flex-col rounded shadow-main p-0 min-w-[90%] min-h-[90%] bg-[color:var(--modal-background-color)] "
style={{
width: '90%',
maxWidth: '90%',
minHeight: '90%',
background: 'var(--modal-background-color)',
}}
> >
<div <div
className="flex flex-shrink-0 justify-between items-center min-h-6 px-4 py-3 border-0 border-b-1 border-solid border-main focus:shadow-none" className="flex flex-shrink-0 justify-between items-center min-h-6 px-4 py-3 border-0 border-b border-solid border-border focus:shadow-none"
tabIndex={FOCUSABLE_BUT_NOT_TABBABLE} tabIndex={FOCUSABLE_BUT_NOT_TABBABLE}
onKeyDown={keyDownHandler} onKeyDown={keyDownHandler}
> >
@@ -97,10 +91,10 @@ const FilePreviewModal: FunctionComponent<Props> = observer(({ application, view
</div> </div>
<div className="flex items-center"> <div className="flex items-center">
<button <button
className="flex p-1.5 mr-4 bg-transparent hover:bg-contrast border-solid border-main border-1 cursor-pointer rounded" className="flex p-1.5 mr-4 bg-transparent hover:bg-contrast border-solid border-border border cursor-pointer rounded"
onClick={() => setShowFileInfoPanel((show) => !show)} onClick={() => setShowFileInfoPanel((show) => !show)}
> >
<Icon type="info" className="color-neutral" /> <Icon type="info" className="text-neutral" />
</button> </button>
<button <button
ref={closeButtonRef} ref={closeButtonRef}
@@ -108,7 +102,7 @@ const FilePreviewModal: FunctionComponent<Props> = observer(({ application, view
aria-label="Close modal" aria-label="Close modal"
className="flex p-1 bg-transparent hover:bg-contrast border-0 cursor-pointer rounded" className="flex p-1 bg-transparent hover:bg-contrast border-0 cursor-pointer rounded"
> >
<Icon type="close" className="color-neutral" /> <Icon type="close" className="text-neutral" />
</button> </button>
</div> </div>
</div> </div>

View File

@@ -37,7 +37,7 @@ const ImagePreview: FunctionComponent<Props> = ({ objectUrl }) => {
}} }}
/> />
</div> </div>
<div className="flex items-center absolute left-1/2 -translate-x-1/2 bottom-6 py-1 px-3 bg-default border-1 border-solid border-main rounded"> <div className="flex items-center absolute left-1/2 -translate-x-1/2 bottom-6 py-1 px-3 bg-default border border-solid border-border rounded">
<span className="mr-1.5">Zoom:</span> <span className="mr-1.5">Zoom:</span>
<IconButton <IconButton
className="hover:bg-contrast p-1 rounded" className="hover:bg-contrast p-1 rounded"

View File

@@ -31,12 +31,15 @@ const FileViewWithoutProtection = ({ application, viewControllerManager, file }:
return ( return (
<div className="sn-component section editor" aria-label="File"> <div className="sn-component section editor" aria-label="File">
<div className="flex flex-col"> <div className="flex flex-col">
<div className="content-title-bar section-title-bar w-full" id="file-title-bar"> <div
className="content-title-bar section-title-bar z-editor-title-bar section-title-bar w-full"
id="file-title-bar"
>
<div className="flex items-center justify-between h-8"> <div className="flex items-center justify-between h-8">
<div className="flex-grow"> <div className="flex-grow">
<form onSubmit={onFormSubmit} className="title overflow-auto"> <form onSubmit={onFormSubmit} className="title overflow-auto">
<input <input
className="input" className="input text-lg"
id={ElementIds.FileTitleEditor} id={ElementIds.FileTitleEditor}
onChange={onTitleChange} onChange={onTitleChange}
onFocus={(event) => { onFocus={(event) => {

View File

@@ -342,9 +342,12 @@ class Footer extends PureComponent<Props, State> {
override render() { override render() {
return ( return (
<div className="sn-component"> <div className="sn-component">
<div id="footer-bar" className="sk-app-bar no-edges no-bottom-edge"> <div
<div className="left"> id="footer-bar"
<div className="sk-app-bar-item ml-0"> className="flex justify-between items-center w-full h-6 px-3 bg-contrast text-text z-footer-bar border-t border-border select-none"
>
<div className="left flex h-full">
<div className="sk-app-bar-item z-footer-bar-item relative select-none ml-0">
<div <div
onClick={this.accountMenuClickHandler} onClick={this.accountMenuClickHandler}
className={ className={
@@ -352,8 +355,12 @@ class Footer extends PureComponent<Props, State> {
' w-8 h-full flex items-center justify-center cursor-pointer rounded-full' ' w-8 h-full flex items-center justify-center cursor-pointer rounded-full'
} }
> >
<div className={this.state.hasError ? 'danger' : (this.user ? 'info' : 'neutral') + ' w-5 h-5'}> <div
<Icon type="account-circle" className="hover:color-info w-5 h-5 max-h-5" /> className={
this.state.hasError ? 'text-danger' : (this.user ? 'text-info' : 'text-neutral') + ' w-5 h-5'
}
>
<Icon type="account-circle" className="hover:text-info max-h-5" />
</div> </div>
</div> </div>
{this.state.showAccountMenu && ( {this.state.showAccountMenu && (
@@ -365,7 +372,7 @@ class Footer extends PureComponent<Props, State> {
/> />
)} )}
</div> </div>
<div className="sk-app-bar-item ml-0-important"> <div className="sk-app-bar-item z-footer-bar-item relative select-none ml-0-important">
<div <div
onClick={this.quickSettingsClickHandler} onClick={this.quickSettingsClickHandler}
className="w-8 h-full flex items-center justify-center cursor-pointer" className="w-8 h-full flex items-center justify-center cursor-pointer"
@@ -373,7 +380,7 @@ class Footer extends PureComponent<Props, State> {
<div className="h-5"> <div className="h-5">
<Icon <Icon
type="tune" type="tune"
className={(this.state.showQuickSettingsMenu ? 'color-info' : '') + ' rounded hover:color-info'} className={(this.state.showQuickSettingsMenu ? 'text-info' : '') + ' rounded hover:text-info'}
/> />
</div> </div>
</div> </div>
@@ -387,9 +394,8 @@ class Footer extends PureComponent<Props, State> {
</div> </div>
{this.state.showBetaWarning && ( {this.state.showBetaWarning && (
<Fragment> <Fragment>
<div className="sk-app-bar-item border" /> <div className="flex items-center z-footer-bar-item pl-3 ml-3 relative select-none border-l border-solid border-border">
<div className="sk-app-bar-item"> <a onClick={this.betaMessageClickHandler} className="no-decoration text-xs font-bold title">
<a onClick={this.betaMessageClickHandler} className="no-decoration sk-label title">
You are using a beta version of the app You are using a beta version of the app
</a> </a>
</div> </div>
@@ -398,28 +404,32 @@ class Footer extends PureComponent<Props, State> {
</div> </div>
<div className="center"> <div className="center">
{this.state.arbitraryStatusMessage && ( {this.state.arbitraryStatusMessage && (
<div className="sk-app-bar-item"> <div className="flex items-center z-footer-bar-item relative select-none text-xs text-neutral font-bold">
<div className="sk-app-bar-item-column"> {this.state.arbitraryStatusMessage}
<span className="neutral sk-label">{this.state.arbitraryStatusMessage}</span>
</div>
</div> </div>
)} )}
</div> </div>
<div className="right"> <div className="right flex h-full">
{this.state.dataUpgradeAvailable && ( {this.state.dataUpgradeAvailable && (
<div onClick={this.securityUpdateClickHandler} className="sk-app-bar-item"> <div
<span className="success sk-label">Encryption upgrade available.</span> onClick={this.securityUpdateClickHandler}
className="flex items-center text-xs text-success font-bold z-footer-bar-item relative select-none"
>
Encryption upgrade available.
</div> </div>
)} )}
{this.state.newUpdateAvailable && ( {this.state.newUpdateAvailable && (
<div onClick={this.newUpdateClickHandler} className="sk-app-bar-item"> <div
<span className="info sk-label">New update available.</span> onClick={this.newUpdateClickHandler}
className="flex items-center ml-3 text-xs text-info font-bold z-footer-bar-item relative select-none"
>
New update available.
</div> </div>
)} )}
{(this.state.outOfSync || this.state.showSyncResolution) && ( {(this.state.outOfSync || this.state.showSyncResolution) && (
<div className="sk-app-bar-item"> <div className="flex items-center ml-3 z-footer-bar-item relative select-none">
{this.state.outOfSync && ( {this.state.outOfSync && (
<div onClick={this.syncResolutionClickHandler} className="sk-label warning"> <div onClick={this.syncResolutionClickHandler} className="font-bold text-xs text-warning">
Potentially Out of Sync Potentially Out of Sync
</div> </div>
)} )}
@@ -429,22 +439,19 @@ class Footer extends PureComponent<Props, State> {
</div> </div>
)} )}
{this.state.offline && ( {this.state.offline && (
<div className="sk-app-bar-item"> <div className="flex items-center ml-3 text-xs font-bold z-footer-bar-item relative select-none">
<div className="sk-label">Offline</div> Offline
</div> </div>
)} )}
{this.state.hasPasscode && ( {this.state.hasPasscode && (
<Fragment> <div
<div className="sk-app-bar-item border" /> id="lock-item"
<div onClick={this.lockClickHandler}
id="lock-item" title="Locks application and wipes unencrypted data from memory."
onClick={this.lockClickHandler} className="flex items-center z-footer-bar-item relative select-none pl-2 ml-3 hover:text-info border-l border-solid border-border cursor-pointer"
title="Locks application and wipes unencrypted data from memory." >
className="sk-app-bar-item pl-1 hover:color-info" <Icon type="lock-filled" size="custom" className="w-4.5 h-4.5" />
> </div>
<Icon type="lock-filled" />
</div>
</Fragment>
)} )}
</div> </div>
</div> </div>

View File

@@ -1,4 +1,4 @@
import { FunctionComponent } from 'react' import { FunctionComponent, useMemo } from 'react'
import { IconType } from '@standardnotes/snjs' import { IconType } from '@standardnotes/snjs'
import { import {
@@ -187,16 +187,32 @@ type Props = {
type: IconType type: IconType
className?: string className?: string
ariaLabel?: string ariaLabel?: string
size?: 'small' | 'medium' | 'normal' | 'custom'
} }
const Icon: FunctionComponent<Props> = ({ type, className = '', ariaLabel }) => { const Icon: FunctionComponent<Props> = ({ type, className = '', ariaLabel, size = 'normal' }) => {
const IconComponent = ICONS[type as keyof typeof ICONS] const IconComponent = ICONS[type as keyof typeof ICONS]
const dimensions = useMemo(() => {
switch (size) {
case 'small':
return 'w-3.5 h-3.5'
case 'medium':
return 'w-4 h-4'
case 'custom':
return ''
default:
return 'w-5 h-5'
}
}, [size])
if (!IconComponent) { if (!IconComponent) {
return null return null
} }
return ( return (
<IconComponent <IconComponent
className={`sn-icon ${className}`} className={`${dimensions} fill-current ${className}`}
role="img" role="img"
{...(ariaLabel ? { 'aria-label': ariaLabel } : { 'aria-hidden': true })} {...(ariaLabel ? { 'aria-label': ariaLabel } : { 'aria-hidden': true })}
/> />

View File

@@ -0,0 +1,18 @@
type Props = {
style: 'neutral' | 'info' | 'danger'
}
const baseClassNames = 'border border-solid w-3 h-3 p-0 rounded-full flex-shrink-0'
const IndicatorCircle = ({ style }: Props) => {
switch (style) {
case 'neutral':
return <div className={`${baseClassNames} bg-neutral border-neutral`} />
case 'info':
return <div className={`${baseClassNames} bg-info border-info`} />
case 'danger':
return <div className={`${baseClassNames} bg-danger border-danger`} />
}
}
export default IndicatorCircle

View File

@@ -3,10 +3,10 @@ import { DecoratedInputProps } from './DecoratedInputProps'
const getClassNames = (hasLeftDecorations: boolean, hasRightDecorations: boolean) => { const getClassNames = (hasLeftDecorations: boolean, hasRightDecorations: boolean) => {
return { return {
container: `flex items-stretch position-relative bg-default border-1 border-solid border-main rounded focus-within:ring-info overflow-hidden ${ container: `flex items-stretch position-relative bg-default border border-solid border-border rounded focus-within:ring-2 focus-within:ring-info overflow-hidden text-sm ${
!hasLeftDecorations && !hasRightDecorations ? 'px-2 py-1.5' : '' !hasLeftDecorations && !hasRightDecorations ? 'px-2 py-1.5' : ''
}`, }`,
input: `w-full border-0 focus:shadow-none bg-transparent color-text ${ input: `w-full border-0 focus:shadow-none focus:outline-none focus:ring-none bg-transparent text-text ${
!hasLeftDecorations && hasRightDecorations ? 'pl-2' : '' !hasLeftDecorations && hasRightDecorations ? 'pl-2' : ''
} ${hasRightDecorations ? 'pr-2' : ''}`, } ${hasRightDecorations ? 'pr-2' : ''}`,
disabled: 'bg-passive-5 cursor-not-allowed', disabled: 'bg-passive-5 cursor-not-allowed',
@@ -21,6 +21,7 @@ const DecoratedInput = forwardRef(
{ {
type = 'text', type = 'text',
className = '', className = '',
id = '',
disabled = false, disabled = false,
left, left,
right, right,
@@ -49,6 +50,7 @@ const DecoratedInput = forwardRef(
<input <input
type={type} type={type}
id={id}
className={`${classNames.input} ${disabled ? classNames.disabled : ''}`} className={`${classNames.input} ${disabled ? classNames.disabled : ''}`}
disabled={disabled} disabled={disabled}
value={value} value={value}

View File

@@ -3,6 +3,7 @@ import { FocusEventHandler, KeyboardEventHandler, ReactNode } from 'react'
export type DecoratedInputProps = { export type DecoratedInputProps = {
type?: 'text' | 'email' | 'password' type?: 'text' | 'email' | 'password'
className?: string className?: string
id?: string
disabled?: boolean disabled?: boolean
left?: ReactNode[] left?: ReactNode[]
right?: ReactNode[] right?: ReactNode[]

View File

@@ -8,9 +8,9 @@ const Toggle: FunctionComponent<{
setIsToggled: Dispatch<SetStateAction<boolean>> setIsToggled: Dispatch<SetStateAction<boolean>>
}> = ({ isToggled, setIsToggled }) => ( }> = ({ isToggled, setIsToggled }) => (
<IconButton <IconButton
className="w-5 h-5 p-0 justify-center sk-circle hover:bg-passive-4 color-neutral" className="w-5 h-5 p-0 justify-center rounded-full hover:bg-passive-4 text-neutral"
icon={isToggled ? 'eye-off' : 'eye'} icon={isToggled ? 'eye-off' : 'eye'}
iconClassName="sn-icon--small" iconClassName="w-3.5 h-3.5"
title="Show/hide password" title="Show/hide password"
onClick={() => setIsToggled((isToggled) => !isToggled)} onClick={() => setIsToggled((isToggled) => !isToggled)}
focusable={true} focusable={true}

View File

@@ -33,14 +33,14 @@ const FloatingLabelInput = forwardRef(
const BASE_CLASSNAME = 'relative bg-default' const BASE_CLASSNAME = 'relative bg-default'
const LABEL_CLASSNAME = `hidden absolute ${!focused ? 'color-neutral' : 'color-info'} ${ const LABEL_CLASSNAME = `absolute ${!focused ? 'text-neutral' : 'text-info'} ${
focused || value ? 'flex top-0 left-2 pt-1.5 px-1' : '' focused || value ? 'flex top-0 left-2 pt-1.5 px-1' : 'hidden'
} ${isInvalid ? 'color-danger' : ''} ${labelClassName}` } ${isInvalid ? 'text-danger' : ''} ${labelClassName}`
const INPUT_CLASSNAME = `w-full h-full ${ const INPUT_CLASSNAME = `w-full h-full ${
focused || value ? 'pt-6 pb-2' : 'py-2.5' focused || value ? 'pt-6 pb-2' : 'py-2.5'
} px-3 text-input border-1 border-solid border-main rounded placeholder-medium text-input focus:ring-info ${ } px-3 text-sm border border-solid border-border rounded placeholder:font-medium focus:ring-info ${
isInvalid ? 'border-danger placeholder-dark-red' : '' isInvalid ? 'border-danger placeholder:text-danger' : ''
} ${inputClassName}` } ${inputClassName}`
const handleFocus = () => setFocused(true) const handleFocus = () => setFocused(true)

View File

@@ -8,7 +8,7 @@ interface Props {
const Input: FunctionComponent<Props> = ({ className = '', disabled = false, text }) => { const Input: FunctionComponent<Props> = ({ className = '', disabled = false, text }) => {
const base = 'rounded py-1.5 px-3 text-input my-1 h-8 bg-contrast' const base = 'rounded py-1.5 px-3 text-input my-1 h-8 bg-contrast'
const stateClasses = disabled ? 'no-border' : 'border-solid border-1 border-main' const stateClasses = disabled ? 'no-border' : 'border-solid border border-border'
const classes = `${base} ${stateClasses} ${className}` const classes = `${base} ${stateClasses} ${className}`
return <input type="text" className={classes} disabled={disabled} value={text} /> return <input type="text" className={classes} disabled={disabled} value={text} />
} }

View File

@@ -53,7 +53,7 @@ const Menu: FunctionComponent<MenuProps> = ({
return ( return (
<menu <menu
className={`m-0 pl-0 list-style-none focus:shadow-none ${className}`} className={`m-0 pl-0 list-none focus:shadow-none ${className}`}
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
ref={menuElementRef} ref={menuElementRef}
style={style} style={style}

View File

@@ -5,6 +5,7 @@ import { SwitchProps } from '@/Components/Switch/SwitchProps'
import { IconType } from '@standardnotes/snjs' import { IconType } from '@standardnotes/snjs'
import { FOCUSABLE_BUT_NOT_TABBABLE } from '@/Constants/Constants' import { FOCUSABLE_BUT_NOT_TABBABLE } from '@/Constants/Constants'
import { MenuItemType } from './MenuItemType' import { MenuItemType } from './MenuItemType'
import RadioIndicator from '../RadioIndicator/RadioIndicator'
type MenuItemProps = { type MenuItemProps = {
type: MenuItemType type: MenuItemType
@@ -36,10 +37,10 @@ const MenuItem = forwardRef(
ref: Ref<HTMLButtonElement>, ref: Ref<HTMLButtonElement>,
) => { ) => {
return type === MenuItemType.SwitchButton && typeof onChange === 'function' ? ( return type === MenuItemType.SwitchButton && typeof onChange === 'function' ? (
<li className="list-style-none" role="none"> <li className="list-none" role="none">
<button <button
ref={ref} ref={ref}
className="sn-dropdown-item focus:bg-info-backdrop focus:shadow-none justify-between" className="flex items-center justify-between border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full focus:bg-info-backdrop focus:shadow-none"
onClick={() => { onClick={() => {
onChange(!checked) onChange(!checked)
}} }}
@@ -53,19 +54,19 @@ const MenuItem = forwardRef(
</button> </button>
</li> </li>
) : ( ) : (
<li className="list-style-none" role="none"> <li className="list-none" role="none">
<button <button
ref={ref} ref={ref}
role={type === MenuItemType.RadioButton ? 'menuitemradio' : 'menuitem'} role={type === MenuItemType.RadioButton ? 'menuitemradio' : 'menuitem'}
tabIndex={typeof tabIndex === 'number' ? tabIndex : FOCUSABLE_BUT_NOT_TABBABLE} tabIndex={typeof tabIndex === 'number' ? tabIndex : FOCUSABLE_BUT_NOT_TABBABLE}
className={`sn-dropdown-item focus:bg-info-backdrop focus:shadow-none ${className}`} className={`flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full focus:bg-info-backdrop focus:shadow-none text-menu-item ${className}`}
onClick={onClick} onClick={onClick}
onBlur={onBlur} onBlur={onBlur}
{...(type === MenuItemType.RadioButton ? { 'aria-checked': checked } : {})} {...(type === MenuItemType.RadioButton ? { 'aria-checked': checked } : {})}
> >
{type === MenuItemType.IconButton && icon ? <Icon type={icon} className={iconClassName} /> : null} {type === MenuItemType.IconButton && icon ? <Icon type={icon} className={iconClassName} /> : null}
{type === MenuItemType.RadioButton && typeof checked === 'boolean' ? ( {type === MenuItemType.RadioButton && typeof checked === 'boolean' ? (
<div className={`pseudo-radio-btn ${checked ? 'pseudo-radio-btn--checked' : ''} flex-shrink-0`}></div> <RadioIndicator checked={checked} className="flex-shrink-0" />
) : null} ) : null}
{children} {children}
</button> </button>

View File

@@ -1,8 +1,8 @@
import { FunctionComponent } from 'react' import { FunctionComponent } from 'react'
const MenuItemSeparator: FunctionComponent = () => ( const MenuItemSeparator: FunctionComponent = () => (
<li className="list-style-none" role="none"> <li className="list-none" role="none">
<div role="separator" className="h-1px my-2 bg-border" /> <div role="separator" className="h-[1px] my-2 bg-border" />
</li> </li>
) )

View File

@@ -40,7 +40,7 @@ const MultipleSelectedFiles = ({
return ( return (
<div className="flex flex-col h-full items-center"> <div className="flex flex-col h-full items-center">
<div className="flex items-center justify-between p-4 w-full"> <div className="flex items-center justify-between p-4 w-full">
<h1 className="sk-h1 font-bold m-0">{count} selected files</h1> <h1 className="text-lg font-bold m-0">{count} selected files</h1>
<div className="flex"> <div className="flex">
<div className="mr-3"> <div className="mr-3">
<AttachedFilesButton <AttachedFilesButton
@@ -58,7 +58,7 @@ const MultipleSelectedFiles = ({
</div> </div>
<div className="flex-grow flex flex-col justify-center items-center w-full max-w-md"> <div className="flex-grow flex flex-col justify-center items-center w-full max-w-md">
<IlNotesIcon className="block" /> <IlNotesIcon className="block" />
<h2 className="text-lg m-0 text-center mt-4">{count} selected files</h2> <h2 className="font-bold text-lg m-0 text-center mt-4">{count} selected files</h2>
<p className="text-sm mt-2 text-center max-w-60">Actions will be performed on all selected files.</p> <p className="text-sm mt-2 text-center max-w-60">Actions will be performed on all selected files.</p>
<Button className="mt-2.5" onClick={cancelMultipleSelection}> <Button className="mt-2.5" onClick={cancelMultipleSelection}>
Cancel multiple selection Cancel multiple selection

View File

@@ -47,7 +47,7 @@ const MultipleSelectedNotes = ({
return ( return (
<div className="flex flex-col h-full items-center"> <div className="flex flex-col h-full items-center">
<div className="flex items-center justify-between p-4 w-full"> <div className="flex items-center justify-between p-4 w-full">
<h1 className="sk-h1 font-bold m-0">{count} selected notes</h1> <h1 className="text-lg font-bold m-0">{count} selected notes</h1>
<div className="flex"> <div className="flex">
<div className="mr-3"> <div className="mr-3">
<AttachedFilesButton <AttachedFilesButton
@@ -74,7 +74,7 @@ const MultipleSelectedNotes = ({
</div> </div>
<div className="flex-grow flex flex-col justify-center items-center w-full max-w-md"> <div className="flex-grow flex flex-col justify-center items-center w-full max-w-md">
<IlNotesIcon className="block" /> <IlNotesIcon className="block" />
<h2 className="text-lg m-0 text-center mt-4">{count} selected notes</h2> <h2 className="font-bold text-lg m-0 text-center mt-4">{count} selected notes</h2>
<p className="text-sm mt-2 text-center max-w-60">Actions will be performed on all selected notes.</p> <p className="text-sm mt-2 text-center max-w-60">Actions will be performed on all selected notes.</p>
<Button className="mt-2.5" onClick={cancelMultipleSelection}> <Button className="mt-2.5" onClick={cancelMultipleSelection}>
Cancel multiple selection Cancel multiple selection

View File

@@ -52,8 +52,8 @@ const Navigation: FunctionComponent<Props> = ({ application }) => {
<div id="navigation-content" className="content"> <div id="navigation-content" className="content">
<div className="section-title-bar"> <div className="section-title-bar">
<div className="section-title-bar-header"> <div className="section-title-bar-header">
<div className="sk-h3 title"> <div className="text-sm title">
<span className="sk-bold">Views</span> <span className="font-bold">Views</span>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -3,6 +3,7 @@ import { AccountMenuController } from '@/Controllers/AccountMenu/AccountMenuCont
import { NoAccountWarningController } from '@/Controllers/NoAccountWarningController' import { NoAccountWarningController } from '@/Controllers/NoAccountWarningController'
import { observer } from 'mobx-react-lite' import { observer } from 'mobx-react-lite'
import { MouseEventHandler, useCallback } from 'react' import { MouseEventHandler, useCallback } from 'react'
import Button from '@/Components/Button/Button'
type Props = { type Props = {
accountMenuController: AccountMenuController accountMenuController: AccountMenuController
@@ -23,18 +24,18 @@ const NoAccountWarningContent = ({ accountMenuController, noAccountWarningContro
}, [noAccountWarningController]) }, [noAccountWarningController])
return ( return (
<div className="mt-4 p-4 rounded-md shadow-sm grid grid-template-cols-1fr"> <div className="mt-4 p-4 rounded-md shadow grid grid-cols-1">
<h1 className="sk-h3 m-0 font-semibold">Data not backed up</h1> <h1 className="sk-h3 m-0 font-semibold text-sm">Data not backed up</h1>
<p className="m-0 mt-1 col-start-1 col-end-3">Sign in or register to back up your notes.</p> <p className="m-0 mt-1 col-start-1 col-end-3 text-sm">Sign in or register to back up your notes.</p>
<button className="sn-button small info mt-3 col-start-1 col-end-3 justify-self-start" onClick={showAccountMenu}> <Button primary small className="mt-3 col-start-1 col-end-3 justify-self-start" onClick={showAccountMenu}>
Open Account menu Open Account menu
</button> </Button>
<button <button
onClick={hideWarning} onClick={hideWarning}
title="Ignore warning" title="Ignore warning"
aria-label="Ignore warning" aria-label="Ignore warning"
style={{ height: '20px' }} style={{ height: '20px' }}
className="border-0 m-0 p-0 bg-transparent cursor-pointer rounded-md col-start-2 row-start-1 color-neutral hover:color-info" className="border-0 m-0 p-0 bg-transparent cursor-pointer rounded-md col-start-2 row-start-1 text-neutral hover:text-info"
> >
<Icon type="close" className="block" /> <Icon type="close" className="block" />
</button> </button>

View File

@@ -116,7 +116,7 @@ const NoteTag = ({ viewControllerManager, tag }: Props) => {
return ( return (
<button <button
ref={tagRef} ref={tagRef}
className="sn-tag pl-1 pr-2 mr-2" className="h-6 bg-contrast border-0 rounded text-xs text-text flex items-center mt-2 cursor-pointer hover:bg-secondary-contrast focus:bg-secondary-contrast py-2 pl-1 pr-2 mr-2"
onClick={onTagClick} onClick={onTagClick}
onKeyDown={onKeyDown} onKeyDown={onKeyDown}
onFocus={onFocus} onFocus={onFocus}
@@ -124,9 +124,9 @@ const NoteTag = ({ viewControllerManager, tag }: Props) => {
tabIndex={getTabIndex()} tabIndex={getTabIndex()}
title={longTitle} title={longTitle}
> >
<Icon type="hashtag" className="sn-icon--small color-info mr-1" /> <Icon type="hashtag" className="text-info mr-1" size="small" />
<span className="whitespace-nowrap overflow-hidden overflow-ellipsis max-w-290px"> <span className="whitespace-nowrap overflow-hidden overflow-ellipsis max-w-290px">
{prefixTitle && <span className="color-passive-1">{prefixTitle}</span>} {prefixTitle && <span className="text-passive-1">{prefixTitle}</span>}
{title} {title}
</span> </span>
{showDeleteButton && ( {showDeleteButton && (
@@ -138,7 +138,7 @@ const NoteTag = ({ viewControllerManager, tag }: Props) => {
onClick={onDeleteTagClick} onClick={onDeleteTagClick}
tabIndex={-1} tabIndex={-1}
> >
<Icon type="close" className="sn-icon--small color-neutral hover:color-info" /> <Icon type="close" className="text-neutral hover:text-info" size="small" />
</a> </a>
)} )}
</button> </button>

View File

@@ -17,12 +17,12 @@ const EditingDisabledBanner: FunctionComponent<Props> = ({
lockText, lockText,
}) => { }) => {
const background = showLockedIcon ? 'bg-warning-faded' : 'bg-info-faded' const background = showLockedIcon ? 'bg-warning-faded' : 'bg-info-faded'
const iconColor = showLockedIcon ? 'color-accessory-tint-3' : 'color-accessory-tint-1' const iconColor = showLockedIcon ? 'text-accessory-tint-3' : 'text-accessory-tint-1'
const textColor = showLockedIcon ? 'color-warning' : 'color-accessory-tint-1' const textColor = showLockedIcon ? 'text-warning' : 'text-accessory-tint-1'
return ( return (
<div <div
className={`flex items-center relative ${background} px-3.5 py-2 cursor-pointer`} className={`flex items-center relative ${background} px-3.5 py-2 cursor-pointer text-sm`}
onMouseLeave={onMouseLeave} onMouseLeave={onMouseLeave}
onMouseOver={onMouseOver} onMouseOver={onMouseOver}
onClick={onClick} onClick={onClick}

View File

@@ -36,6 +36,7 @@ import {
import { reloadFont } from './FontFunctions' import { reloadFont } from './FontFunctions'
import { NoteViewProps } from './NoteViewProps' import { NoteViewProps } from './NoteViewProps'
import { WebAppEvent } from '@/Application/WebAppEvent' import { WebAppEvent } from '@/Application/WebAppEvent'
import IndicatorCircle from '../IndicatorCircle/IndicatorCircle'
const MINIMUM_STATUS_DURATION = 400 const MINIMUM_STATUS_DURATION = 400
const TEXTAREA_DEBOUNCE = 100 const TEXTAREA_DEBOUNCE = 100
@@ -907,12 +908,15 @@ class NoteView extends PureComponent<NoteViewProps, State> {
)} )}
{this.note && ( {this.note && (
<div id="editor-title-bar" className="content-title-bar section-title-bar w-full"> <div
id="editor-title-bar"
className="content-title-bar section-title-bar z-editor-title-bar section-title-bar w-full"
>
<div className="flex items-center justify-between h-8"> <div className="flex items-center justify-between h-8">
<div className={(this.state.noteLocked ? 'locked' : '') + ' flex-grow'}> <div className={(this.state.noteLocked ? 'locked' : '') + ' flex-grow'}>
<div className="title overflow-auto"> <div className="title overflow-auto">
<input <input
className="input" className="input text-lg"
disabled={this.state.noteLocked} disabled={this.state.noteLocked}
id={ElementIds.NoteTitleEditor} id={ElementIds.NoteTitleEditor}
onChange={this.onTitleChange} onChange={this.onTitleChange}
@@ -931,14 +935,14 @@ class NoteView extends PureComponent<NoteViewProps, State> {
<div id="save-status"> <div id="save-status">
<div <div
className={ className={
(this.state.syncTakingTooLong ? 'warning sk-bold ' : '') + (this.state.syncTakingTooLong ? 'text-warning font-bold ' : '') +
(this.state.saveError ? 'danger sk-bold ' : '') + (this.state.saveError ? 'text-danger font-bold ' : '') +
' message' 'text-xs message'
} }
> >
{this.state.noteStatus?.message} {this.state.noteStatus?.message}
</div> </div>
{this.state.noteStatus?.desc && <div className="desc">{this.state.noteStatus.desc}</div>} {this.state.noteStatus?.desc && <div className="text-xs desc">{this.state.noteStatus.desc}</div>}
</div> </div>
</div> </div>
<div className="mr-3"> <div className="mr-3">
@@ -980,7 +984,11 @@ class NoteView extends PureComponent<NoteViewProps, State> {
</div> </div>
)} )}
<div id={ElementIds.EditorContent} className={ElementIds.EditorContent} ref={this.editorContentRef}> <div
id={ElementIds.EditorContent}
className={`${ElementIds.EditorContent} z-editor-content`}
ref={this.editorContentRef}
>
{this.state.marginResizersEnabled && this.editorContentRef.current ? ( {this.state.marginResizersEnabled && this.editorContentRef.current ? (
<PanelResizer <PanelResizer
minWidth={300} minWidth={300}
@@ -1039,8 +1047,11 @@ class NoteView extends PureComponent<NoteViewProps, State> {
<div id="editor-pane-component-stack"> <div id="editor-pane-component-stack">
{this.state.availableStackComponents.length > 0 && ( {this.state.availableStackComponents.length > 0 && (
<div id="component-stack-menu-bar" className="sk-app-bar no-edges"> <div
<div className="left"> id="component-stack-menu-bar"
className="flex justify-between items-center w-full h-6 px-2 py-0 bg-contrast text-text border-t border-solid border-border"
>
<div className="flex h-full">
{this.state.availableStackComponents.map((component) => { {this.state.availableStackComponents.map((component) => {
return ( return (
<div <div
@@ -1048,19 +1059,16 @@ class NoteView extends PureComponent<NoteViewProps, State> {
onClick={() => { onClick={() => {
this.toggleStackComponent(component).catch(console.error) this.toggleStackComponent(component).catch(console.error)
}} }}
className="sk-app-bar-item" className="flex justify-center items-center flex-grow [&:not(:first-child)]:ml-3 cursor-pointer"
> >
<div className="sk-app-bar-item-column"> <div className="flex items-center h-full [&:not(:first-child)]:ml-2">
<div {this.stackComponentExpanded(component) && component.active && (
className={ <IndicatorCircle style="info" />
(this.stackComponentExpanded(component) && component.active ? 'info ' : '') + )}
(!this.stackComponentExpanded(component) ? 'neutral ' : '') + {!this.stackComponentExpanded(component) && <IndicatorCircle style="neutral" />}
' sk-circle small'
}
/>
</div> </div>
<div className="sk-app-bar-item-column"> <div className="flex items-center h-full [&:not(:first-child)]:ml-2">
<div className="sk-label">{component.name}</div> <div className="font-bold whitespace-nowrap text-xs">{component.name}</div>
</div> </div>
</div> </div>
) )

View File

@@ -45,7 +45,7 @@ const NotesContextMenu = ({
return contextMenuOpen ? ( return contextMenuOpen ? (
<div <div
ref={contextMenuRef} ref={contextMenuRef}
className="sn-dropdown min-w-80 max-h-120 max-w-xs flex flex-col pt-2 overflow-y-auto fixed" className="bg-default rounded shadow-main min-w-80 max-h-120 max-w-xs flex flex-col pt-2 overflow-y-auto fixed z-dropdown-menu"
style={{ style={{
...contextMenuPosition, ...contextMenuPosition,
maxHeight: contextMenuMaxHeight, maxHeight: contextMenuMaxHeight,

View File

@@ -66,13 +66,13 @@ const AddTagOption: FunctionComponent<Props> = ({ navigationController, notesCon
}} }}
onBlur={closeOnBlur} onBlur={closeOnBlur}
ref={menuButtonRef} ref={menuButtonRef}
className="sn-dropdown-item justify-between" className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full focus:bg-info-backdrop focus:shadow-none text-menu-item justify-between"
> >
<div className="flex items-center"> <div className="flex items-center">
<Icon type="hashtag" className="mr-2 color-neutral" /> <Icon type="hashtag" className="mr-2 text-neutral" />
Add tag Add tag
</div> </div>
<Icon type="chevron-right" className="color-neutral" /> <Icon type="chevron-right" className="text-neutral" />
</DisclosureButton> </DisclosureButton>
<DisclosurePanel <DisclosurePanel
ref={menuRef} ref={menuRef}
@@ -86,12 +86,14 @@ const AddTagOption: FunctionComponent<Props> = ({ navigationController, notesCon
...menuStyle, ...menuStyle,
position: 'fixed', position: 'fixed',
}} }}
className="sn-dropdown min-w-80 flex flex-col py-2 max-h-120 max-w-xs fixed overflow-y-auto" className={`${
isMenuOpen ? 'flex' : 'hidden'
} flex-col py-2 bg-default rounded shadow-main min-w-80 max-h-120 max-w-xs fixed overflow-y-auto`}
> >
{navigationController.tags.map((tag) => ( {navigationController.tags.map((tag) => (
<button <button
key={tag.uuid} key={tag.uuid}
className="sn-dropdown-item sn-dropdown-item--no-icon max-w-80" className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-2 text-left w-full focus:bg-info-backdrop focus:shadow-none text-menu-item max-w-80"
onBlur={closeOnBlur} onBlur={closeOnBlur}
onClick={() => { onClick={() => {
notesController.isTagInSelectedNotes(tag) notesController.isTagInSelectedNotes(tag)

View File

@@ -50,7 +50,7 @@ const ChangeEditorOption: FunctionComponent<ChangeEditorOptionProps> = ({ applic
setMenuStyle(newMenuStyle) setMenuStyle(newMenuStyle)
setIsVisible(true) setIsVisible(true)
} }
}) }, 5)
} }
}, [isOpen]) }, [isOpen])
@@ -65,13 +65,13 @@ const ChangeEditorOption: FunctionComponent<ChangeEditorOptionProps> = ({ applic
}} }}
onBlur={closeOnBlur} onBlur={closeOnBlur}
ref={buttonRef} ref={buttonRef}
className="sn-dropdown-item justify-between" className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full focus:bg-info-backdrop focus:shadow-none text-menu-item justify-between"
> >
<div className="flex items-center"> <div className="flex items-center">
<Icon type="dashboard" className="color-neutral mr-2" /> <Icon type="dashboard" className="text-neutral mr-2" />
Change note type Change note type
</div> </div>
<Icon type="chevron-right" className="color-neutral" /> <Icon type="chevron-right" className="text-neutral" />
</DisclosureButton> </DisclosureButton>
<DisclosurePanel <DisclosurePanel
ref={menuRef} ref={menuRef}
@@ -85,7 +85,7 @@ const ChangeEditorOption: FunctionComponent<ChangeEditorOptionProps> = ({ applic
...menuStyle, ...menuStyle,
position: 'fixed', position: 'fixed',
}} }}
className="sn-dropdown flex flex-col max-h-120 min-w-68 fixed overflow-y-auto" className="bg-default rounded shadow-main flex flex-col max-h-120 min-w-68 fixed overflow-y-auto"
> >
{isOpen && ( {isOpen && (
<ChangeEditorMenu <ChangeEditorMenu

View File

@@ -0,0 +1,145 @@
import { WebApplication } from '@/Application/Application'
import { Action, SNNote } from '@standardnotes/snjs'
import { Fragment, useCallback, useEffect, useState } from 'react'
import Icon from '@/Components/Icon/Icon'
import { ListedMenuGroup } from './ListedMenuGroup'
import ListedMenuItem from './ListedMenuItem'
import Spinner from '@/Components/Spinner/Spinner'
type ListedActionsMenuProps = {
application: WebApplication
note: SNNote
recalculateMenuStyle: () => void
}
const ListedActionsMenu = ({ application, note, recalculateMenuStyle }: ListedActionsMenuProps) => {
const [menuGroups, setMenuGroups] = useState<ListedMenuGroup[]>([])
const [isFetchingAccounts, setIsFetchingAccounts] = useState(true)
const reloadMenuGroup = useCallback(
async (group: ListedMenuGroup) => {
const updatedAccountInfo = await application.getListedAccountInfo(group.account, note.uuid)
if (!updatedAccountInfo) {
return
}
const updatedGroup: ListedMenuGroup = {
name: updatedAccountInfo.display_name,
account: group.account,
actions: updatedAccountInfo.actions as Action[],
}
const updatedGroups = menuGroups.map((group) => {
if (updatedGroup.account.authorId === group.account.authorId) {
return updatedGroup
} else {
return group
}
})
setMenuGroups(updatedGroups)
},
[application, menuGroups, note],
)
useEffect(() => {
const fetchListedAccounts = async () => {
if (!application.hasAccount()) {
setIsFetchingAccounts(false)
return
}
try {
const listedAccountEntries = await application.getListedAccounts()
if (!listedAccountEntries.length) {
throw new Error('No Listed accounts found')
}
const menuGroups: ListedMenuGroup[] = []
await Promise.all(
listedAccountEntries.map(async (account) => {
const accountInfo = await application.getListedAccountInfo(account, note.uuid)
if (accountInfo) {
menuGroups.push({
name: accountInfo.display_name,
account,
actions: accountInfo.actions as Action[],
})
} else {
menuGroups.push({
name: account.authorId,
account,
actions: [],
})
}
}),
)
setMenuGroups(
menuGroups.sort((a, b) => {
return a.name.toString().toLowerCase() < b.name.toString().toLowerCase() ? -1 : 1
}),
)
} catch (err) {
console.error(err)
} finally {
setIsFetchingAccounts(false)
setTimeout(() => {
recalculateMenuStyle()
})
}
}
void fetchListedAccounts()
}, [application, note.uuid, recalculateMenuStyle])
return (
<>
{isFetchingAccounts && (
<div className="w-full flex items-center justify-center p-4">
<Spinner className="w-5 h-5" />
</div>
)}
{!isFetchingAccounts && menuGroups.length ? (
<>
{menuGroups.map((group, index) => (
<Fragment key={group.account.authorId}>
<div
className={`w-full flex items-center px-2.5 py-2 text-input font-semibold text-text border-y border-solid border-border ${
index === 0 ? 'border-t-0 mb-1' : 'my-1'
}`}
>
<Icon type="notes" className="mr-2 text-info" /> {group.name}
</div>
{group.actions.length ? (
group.actions.map((action) => (
<ListedMenuItem
action={action}
note={note}
key={action.url}
group={group}
application={application}
reloadMenuGroup={reloadMenuGroup}
/>
))
) : (
<div className="px-3 py-2 text-sm text-passive-0 select-none">No actions available</div>
)}
</Fragment>
))}
</>
) : null}
{!isFetchingAccounts && !menuGroups.length ? (
<div className="w-full flex items-center justify-center px-4 py-6">
<div className="text-sm text-passive-0 select-none">No Listed accounts found</div>
</div>
) : null}
</>
)
}
export default ListedActionsMenu

View File

@@ -1,210 +1,17 @@
import { WebApplication } from '@/Application/Application' import { WebApplication } from '@/Application/Application'
import { calculateSubmenuStyle, SubmenuStyle } from '@/Utils/CalculateSubmenuStyle' import { calculateSubmenuStyle, SubmenuStyle } from '@/Utils/CalculateSubmenuStyle'
import { Disclosure, DisclosureButton, DisclosurePanel } from '@reach/disclosure' import { Disclosure, DisclosureButton, DisclosurePanel } from '@reach/disclosure'
import { Action, ListedAccount, SNNote } from '@standardnotes/snjs' import { SNNote } from '@standardnotes/snjs'
import { Fragment, FunctionComponent, useCallback, useEffect, useRef, useState } from 'react' import { FunctionComponent, useCallback, useEffect, useRef, useState } from 'react'
import Icon from '@/Components/Icon/Icon' import Icon from '@/Components/Icon/Icon'
import { useCloseOnBlur } from '@/Hooks/useCloseOnBlur' import { useCloseOnBlur } from '@/Hooks/useCloseOnBlur'
import ListedActionsMenu from './ListedActionsMenu'
type Props = { type Props = {
application: WebApplication application: WebApplication
note: SNNote note: SNNote
} }
type ListedMenuGroup = {
name: string
account: ListedAccount
actions: Action[]
}
type ListedMenuItemProps = {
action: Action
note: SNNote
group: ListedMenuGroup
application: WebApplication
reloadMenuGroup: (group: ListedMenuGroup) => Promise<void>
}
const ListedMenuItem: FunctionComponent<ListedMenuItemProps> = ({
action,
note,
application,
group,
reloadMenuGroup,
}) => {
const [isRunning, setIsRunning] = useState(false)
const handleClick = useCallback(async () => {
if (isRunning) {
return
}
setIsRunning(true)
await application.actionsManager.runAction(action, note)
setIsRunning(false)
reloadMenuGroup(group).catch(console.error)
}, [application, action, group, isRunning, note, reloadMenuGroup])
return (
<button
key={action.url}
onClick={handleClick}
className="sn-dropdown-item flex justify-between py-2 text-input focus:bg-info-backdrop focus:shadow-none"
>
<div className="flex flex-col">
<div className="font-semibold">{action.label}</div>
{action.access_type && (
<div className="text-xs mt-0.5 color-passive-0">
{'Uses '}
<strong>{action.access_type}</strong>
{' access to this note.'}
</div>
)}
</div>
{isRunning && <div className="sk-spinner spinner-info w-3 h-3" />}
</button>
)
}
type ListedActionsMenuProps = {
application: WebApplication
note: SNNote
recalculateMenuStyle: () => void
}
const ListedActionsMenu: FunctionComponent<ListedActionsMenuProps> = ({ application, note, recalculateMenuStyle }) => {
const [menuGroups, setMenuGroups] = useState<ListedMenuGroup[]>([])
const [isFetchingAccounts, setIsFetchingAccounts] = useState(true)
const reloadMenuGroup = useCallback(
async (group: ListedMenuGroup) => {
const updatedAccountInfo = await application.getListedAccountInfo(group.account, note.uuid)
if (!updatedAccountInfo) {
return
}
const updatedGroup: ListedMenuGroup = {
name: updatedAccountInfo.display_name,
account: group.account,
actions: updatedAccountInfo.actions as Action[],
}
const updatedGroups = menuGroups.map((group) => {
if (updatedGroup.account.authorId === group.account.authorId) {
return updatedGroup
} else {
return group
}
})
setMenuGroups(updatedGroups)
},
[application, menuGroups, note],
)
useEffect(() => {
const fetchListedAccounts = async () => {
if (!application.hasAccount()) {
setIsFetchingAccounts(false)
return
}
try {
const listedAccountEntries = await application.getListedAccounts()
if (!listedAccountEntries.length) {
throw new Error('No Listed accounts found')
}
const menuGroups: ListedMenuGroup[] = []
await Promise.all(
listedAccountEntries.map(async (account) => {
const accountInfo = await application.getListedAccountInfo(account, note.uuid)
if (accountInfo) {
menuGroups.push({
name: accountInfo.display_name,
account,
actions: accountInfo.actions as Action[],
})
} else {
menuGroups.push({
name: account.authorId,
account,
actions: [],
})
}
}),
)
setMenuGroups(
menuGroups.sort((a, b) => {
return a.name.toString().toLowerCase() < b.name.toString().toLowerCase() ? -1 : 1
}),
)
} catch (err) {
console.error(err)
} finally {
setIsFetchingAccounts(false)
setTimeout(() => {
recalculateMenuStyle()
})
}
}
void fetchListedAccounts()
}, [application, note.uuid, recalculateMenuStyle])
return (
<>
{isFetchingAccounts && (
<div className="w-full flex items-center justify-center p-4">
<div className="sk-spinner w-5 h-5 spinner-info" />
</div>
)}
{!isFetchingAccounts && menuGroups.length ? (
<>
{menuGroups.map((group, index) => (
<Fragment key={group.account.authorId}>
<div
className={`w-full flex items-center px-2.5 py-2 text-input font-semibold color-text border-0 border-y-1px border-solid border-main ${
index === 0 ? 'border-t-0 mb-1' : 'my-1'
}`}
>
<Icon type="notes" className="mr-2 color-info" /> {group.name}
</div>
{group.actions.length ? (
group.actions.map((action) => (
<ListedMenuItem
action={action}
note={note}
key={action.url}
group={group}
application={application}
reloadMenuGroup={reloadMenuGroup}
/>
))
) : (
<div className="px-3 py-2 color-passive-0 select-none">No actions available</div>
)}
</Fragment>
))}
</>
) : null}
{!isFetchingAccounts && !menuGroups.length ? (
<div className="w-full flex items-center justify-center px-4 py-6">
<div className="color-passive-0 select-none">No Listed accounts found</div>
</div>
) : null}
</>
)
}
const ListedActionsOption: FunctionComponent<Props> = ({ application, note }) => { const ListedActionsOption: FunctionComponent<Props> = ({ application, note }) => {
const menuContainerRef = useRef<HTMLDivElement>(null) const menuContainerRef = useRef<HTMLDivElement>(null)
const menuRef = useRef<HTMLDivElement>(null) const menuRef = useRef<HTMLDivElement>(null)
@@ -249,12 +56,16 @@ const ListedActionsOption: FunctionComponent<Props> = ({ application, note }) =>
return ( return (
<div ref={menuContainerRef}> <div ref={menuContainerRef}>
<Disclosure open={isMenuOpen} onChange={toggleListedMenu}> <Disclosure open={isMenuOpen} onChange={toggleListedMenu}>
<DisclosureButton ref={menuButtonRef} onBlur={closeOnBlur} className="sn-dropdown-item justify-between"> <DisclosureButton
ref={menuButtonRef}
onBlur={closeOnBlur}
className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full focus:bg-info-backdrop focus:shadow-none text-menu-item justify-between"
>
<div className="flex items-center"> <div className="flex items-center">
<Icon type="listed" className="color-neutral mr-2" /> <Icon type="listed" className="text-neutral mr-2" />
Listed actions Listed actions
</div> </div>
<Icon type="chevron-right" className="color-neutral" /> <Icon type="chevron-right" className="text-neutral" />
</DisclosureButton> </DisclosureButton>
<DisclosurePanel <DisclosurePanel
ref={menuRef} ref={menuRef}
@@ -262,7 +73,9 @@ const ListedActionsOption: FunctionComponent<Props> = ({ application, note }) =>
...menuStyle, ...menuStyle,
position: 'fixed', position: 'fixed',
}} }}
className="sn-dropdown flex flex-col max-h-120 min-w-68 pb-1 fixed overflow-y-auto" className={`${
isMenuOpen ? 'flex' : 'hidden'
} flex-col bg-default rounded shadow-main max-h-120 min-w-68 pb-1 fixed overflow-y-auto`}
> >
{isMenuOpen && ( {isMenuOpen && (
<ListedActionsMenu application={application} note={note} recalculateMenuStyle={recalculateMenuStyle} /> <ListedActionsMenu application={application} note={note} recalculateMenuStyle={recalculateMenuStyle} />

View File

@@ -0,0 +1,7 @@
import { Action, ListedAccount } from '@standardnotes/snjs'
export type ListedMenuGroup = {
name: string
account: ListedAccount
actions: Action[]
}

View File

@@ -0,0 +1,59 @@
import { WebApplication } from '@/Application/Application'
import { Action, SNNote } from '@standardnotes/snjs'
import { FunctionComponent, useCallback, useState } from 'react'
import Spinner from '@/Components/Spinner/Spinner'
import { ListedMenuGroup } from './ListedMenuGroup'
type ListedMenuItemProps = {
action: Action
note: SNNote
group: ListedMenuGroup
application: WebApplication
reloadMenuGroup: (group: ListedMenuGroup) => Promise<void>
}
const ListedMenuItem: FunctionComponent<ListedMenuItemProps> = ({
action,
note,
application,
group,
reloadMenuGroup,
}) => {
const [isRunning, setIsRunning] = useState(false)
const handleClick = useCallback(async () => {
if (isRunning) {
return
}
setIsRunning(true)
await application.actionsManager.runAction(action, note)
setIsRunning(false)
reloadMenuGroup(group).catch(console.error)
}, [application, action, group, isRunning, note, reloadMenuGroup])
return (
<button
key={action.url}
onClick={handleClick}
className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-2 text-left w-full focus:bg-info-backdrop focus:shadow-none text-sm"
>
<div className="flex flex-col">
<div className="font-semibold">{action.label}</div>
{action.access_type && (
<div className="text-xs mt-0.5 text-passive-0">
{'Uses '}
<strong>{action.access_type}</strong>
{' access to this note.'}
</div>
)}
</div>
{isRunning && <Spinner className="w-3 h-3" />}
</button>
)
}
export default ListedMenuItem

View File

@@ -11,6 +11,7 @@ import AddTagOption from './AddTagOption'
import { addToast, dismissToast, ToastType } from '@standardnotes/toast' import { addToast, dismissToast, ToastType } from '@standardnotes/toast'
import { NotesOptionsProps } from './NotesOptionsProps' import { NotesOptionsProps } from './NotesOptionsProps'
import { NotesController } from '@/Controllers/NotesController' import { NotesController } from '@/Controllers/NotesController'
import HorizontalSeparator from '../Shared/HorizontalSeparator'
type DeletePermanentlyButtonProps = { type DeletePermanentlyButtonProps = {
closeOnBlur: NotesOptionsProps['closeOnBlur'] closeOnBlur: NotesOptionsProps['closeOnBlur']
@@ -18,16 +19,20 @@ type DeletePermanentlyButtonProps = {
} }
const DeletePermanentlyButton = ({ closeOnBlur, onClick }: DeletePermanentlyButtonProps) => ( const DeletePermanentlyButton = ({ closeOnBlur, onClick }: DeletePermanentlyButtonProps) => (
<button onBlur={closeOnBlur} className="sn-dropdown-item" onClick={onClick}> <button
<Icon type="close" className="color-danger mr-2" /> onBlur={closeOnBlur}
<span className="color-danger">Delete permanently</span> className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full focus:bg-info-backdrop focus:shadow-none text-menu-item"
onClick={onClick}
>
<Icon type="close" className="text-danger mr-2" />
<span className="text-danger">Delete permanently</span>
</button> </button>
) )
const iconClass = 'color-neutral mr-2' const iconClass = 'text-neutral mr-2'
const iconClassDanger = 'color-danger mr-2' const iconClassDanger = 'text-danger mr-2'
const iconClassWarning = 'color-warning mr-2' const iconClassWarning = 'text-warning mr-2'
const iconClassSuccess = 'color-success mr-2' const iconClassSuccess = 'text-success mr-2'
const getWordCount = (text: string) => { const getWordCount = (text: string) => {
if (text.trim().length === 0) { if (text.trim().length === 0) {
@@ -96,7 +101,7 @@ const NoteAttributes: FunctionComponent<{
const format = editor?.package_info?.file_type || 'txt' const format = editor?.package_info?.file_type || 'txt'
return ( return (
<div className="px-3 pt-1.5 pb-2.5 text-xs color-neutral font-medium"> <div className="px-3 pt-1.5 pb-2.5 text-xs text-neutral font-medium">
{typeof words === 'number' && (format === 'txt' || format === 'md') ? ( {typeof words === 'number' && (format === 'txt' || format === 'md') ? (
<> <>
<div className="mb-1"> <div className="mb-1">
@@ -135,7 +140,7 @@ const SpellcheckOptions: FunctionComponent<{
return ( return (
<div className="flex flex-col"> <div className="flex flex-col">
<button <button
className="sn-dropdown-item justify-between px-3 py-1" className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1 text-left w-full focus:bg-info-backdrop focus:shadow-none text-menu-item justify-between"
onClick={() => { onClick={() => {
notesController.toggleGlobalSpellcheckForNote(note).catch(console.error) notesController.toggleGlobalSpellcheckForNote(note).catch(console.error)
}} }}
@@ -161,8 +166,8 @@ const NoteSizeWarning: FunctionComponent<{
}> = ({ note }) => { }> = ({ note }) => {
return new Blob([note.text]).size > NOTE_SIZE_WARNING_THRESHOLD ? ( return new Blob([note.text]).size > NOTE_SIZE_WARNING_THRESHOLD ? (
<div className="flex items-center px-3 py-3.5 relative bg-warning-faded"> <div className="flex items-center px-3 py-3.5 relative bg-warning-faded">
<Icon type="warning" className="color-accessory-tint-3 flex-shrink-0 mr-3" /> <Icon type="warning" className="text-accessory-tint-3 flex-shrink-0 mr-3" />
<div className="color-warning select-none leading-140% max-w-80%"> <div className="text-warning select-none leading-140% max-w-80%">
This note may have trouble syncing to the mobile application due to its size. This note may have trouble syncing to the mobile application due to its size.
</div> </div>
</div> </div>
@@ -267,15 +272,19 @@ const NotesOptions = ({
<> <>
{notes.length === 1 && ( {notes.length === 1 && (
<> <>
<button onBlur={closeOnBlur} className="sn-dropdown-item" onClick={openRevisionHistoryModal}> <button
onBlur={closeOnBlur}
className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full focus:bg-info-backdrop focus:shadow-none text-menu-item"
onClick={openRevisionHistoryModal}
>
<Icon type="history" className={iconClass} /> <Icon type="history" className={iconClass} />
Note history Note history
</button> </button>
<div className="min-h-1px my-2 bg-border"></div> <HorizontalSeparator classes="my-2" />
</> </>
)} )}
<button <button
className="sn-dropdown-item justify-between" className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full focus:bg-info-backdrop focus:shadow-none text-menu-item justify-between"
onClick={() => { onClick={() => {
notesController.setLockSelectedNotes(!locked) notesController.setLockSelectedNotes(!locked)
}} }}
@@ -288,7 +297,7 @@ const NotesOptions = ({
<Switch className="px-0" checked={locked} /> <Switch className="px-0" checked={locked} />
</button> </button>
<button <button
className="sn-dropdown-item justify-between" className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full focus:bg-info-backdrop focus:shadow-none text-menu-item justify-between"
onClick={() => { onClick={() => {
notesController.setHideSelectedNotePreviews(!hidePreviews) notesController.setHideSelectedNotePreviews(!hidePreviews)
}} }}
@@ -301,7 +310,7 @@ const NotesOptions = ({
<Switch className="px-0" checked={!hidePreviews} /> <Switch className="px-0" checked={!hidePreviews} />
</button> </button>
<button <button
className="sn-dropdown-item justify-between" className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full focus:bg-info-backdrop focus:shadow-none text-menu-item justify-between"
onClick={() => { onClick={() => {
notesController.setProtectSelectedNotes(!protect).catch(console.error) notesController.setProtectSelectedNotes(!protect).catch(console.error)
}} }}
@@ -315,11 +324,11 @@ const NotesOptions = ({
</button> </button>
{notes.length === 1 && ( {notes.length === 1 && (
<> <>
<div className="min-h-1px my-2 bg-border"></div> <HorizontalSeparator classes="my-2" />
<ChangeEditorOption application={application} note={notes[0]} /> <ChangeEditorOption application={application} note={notes[0]} />
</> </>
)} )}
<div className="min-h-1px my-2 bg-border"></div> <HorizontalSeparator classes="my-2" />
{navigationController.tagsCount > 0 && ( {navigationController.tagsCount > 0 && (
<AddTagOption <AddTagOption
navigationController={navigationController} navigationController={navigationController}
@@ -330,7 +339,7 @@ const NotesOptions = ({
{unpinned && ( {unpinned && (
<button <button
onBlur={closeOnBlur} onBlur={closeOnBlur}
className="sn-dropdown-item" className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full focus:bg-info-backdrop focus:shadow-none text-menu-item"
onClick={() => { onClick={() => {
notesController.setPinSelectedNotes(true) notesController.setPinSelectedNotes(true)
}} }}
@@ -342,7 +351,7 @@ const NotesOptions = ({
{pinned && ( {pinned && (
<button <button
onBlur={closeOnBlur} onBlur={closeOnBlur}
className="sn-dropdown-item" className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full focus:bg-info-backdrop focus:shadow-none text-menu-item"
onClick={() => { onClick={() => {
notesController.setPinSelectedNotes(false) notesController.setPinSelectedNotes(false)
}} }}
@@ -351,36 +360,44 @@ const NotesOptions = ({
Unpin Unpin
</button> </button>
)} )}
<button onBlur={closeOnBlur} className="sn-dropdown-item" onClick={downloadSelectedItems}> <button
onBlur={closeOnBlur}
className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full focus:bg-info-backdrop focus:shadow-none text-menu-item"
onClick={downloadSelectedItems}
>
<Icon type="download" className={iconClass} /> <Icon type="download" className={iconClass} />
Export Export
</button> </button>
<button onBlur={closeOnBlur} className="sn-dropdown-item" onClick={duplicateSelectedItems}> <button
onBlur={closeOnBlur}
className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full focus:bg-info-backdrop focus:shadow-none text-menu-item"
onClick={duplicateSelectedItems}
>
<Icon type="copy" className={iconClass} /> <Icon type="copy" className={iconClass} />
Duplicate Duplicate
</button> </button>
{unarchived && ( {unarchived && (
<button <button
onBlur={closeOnBlur} onBlur={closeOnBlur}
className="sn-dropdown-item" className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full focus:bg-info-backdrop focus:shadow-none text-menu-item"
onClick={() => { onClick={() => {
notesController.setArchiveSelectedNotes(true).catch(console.error) notesController.setArchiveSelectedNotes(true).catch(console.error)
}} }}
> >
<Icon type="archive" className={iconClassWarning} /> <Icon type="archive" className={iconClassWarning} />
<span className="color-warning">Archive</span> <span className="text-warning">Archive</span>
</button> </button>
)} )}
{archived && ( {archived && (
<button <button
onBlur={closeOnBlur} onBlur={closeOnBlur}
className="sn-dropdown-item" className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full focus:bg-info-backdrop focus:shadow-none text-menu-item"
onClick={() => { onClick={() => {
notesController.setArchiveSelectedNotes(false).catch(console.error) notesController.setArchiveSelectedNotes(false).catch(console.error)
}} }}
> >
<Icon type="unarchive" className={iconClassWarning} /> <Icon type="unarchive" className={iconClassWarning} />
<span className="color-warning">Unarchive</span> <span className="text-warning">Unarchive</span>
</button> </button>
)} )}
{notTrashed && {notTrashed &&
@@ -394,26 +411,26 @@ const NotesOptions = ({
) : ( ) : (
<button <button
onBlur={closeOnBlur} onBlur={closeOnBlur}
className="sn-dropdown-item" className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full focus:bg-info-backdrop focus:shadow-none text-menu-item"
onClick={async () => { onClick={async () => {
await notesController.setTrashSelectedNotes(true) await notesController.setTrashSelectedNotes(true)
}} }}
> >
<Icon type="trash" className={iconClassDanger} /> <Icon type="trash" className={iconClassDanger} />
<span className="color-danger">Move to trash</span> <span className="text-danger">Move to trash</span>
</button> </button>
))} ))}
{trashed && ( {trashed && (
<> <>
<button <button
onBlur={closeOnBlur} onBlur={closeOnBlur}
className="sn-dropdown-item" className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full focus:bg-info-backdrop focus:shadow-none text-menu-item"
onClick={async () => { onClick={async () => {
await notesController.setTrashSelectedNotes(false) await notesController.setTrashSelectedNotes(false)
}} }}
> >
<Icon type="restore" className={iconClassSuccess} /> <Icon type="restore" className={iconClassSuccess} />
<span className="color-success">Restore</span> <span className="text-success">Restore</span>
</button> </button>
<DeletePermanentlyButton <DeletePermanentlyButton
closeOnBlur={closeOnBlur} closeOnBlur={closeOnBlur}
@@ -423,15 +440,15 @@ const NotesOptions = ({
/> />
<button <button
onBlur={closeOnBlur} onBlur={closeOnBlur}
className="sn-dropdown-item" className="flex items-center border-0 cursor-pointer hover:bg-contrast hover:text-foreground text-text bg-transparent px-3 py-1.5 text-left w-full focus:bg-info-backdrop focus:shadow-none text-menu-item"
onClick={async () => { onClick={async () => {
await notesController.emptyTrash() await notesController.emptyTrash()
}} }}
> >
<div className="flex items-start"> <div className="flex items-start">
<Icon type="trash-sweep" className="color-danger mr-2" /> <Icon type="trash-sweep" className="text-danger mr-2" />
<div className="flex-row"> <div className="flex-row">
<div className="color-danger">Empty Trash</div> <div className="text-danger">Empty Trash</div>
<div className="text-xs">{notesController.trashedNotesCount} notes in Trash</div> <div className="text-xs">{notesController.trashedNotesCount} notes in Trash</div>
</div> </div>
</div> </div>
@@ -440,11 +457,11 @@ const NotesOptions = ({
)} )}
{notes.length === 1 ? ( {notes.length === 1 ? (
<> <>
<div className="min-h-1px my-2 bg-border"></div> <HorizontalSeparator classes="my-2" />
<ListedActionsOption application={application} note={notes[0]} /> <ListedActionsOption application={application} note={notes[0]} />
<div className="min-h-1px my-2 bg-border"></div> <HorizontalSeparator classes="my-2" />
<SpellcheckOptions editorForNote={editorForNote} notesController={notesController} note={notes[0]} /> <SpellcheckOptions editorForNote={editorForNote} notesController={notesController} note={notes[0]} />
<div className="min-h-1px my-2 bg-border"></div> <HorizontalSeparator classes="my-2" />
<NoteAttributes application={application} note={notes[0]} /> <NoteAttributes application={application} note={notes[0]} />
<NoteSizeWarning note={notes[0]} /> <NoteSizeWarning note={notes[0]} />
</> </>

View File

@@ -71,7 +71,7 @@ const NotesOptionsPanel = ({
}} }}
onBlur={closeOnBlur} onBlur={closeOnBlur}
ref={buttonRef} ref={buttonRef}
className="sn-icon-button border-contrast" className="flex justify-center items-center min-w-8 h-8 bg-text-padding hover:bg-contrast focus:bg-contrast text-neutral border border-solid border-border rounded-full cursor-pointer"
> >
<VisuallyHidden>Actions</VisuallyHidden> <VisuallyHidden>Actions</VisuallyHidden>
<Icon type="more" className="block" /> <Icon type="more" className="block" />
@@ -88,7 +88,9 @@ const NotesOptionsPanel = ({
...position, ...position,
maxHeight, maxHeight,
}} }}
className="sn-dropdown sn-dropdown--animated min-w-80 max-h-120 max-w-xs flex flex-col pt-2 overflow-y-auto fixed" className={`${
open ? 'flex' : 'hidden'
} flex-col min-w-80 max-h-120 max-w-xs pt-2 fixed bg-default rounded shadow-main transition-transform duration-150 slide-down-animation overflow-y-auto`}
onBlur={closeOnBlur} onBlur={closeOnBlur}
tabIndex={FOCUSABLE_BUT_NOT_TABBABLE} tabIndex={FOCUSABLE_BUT_NOT_TABBABLE}
> >

View File

@@ -3,6 +3,7 @@ import { AlertDialog, AlertDialogDescription, AlertDialogLabel } from '@reach/al
import { WebApplication } from '@/Application/Application' import { WebApplication } from '@/Application/Application'
import { ViewControllerManager } from '@/Services/ViewControllerManager' import { ViewControllerManager } from '@/Services/ViewControllerManager'
import { observer } from 'mobx-react-lite' import { observer } from 'mobx-react-lite'
import Button from '@/Components/Button/Button'
type Props = { type Props = {
application: WebApplication application: WebApplication
@@ -17,7 +18,7 @@ const ConfirmOtherSessionsSignOut = observer(({ application, viewControllerManag
}, [viewControllerManager]) }, [viewControllerManager])
return ( return (
<AlertDialog onDismiss={closeDialog} leastDestructiveRef={cancelRef}> <AlertDialog onDismiss={closeDialog} leastDestructiveRef={cancelRef} className="p-0 max-w-[600px]">
<div className="sk-modal-content"> <div className="sk-modal-content">
<div className="sn-component"> <div className="sn-component">
<div className="sk-panel"> <div className="sk-panel">
@@ -27,18 +28,21 @@ const ConfirmOtherSessionsSignOut = observer(({ application, viewControllerManag
End all other sessions? End all other sessions?
</AlertDialogLabel> </AlertDialogLabel>
<AlertDialogDescription className="sk-panel-row"> <AlertDialogDescription className="sk-panel-row">
<p className="color-foreground"> <p className="text-foreground">
This action will sign out all other devices signed into your account, and remove your data from This action will sign out all other devices signed into your account, and remove your data from
those devices when they next regain connection to the internet. You may sign back in on those those devices when they next regain connection to the internet. You may sign back in on those
devices at any time. devices at any time.
</p> </p>
</AlertDialogDescription> </AlertDialogDescription>
<div className="flex my-1 mt-4"> <div className="flex my-1 mt-4 gap-2">
<button className="sn-button small neutral" ref={cancelRef} onClick={closeDialog}> <Button primary small colorStyle="neutral" rounded={false} ref={cancelRef} onClick={closeDialog}>
Cancel Cancel
</button> </Button>
<button <Button
className="sn-button small danger ml-2" primary
small
colorStyle="danger"
rounded={false}
onClick={() => { onClick={() => {
application.revokeAllOtherSessions().catch(console.error) application.revokeAllOtherSessions().catch(console.error)
closeDialog() closeDialog()
@@ -48,7 +52,7 @@ const ConfirmOtherSessionsSignOut = observer(({ application, viewControllerManag
}} }}
> >
End Sessions End Sessions
</button> </Button>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,6 +1,8 @@
import { WebApplication } from '@/Application/Application' import { WebApplication } from '@/Application/Application'
import { ChangeEventHandler, createRef } from 'react' import { createRef } from 'react'
import { PureComponent } from '@/Components/Abstract/PureComponent' import { PureComponent } from '@/Components/Abstract/PureComponent'
import Button from '@/Components/Button/Button'
import DecoratedPasswordInput from '../Input/DecoratedPasswordInput'
interface Props { interface Props {
application: WebApplication application: WebApplication
@@ -202,21 +204,21 @@ class PasswordWizard extends PureComponent<Props, State> {
}) })
} }
handleCurrentPasswordInputChange: ChangeEventHandler<HTMLInputElement> = ({ currentTarget }) => { handleCurrentPasswordInputChange = (currentPassword: string) => {
this.setFormDataState({ this.setFormDataState({
currentPassword: currentTarget.value, currentPassword,
}).catch(console.error) }).catch(console.error)
} }
handleNewPasswordInputChange: ChangeEventHandler<HTMLInputElement> = ({ currentTarget }) => { handleNewPasswordInputChange = (newPassword: string) => {
this.setFormDataState({ this.setFormDataState({
newPassword: currentTarget.value, newPassword,
}).catch(console.error) }).catch(console.error)
} }
handleNewPasswordConfirmationInputChange: ChangeEventHandler<HTMLInputElement> = ({ currentTarget }) => { handleNewPasswordConfirmationInputChange = (newPasswordConfirmation: string) => {
this.setFormDataState({ this.setFormDataState({
newPasswordConfirmation: currentTarget.value, newPasswordConfirmation,
}).catch(console.error) }).catch(console.error)
} }
@@ -244,13 +246,12 @@ class PasswordWizard extends PureComponent<Props, State> {
Current Password Current Password
</label> </label>
<input <DecoratedPasswordInput
ref={this.currentPasswordInput} ref={this.currentPasswordInput}
id="password-wiz-current-password" id="password-wiz-current-password"
value={this.state.formData.currentPassword} value={this.state.formData.currentPassword}
onChange={this.handleCurrentPasswordInputChange} onChange={this.handleCurrentPasswordInputChange}
type="password" type="password"
className="sk-input contrast"
/> />
<div className="sk-panel-row" /> <div className="sk-panel-row" />
@@ -259,12 +260,11 @@ class PasswordWizard extends PureComponent<Props, State> {
New Password New Password
</label> </label>
<input <DecoratedPasswordInput
id="password-wiz-new-password" id="password-wiz-new-password"
value={this.state.formData.newPassword} value={this.state.formData.newPassword}
onChange={this.handleNewPasswordInputChange} onChange={this.handleNewPasswordInputChange}
type="password" type="password"
className="sk-input contrast"
/> />
<div className="sk-panel-row" /> <div className="sk-panel-row" />
@@ -272,12 +272,11 @@ class PasswordWizard extends PureComponent<Props, State> {
Confirm New Password Confirm New Password
</label> </label>
<input <DecoratedPasswordInput
id="password-wiz-confirm-new-password" id="password-wiz-confirm-new-password"
value={this.state.formData.newPasswordConfirmation} value={this.state.formData.newPasswordConfirmation}
onChange={this.handleNewPasswordConfirmationInputChange} onChange={this.handleNewPasswordConfirmationInputChange}
type="password" type="password"
className="sk-input contrast"
/> />
</form> </form>
</div> </div>
@@ -286,7 +285,7 @@ class PasswordWizard extends PureComponent<Props, State> {
)} )}
{this.state.step === Steps.FinishStep && ( {this.state.step === Steps.FinishStep && (
<div className="sk-panel-section"> <div className="sk-panel-section">
<div className="sk-label sk-bold info">Your password has been successfully changed.</div> <div className="font-bold text-info mb-1">Your password has been successfully changed.</div>
<p className="sk-p"> <p className="sk-p">
Please ensure you are running the latest version of Standard Notes on all platforms to ensure Please ensure you are running the latest version of Standard Notes on all platforms to ensure
maximum compatibility. maximum compatibility.
@@ -295,13 +294,9 @@ class PasswordWizard extends PureComponent<Props, State> {
)} )}
</div> </div>
<div className="sk-panel-footer"> <div className="sk-panel-footer">
<button <Button primary onClick={this.nextStep} disabled={this.state.lockContinue} className="min-w-20">
onClick={this.nextStep}
disabled={this.state.lockContinue}
className="sn-button min-w-20 info"
>
{this.state.continueTitle} {this.state.continueTitle}
</button> </Button>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,6 +1,11 @@
import { WebApplication } from '@/Application/Application' import { WebApplication } from '@/Application/Application'
import { SNComponent } from '@standardnotes/snjs' import { SNComponent } from '@standardnotes/snjs'
import { Component } from 'react' import { Component } from 'react'
import Button from '@/Components/Button/Button'
import ModalDialog from '../Shared/ModalDialog'
import ModalDialogLabel from '../Shared/ModalDialogLabel'
import ModalDialogDescription from '../Shared/ModalDialogDescription'
import ModalDialogButtons from '../Shared/ModalDialogButtons'
interface Props { interface Props {
application: WebApplication application: WebApplication
@@ -23,50 +28,29 @@ class PermissionsModal extends Component<Props> {
override render() { override render() {
return ( return (
<div className="sk-modal"> <ModalDialog className="w-[350px]">
<div onClick={this.deny} className="sk-modal-background" /> <ModalDialogLabel closeDialog={this.deny}>Activate Component</ModalDialogLabel>
<div id="permissions-modal" className="sk-modal-content"> <ModalDialogDescription>
<div className="sn-component"> <div className="text-base">
<div className="sk-panel"> <strong>{this.props.component.displayName}</strong>
<div className="sk-panel-header"> {' would like to interact with your '}
<div className="sk-panel-header-title">Activate Component</div> {this.props.permissionsString}
<a onClick={this.deny} className="sk-a info close-button">
Cancel
</a>
</div>
<div className="sk-panel-content">
<div className="sk-panel-section">
<div className="sk-panel-row">
<div className="sk-h2">
<strong>{this.props.component.displayName}</strong>
{' would like to interact with your '}
{this.props.permissionsString}
</div>
</div>
<div className="sk-panel-row">
<p className="sk-p">
Components use an offline messaging system to communicate. Learn more at{' '}
<a
href="https://standardnotes.com/permissions"
rel="noopener"
target="_blank"
className="sk-a info"
>
https://standardnotes.com/permissions.
</a>
</p>
</div>
</div>
</div>
<div className="sk-panel-footer">
<button onClick={this.accept} className="sn-button info block w-full text-base py-3">
Continue
</button>
</div>
</div>
</div> </div>
</div> <div className="sk-panel-row">
</div> <p className="sk-p">
Components use an offline messaging system to communicate. Learn more at{' '}
<a href="https://standardnotes.com/permissions" rel="noopener" target="_blank" className="sk-a info">
https://standardnotes.com/permissions.
</a>
</p>
</div>
</ModalDialogDescription>
<ModalDialogButtons>
<Button primary fullWidth onClick={this.accept} className="block">
Continue
</Button>
</ModalDialogButtons>
</ModalDialog>
) )
} }
} }

View File

@@ -26,7 +26,12 @@ const PinNoteButton: FunctionComponent<Props> = ({ className = '', notesControll
}, [onClickPreprocessing, pinned, notesController]) }, [onClickPreprocessing, pinned, notesController])
return ( return (
<button className={`sn-icon-button border-contrast ${pinned ? 'toggled' : ''} ${className}`} onClick={togglePinned}> <button
className={`sn-icon-button flex justify-center items-center min-w-8 h-8 hover:bg-contrast focus:bg-contrast text-neutral border border-solid border-border rounded-full cursor-pointer ${
pinned ? 'toggled' : ''
} ${className}`}
onClick={togglePinned}
>
<VisuallyHidden>Pin selected notes</VisuallyHidden> <VisuallyHidden>Pin selected notes</VisuallyHidden>
<Icon type="pin" className="block" /> <Icon type="pin" className="block" />
</button> </button>

View File

@@ -36,10 +36,10 @@ const Authentication: FunctionComponent<Props> = ({ viewControllerManager }) =>
<Text className="text-center mb-3"> <Text className="text-center mb-3">
Sign in to sync your notes and preferences across all your devices and enable end-to-end encryption. Sign in to sync your notes and preferences across all your devices and enable end-to-end encryption.
</Text> </Text>
<Button variant="primary" label="Create free account" onClick={clickRegister} className="mb-3" /> <Button primary label="Create free account" onClick={clickRegister} className="mb-3" />
<div className="text-input"> <div className="text-sm">
Already have an account?{' '} Already have an account?{' '}
<button className="border-0 p-0 bg-default color-info underline cursor-pointer" onClick={clickSignIn}> <button className="border-0 p-0 bg-default text-info underline cursor-pointer" onClick={clickSignIn}>
Sign in Sign in
</button> </button>
</div> </div>

View File

@@ -142,14 +142,14 @@ const ChangeEmail: FunctionComponent<Props> = ({ onCloseDialog, application }) =
<div> <div>
<ModalDialog> <ModalDialog>
<ModalDialogLabel closeDialog={handleDialogClose}>Change Email</ModalDialogLabel> <ModalDialogLabel closeDialog={handleDialogClose}>Change Email</ModalDialogLabel>
<ModalDialogDescription className="px-4.5"> <ModalDialogDescription className="px-4.5 flex flex-row items-center">
{currentStep === Steps.InitialStep && ( {currentStep === Steps.InitialStep && (
<ChangeEmailForm setNewEmail={setNewEmail} setCurrentPassword={setCurrentPassword} /> <ChangeEmailForm setNewEmail={setNewEmail} setCurrentPassword={setCurrentPassword} />
)} )}
{currentStep === Steps.FinishStep && <ChangeEmailSuccess />} {currentStep === Steps.FinishStep && <ChangeEmailSuccess />}
</ModalDialogDescription> </ModalDialogDescription>
<ModalDialogButtons className="px-4.5"> <ModalDialogButtons className="px-4.5">
<Button className="min-w-20" variant="primary" label={submitButtonTitle} onClick={handleSubmit} /> <Button className="min-w-20" primary label={submitButtonTitle} onClick={handleSubmit} />
</ModalDialogButtons> </ModalDialogButtons>
</ModalDialog> </ModalDialog>
</div> </div>

View File

@@ -1,3 +1,5 @@
import DecoratedInput from '@/Components/Input/DecoratedInput'
import DecoratedPasswordInput from '@/Components/Input/DecoratedPasswordInput'
import { Dispatch, SetStateAction, FunctionComponent } from 'react' import { Dispatch, SetStateAction, FunctionComponent } from 'react'
type Props = { type Props = {
@@ -7,8 +9,6 @@ type Props = {
const labelClassName = 'block mb-1' const labelClassName = 'block mb-1'
const inputClassName = 'sk-input contrast'
const ChangeEmailForm: FunctionComponent<Props> = ({ setNewEmail, setCurrentPassword }) => { const ChangeEmailForm: FunctionComponent<Props> = ({ setNewEmail, setCurrentPassword }) => {
return ( return (
<div className="w-full flex flex-col"> <div className="w-full flex flex-col">
@@ -16,12 +16,11 @@ const ChangeEmailForm: FunctionComponent<Props> = ({ setNewEmail, setCurrentPass
<label className={labelClassName} htmlFor="change-email-email-input"> <label className={labelClassName} htmlFor="change-email-email-input">
New Email: New Email:
</label> </label>
<input <DecoratedInput
id="change-email-email-input"
className={inputClassName}
type="email" type="email"
onChange={({ target }) => { id="change-email-email-input"
setNewEmail((target as HTMLInputElement).value) onChange={(newEmail) => {
setNewEmail(newEmail)
}} }}
/> />
</div> </div>
@@ -29,12 +28,11 @@ const ChangeEmailForm: FunctionComponent<Props> = ({ setNewEmail, setCurrentPass
<label className={labelClassName} htmlFor="change-email-password-input"> <label className={labelClassName} htmlFor="change-email-password-input">
Current Password: Current Password:
</label> </label>
<input <DecoratedPasswordInput
id="change-email-password-input" id="change-email-password-input"
className={inputClassName}
type="password" type="password"
onChange={({ target }) => { onChange={(currentPassword) => {
setCurrentPassword((target as HTMLInputElement).value) setCurrentPassword(currentPassword)
}} }}
/> />
</div> </div>

View File

@@ -3,8 +3,8 @@ import { FunctionComponent } from 'react'
const ChangeEmailSuccess: FunctionComponent = () => { const ChangeEmailSuccess: FunctionComponent = () => {
return ( return (
<div> <div>
<div className={'sk-label sk-bold info mt-2'}>Your email has been successfully changed.</div> <div className={'font-bold text-info mb-2'}>Your email has been successfully changed.</div>
<p className={'sk-p'}> <p>
Please ensure you are running the latest version of Standard Notes on all platforms to ensure maximum Please ensure you are running the latest version of Standard Notes on all platforms to ensure maximum
compatibility. compatibility.
</p> </p>

View File

@@ -13,10 +13,9 @@ const ClearSessionDataView: FunctionComponent<{
<PreferencesGroup> <PreferencesGroup>
<PreferencesSegment> <PreferencesSegment>
<Title>Clear workspace</Title> <Title>Clear workspace</Title>
<Text>Remove all data related to the current workspace from the application.</Text> <Text className="mb-3">Remove all data related to the current workspace from the application.</Text>
<div className="min-h-3" />
<Button <Button
dangerStyle={true} colorStyle="danger"
label="Clear workspace" label="Clear workspace"
onClick={() => { onClick={() => {
viewControllerManager.accountMenuController.setSigningOut(true) viewControllerManager.accountMenuController.setSigningOut(true)

View File

@@ -44,7 +44,6 @@ const Credentials: FunctionComponent<Props> = ({ application }: Props) => {
</Text> </Text>
<Button <Button
className="min-w-20 mt-3" className="min-w-20 mt-3"
variant="normal"
label="Change email" label="Change email"
onClick={() => { onClick={() => {
setIsChangeEmailDialogOpen(true) setIsChangeEmailDialogOpen(true)
@@ -55,7 +54,7 @@ const Credentials: FunctionComponent<Props> = ({ application }: Props) => {
<Text> <Text>
Current password was set on <span className="font-bold">{passwordCreatedOn}</span> Current password was set on <span className="font-bold">{passwordCreatedOn}</span>
</Text> </Text>
<Button className="min-w-20 mt-3" variant="normal" label="Change password" onClick={presentPasswordWizard} /> <Button className="min-w-20 mt-3" label="Change password" onClick={presentPasswordWizard} />
{isChangeEmailDialogOpen && ( {isChangeEmailDialogOpen && (
<ChangeEmail onCloseDialog={() => setIsChangeEmailDialogOpen(false)} application={application} /> <ChangeEmail onCloseDialog={() => setIsChangeEmailDialogOpen(false)} application={application} />
)} )}

Some files were not shown because too many files have changed in this diff Show More