Compare commits

...
30 changed files with 208 additions and 81 deletions
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.23.103](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-25)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.102](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-24)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.101](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-23)
**Note:** Version bump only for package @standardnotes/desktop
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@standardnotes/desktop",
"main": "./app/dist/index.js",
"version": "3.23.101",
"version": "3.23.103",
"license": "AGPL-3.0-or-later",
"author": "Standard Notes.",
"private": true,
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.31.19](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-25)
**Note:** Version bump only for package @standardnotes/mobile
## [3.31.18](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-24)
**Note:** Version bump only for package @standardnotes/mobile
## [3.31.17](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-23)
**Note:** Version bump only for package @standardnotes/mobile
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/mobile",
"version": "3.31.17",
"version": "3.31.19",
"author": "Standard Notes.",
"private": true,
"license": "AGPL-3.0-or-later",
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.3.25](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-25)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.24](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-24)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.23](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-23)
**Note:** Version bump only for package @standardnotes/releases
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/releases",
"version": "1.3.23",
"version": "1.3.25",
"license": "AGPL-3.0-or-later",
"main": "dist/releases.json",
"types": "dist/index.d.ts",
+6
View File
@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.125.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-24)
### Bug Fixes
* **snjs:** showing archived notes on trashed smart view ([#1426](https://github.com/standardnotes/app/issues/1426)) ([2c69a51](https://github.com/standardnotes/app/commit/2c69a514a8a2c3cfe713e118bb6997f21e41ebe8))
## [2.125.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-23)
**Note:** Version bump only for package @standardnotes/snjs
@@ -11,6 +11,8 @@ import {
FillItemContent,
PayloadTimestampDefaults,
NoteContent,
SmartView,
SystemViewId,
} from '@standardnotes/models'
const setupRandomUuid = () => {
@@ -179,6 +181,39 @@ describe('itemManager', () => {
const notes = itemManager.getDisplayableNotes()
expect(notes).toHaveLength(1)
})
it('viewing trashed notes smart view should include archived notes', async () => {
itemManager = createService()
const archivedNote = createNote('archived')
const trashedNote = createNote('trashed')
const archivedAndTrashedNote = createNote('archived&trashed')
await itemManager.insertItems([archivedNote, trashedNote, archivedAndTrashedNote])
await itemManager.changeItem<Models.NoteMutator>(archivedNote, (m) => {
m.archived = true
})
await itemManager.changeItem<Models.NoteMutator>(trashedNote, (m) => {
m.trashed = true
})
await itemManager.changeItem<Models.NoteMutator>(archivedAndTrashedNote, (m) => {
m.trashed = true
m.archived = true
})
itemManager.setPrimaryItemDisplayOptions({
sortBy: 'title',
sortDirection: 'asc',
includeArchived: false,
includeTrashed: false,
views: [{ uuid: SystemViewId.TrashedNotes } as jest.Mocked<SmartView>],
})
const notes = itemManager.getDisplayableNotes()
expect(notes).toHaveLength(2)
})
})
describe('tag relationships', () => {
@@ -127,20 +127,20 @@ export class ItemManager
const override: Models.FilterDisplayOptions = {}
if (options.views && options.views.find((view) => view.uuid === Models.SystemViewId.AllNotes)) {
if (options.includeArchived == undefined) {
if (options.includeArchived === undefined) {
override.includeArchived = false
}
if (options.includeTrashed == undefined) {
if (options.includeTrashed === undefined) {
override.includeTrashed = false
}
}
if (options.views && options.views.find((view) => view.uuid === Models.SystemViewId.ArchivedNotes)) {
if (options.includeTrashed == undefined) {
if (options.includeTrashed === undefined) {
override.includeTrashed = false
}
}
if (options.views && options.views.find((view) => view.uuid === Models.SystemViewId.TrashedNotes)) {
if (options.includeArchived == undefined) {
if (!options.includeArchived) {
override.includeArchived = true
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/snjs",
"version": "2.125.2",
"version": "2.125.3",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+10
View File
@@ -3,6 +3,16 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.45.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-25)
### Bug Fixes
* editor content being hidden under keyboard on mobile ([#1410](https://github.com/standardnotes/app/issues/1410)) ([520b3ad](https://github.com/standardnotes/app/commit/520b3add0f8597c79706812c4819fb23a551becc))
## [3.45.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-24)
**Note:** Version bump only for package @standardnotes/web
## [3.45.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-23)
**Note:** Version bump only for package @standardnotes/web
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/web",
"version": "3.45.5",
"version": "3.45.7",
"license": "AGPL-3.0-or-later",
"main": "dist/app.js",
"author": "Standard Notes.",
+3 -14
View File
@@ -34,18 +34,13 @@ import { ApplicationGroup } from './Application/ApplicationGroup'
import { WebOrDesktopDevice } from './Application/Device/WebOrDesktopDevice'
import { WebApplication } from './Application/Application'
import { createRoot, Root } from 'react-dom/client'
import { ElementIds } from './Constants/ElementIDs'
let keyCount = 0
const getKey = () => {
return keyCount++
}
const RootId = 'app-group-root'
const setViewportHeight = () => {
document.documentElement.style.setProperty('--viewport-height', `${window.innerHeight}px`)
}
const startApplication: StartApplication = async function startApplication(
defaultSyncServerHost: string,
device: WebOrDesktopDevice,
@@ -58,24 +53,18 @@ const startApplication: StartApplication = async function startApplication(
let root: Root
const onDestroy = () => {
const rootElement = document.getElementById(RootId) as HTMLElement
const rootElement = document.getElementById(ElementIds.RootId) as HTMLElement
root.unmount()
rootElement.remove()
window.removeEventListener('resize', setViewportHeight)
window.removeEventListener('orientationchange', setViewportHeight)
renderApp()
}
const renderApp = () => {
const rootElement = document.createElement('div')
rootElement.id = RootId
rootElement.id = ElementIds.RootId
const appendedRootNode = document.body.appendChild(rootElement)
root = createRoot(appendedRootNode)
setViewportHeight()
window.addEventListener('resize', setViewportHeight)
window.addEventListener('orientationchange', setViewportHeight)
disableIosTextFieldZoom()
root.render(
@@ -33,7 +33,7 @@ const VisibilityChangeKey = 'visibilitychange'
const MSToWaitAfterIframeLoadToAvoidFlicker = 35
const ComponentView: FunctionComponent<IProps> = ({ application, onLoad, componentViewer, requestReload }) => {
const iframeRef = useRef<HTMLIFrameElement>(null)
const iframeRef = useRef<HTMLIFrameElement | null>(null)
const [loadTimeout, setLoadTimeout] = useState<ReturnType<typeof setTimeout> | undefined>(undefined)
const [hasIssueLoading, setHasIssueLoading] = useState(false)
@@ -200,6 +200,7 @@ const ComponentView: FunctionComponent<IProps> = ({ application, onLoad, compone
{error === ComponentViewerError.MissingUrl && <UrlMissing componentName={component.displayName} />}
{component.uuid && isComponentValid && (
<iframe
className="min-h-[40rem]"
ref={iframeRef}
onLoad={onIframeLoad}
data-component-viewer-id={componentViewer.identifier}
@@ -68,8 +68,8 @@ const ContentList: FunctionComponent<Props> = ({
return (
<div
className={classNames(
'infinite-scroll overflow-y-auto overflow-x-hidden focus:shadow-none focus:outline-none',
'md:overflow-y-hidden md:hover:overflow-y-auto',
'infinite-scroll max-h-[75vh] overflow-y-auto overflow-x-hidden focus:shadow-none focus:outline-none',
'md:max-h-full md:overflow-y-hidden md:hover:overflow-y-auto',
'md:hover:[overflow-y:_overlay]',
)}
id={ElementIds.ContentList}
@@ -191,7 +191,7 @@ const ContentListView: FunctionComponent<Props> = ({
aria-label={'Notes & Files'}
ref={itemsViewPanelRef}
>
<ResponsivePaneContent paneId={AppPaneId.Items}>
<ResponsivePaneContent paneId={AppPaneId.Items} contentClassName="min-h-[85vh]">
<div id="items-title-bar" className="section-title-bar border-b border-solid border-border">
<div id="items-title-bar-container">
<input
@@ -51,7 +51,11 @@ const Navigation: FunctionComponent<Props> = ({ application }) => {
className={'sn-component section app-column w-[220px] xsm-only:!w-full sm-only:!w-full'}
ref={ref}
>
<ResponsivePaneContent paneId={AppPaneId.Navigation} contentElementId="navigation-content">
<ResponsivePaneContent
paneId={AppPaneId.Navigation}
contentElementId="navigation-content"
contentClassName="min-h-[85vh]"
>
<div className={'section-title-bar'}>
<div className="section-title-bar-header">
<div className="title text-sm">
@@ -0,0 +1,30 @@
import { classNames } from '@/Utils/ConcatenateClassNames'
import { ComponentPropsWithoutRef, ForwardedRef, forwardRef } from 'react'
// Based on: https://css-tricks.com/auto-growing-inputs-textareas/#aa-other-ideas
const AutoresizingNoteViewTextarea = forwardRef(
({ value, ...textareaProps }: ComponentPropsWithoutRef<'textarea'>, ref: ForwardedRef<HTMLTextAreaElement>) => {
return (
<div className="relative inline-grid min-h-[75vh] w-full grid-rows-1 items-stretch md:block md:flex-grow">
<pre
id="textarea-mobile-resizer"
className={classNames(
'editable font-editor break-word whitespace-pre-wrap',
'invisible [grid-area:1_/_1] md:hidden',
)}
aria-hidden
>
{value}{' '}
</pre>
<textarea
value={value}
className="editable font-editor [grid-area:1_/_1] md:h-full md:min-h-0"
{...textareaProps}
ref={ref}
></textarea>
</div>
)
},
)
export default AutoresizingNoteViewTextarea
@@ -37,6 +37,7 @@ import { reloadFont } from './FontFunctions'
import { NoteViewProps } from './NoteViewProps'
import IndicatorCircle from '../IndicatorCircle/IndicatorCircle'
import { classNames } from '@/Utils/ConcatenateClassNames'
import AutoresizingNoteViewTextarea from './AutoresizingTextarea'
const MINIMUM_STATUS_DURATION = 400
const TEXTAREA_DEBOUNCE = 100
@@ -889,7 +890,7 @@ class NoteView extends PureComponent<NoteViewProps, State> {
return (
<div aria-label="Note" className="section editor sn-component">
<div className="flex flex-grow flex-col">
<div className="flex-grow flex-col md:flex">
{this.state.noteLocked && (
<EditingDisabledBanner
onMouseLeave={() => {
@@ -1021,9 +1022,8 @@ class NoteView extends PureComponent<NoteViewProps, State> {
)}
{this.state.editorStateDidLoad && !this.state.editorComponentViewer && !this.state.textareaUnloading && (
<textarea
<AutoresizingNoteViewTextarea
autoComplete="off"
className="editable font-editor"
dir="auto"
id={ElementIds.NoteTextEditor}
onChange={this.onTextAreaChange}
@@ -1032,7 +1032,7 @@ class NoteView extends PureComponent<NoteViewProps, State> {
onFocus={this.onContentFocus}
spellCheck={this.state.spellcheck}
ref={(ref) => ref && this.onSystemEditorLoad(ref)}
></textarea>
/>
)}
{this.state.marginResizersEnabled && this.editorContentRef.current ? (
@@ -9,6 +9,8 @@ import { getPositionedPopoverStyles } from './GetPositionedPopoverStyles'
import { PopoverContentProps } from './Types'
import { getPopoverMaxHeight, getAppRect } from './Utils/Rect'
import { usePopoverCloseOnClickOutside } from './Utils/usePopoverCloseOnClickOutside'
import { fitNodeToMobileScreen } from '@/Utils'
import { useDisableBodyScrollOnMobile } from '@/Hooks/useDisableBodyScrollOnMobile'
const PositionedPopoverContent = ({
align = 'end',
@@ -49,6 +51,8 @@ const PositionedPopoverContent = ({
childPopovers,
})
useDisableBodyScrollOnMobile()
return (
<Portal>
<div
@@ -63,6 +67,7 @@ const PositionedPopoverContent = ({
}}
ref={(node) => {
setPopoverElement(node)
fitNodeToMobileScreen(node)
}}
data-popover={id}
>
@@ -4,6 +4,8 @@ import { observer } from 'mobx-react-lite'
import { PreferencesMenu } from './PreferencesMenu'
import PreferencesCanvas from './PreferencesCanvas'
import { PreferencesProps } from './PreferencesProps'
import { fitNodeToMobileScreen } from '@/Utils'
import { useDisableBodyScrollOnMobile } from '@/Hooks/useDisableBodyScrollOnMobile'
const PreferencesView: FunctionComponent<PreferencesProps> = (props) => {
const menu = useMemo(
@@ -25,8 +27,13 @@ const PreferencesView: FunctionComponent<PreferencesProps> = (props) => {
}
}, [props, menu])
useDisableBodyScrollOnMobile()
return (
<div className="absolute top-0 left-0 z-preferences flex h-full w-full flex-col bg-contrast">
<div
className="absolute top-0 left-0 z-preferences flex h-full max-h-screen w-full flex-col bg-contrast"
ref={fitNodeToMobileScreen}
>
<div className="flex w-full flex-row items-center justify-between border-b border-solid border-border bg-default px-3 py-2 md:p-3">
<div className="hidden h-8 w-8 md:block" />
<h1 className="text-base font-bold md:text-lg">Your preferences for Standard Notes</h1>
@@ -1,5 +1,5 @@
import { classNames } from '@/Utils/ConcatenateClassNames'
import { FunctionComponent } from 'react'
import { Fragment, FunctionComponent } from 'react'
type Props = {
className?: string
@@ -11,10 +11,10 @@ const ModalDialogButtons: FunctionComponent<Props> = ({ children, className }) =
<div className={classNames('flex items-center justify-end px-4 py-4', className)}>
{children != undefined && Array.isArray(children)
? children.map((child, idx, arr) => (
<>
<Fragment key={idx}>
{child}
{idx < arr.length - 1 ? <div className="min-w-3" /> : undefined}
</>
</Fragment>
))
: children}
</div>
@@ -8,4 +8,5 @@ export const ElementIds = {
NavigationColumn: 'navigation',
NoteTextEditor: 'note-text-editor',
NoteTitleEditor: 'note-title-editor',
}
RootId: 'app-group-root',
} as const
@@ -0,0 +1,27 @@
import { isMobileScreen } from '@/Utils'
import { useEffect, useRef } from 'react'
/**
* Used to disable scroll on document.body when opening popovers or preferences view
* on mobile so that user can only scroll within the popover or prefs view
*/
export const useDisableBodyScrollOnMobile = () => {
const styleElementRef = useRef<HTMLStyleElement | null>(null)
useEffect(() => {
const isMobile = isMobileScreen()
if (isMobile && !styleElementRef.current) {
const styleElement = document.createElement('style')
styleElement.textContent = 'body { overflow: hidden; }'
document.body.appendChild(styleElement)
styleElementRef.current = styleElement
}
return () => {
if (isMobile && styleElementRef.current) {
styleElementRef.current.remove()
}
}
}, [])
}
@@ -1,28 +0,0 @@
/**
* source: https://github.com/juliangruber/is-mobile
*
* (MIT)
* Copyright (c) 2013 Julian Gruber <[email protected]>
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
const mobileRE =
/(android|bb\d+|meego).+mobile|armv7l|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series[46]0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i
const tabletRE = /android|ipad|playbook|silk/i
export type Opts = {
tablet?: boolean
}
export const isMobile = (opts: Opts = {}) => {
const ua = navigator.userAgent || navigator.vendor
if (typeof ua !== 'string') {
return false
}
return mobileRE.test(ua) || (!!opts.tablet && tabletRE.test(ua))
}
+11 -2
View File
@@ -2,8 +2,6 @@ import { Platform, platformFromString } from '@standardnotes/snjs'
import { IsDesktopPlatform, IsWebPlatform } from '@/Constants/Version'
import { EMAIL_REGEX } from '../Constants/Constants'
export { isMobile } from './IsMobile'
declare const process: {
env: {
NODE_ENV: string | null | undefined
@@ -203,3 +201,14 @@ export const disableIosTextFieldZoom = () => {
addMaximumScaleToMetaViewport()
}
}
export const isMobileScreen = () => !window.matchMedia('(min-width: 768px)').matches
export const fitNodeToMobileScreen = (node: HTMLElement | null) => {
if (!node || !isMobileScreen()) {
return
}
node.style.height = `${visualViewport.height}px`
node.style.position = 'absolute'
node.style.top = `${document.documentElement.scrollTop}px`
}
@@ -1,4 +1,3 @@
export * from './ConcatenateUint8Arrays'
export * from './IsMobile'
export * from './StringUtils'
export * from './Utils'
@@ -21,7 +21,6 @@
flex-grow: 1;
.content {
height: 100%;
overflow-y: auto;
}
}
+1 -2
View File
@@ -9,6 +9,7 @@ $heading-height: 75px;
.section.editor {
display: flex;
flex-direction: column;
flex-grow: 1;
overflow-y: hidden;
background-color: var(--editor-background-color);
color: var(--editor-foreground-color);
@@ -95,8 +96,6 @@ $heading-height: 75px;
.editor-content,
#editor-content {
flex: 1;
overflow-y: hidden;
height: 100%;
display: flex;
tab-size: 2;
background-color: var(--editor-pane-background-color);
+20 -10
View File
@@ -41,8 +41,6 @@ body {
-moz-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
min-height: 100%;
height: 100%;
line-height: normal;
margin: 0;
}
@@ -107,16 +105,30 @@ p {
margin: 0;
}
html,
body,
.main-ui-view {
height: max-content;
min-height: 0;
max-height: none;
display: block;
@media screen and (min-width: 768px) {
display: flex;
flex-direction: column;
}
}
.main-ui-view {
// Fallbacks
min-height: 100vh;
height: 100vh;
// Mobile-corrected viewport height
min-height: var(--viewport-height);
height: var(--viewport-height);
position: relative;
overflow: auto;
background-color: var(--editor-header-bar-background-color);
@media screen and (min-width: 768px) {
min-height: 100vh;
height: 100vh;
}
}
$footer-height: 2rem;
@@ -139,8 +151,6 @@ $footer-height: 2rem;
.section {
padding-bottom: 0px;
height: 100%;
max-height: calc(100vh - #{$footer-height});
position: relative;
overflow: hidden;