Compare commits

...
Author SHA1 Message Date
StandardNotes CI a780fa4e87 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected]
2022-08-22 10:04:58 +00:00
StandardNotes CI becbe34233 chore(release): components 2022-08-22 10:04:37 +00:00
Vardan Hakobyan 2a976a0de4 fix: trigger the onChange event of qr code uploading input when clicking on the button (#1421) 2022-08-22 13:22:22 +04:00
StandardNotes CI e7acbd7de8 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
2022-08-18 07:28:47 +00:00
Aman Harwara 779596b9ae fix: hidden file input being clickable (#1414) 2022-08-18 12:30:30 +05:30
StandardNotes CI b1f23d6076 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
2022-08-17 15:16:44 +00:00
Aman Harwara 818c3066cc fix: context menu on longpress on ios safari (#1405) 2022-08-17 20:20:18 +05:30
StandardNotes CI 13343c9a56 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
2022-08-17 14:09:08 +00:00
Aman Harwara 3d1dc8f38a feat: move search bar back to notes column (#1408) 2022-08-17 19:12:40 +05:30
StandardNotes CI 163cc8ce8a chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].7
2022-08-17 12:06:07 +00:00
Vardan Hakobyan a25923f084 fix: remove tablet specific responsive UI (#1411)
* fix: revert tablet responsiveness UI

* fix: don't let the "Saving..." text container hide the note title on tablets

* chore: better visibility of css classes list

* fix: fixed width of notes container column on Tablets
2022-08-17 15:39:56 +04:00
StandardNotes CI f14f105703 chore(release): publish
- @standardnotes/[email protected]
2022-08-17 11:33:50 +00:00
Karol Sójko 6d7bcd7a8d feat(docs): remove matomo in favour of plausible 2022-08-17 13:05:07 +02:00
Karol Sójko da06f293e0 chore(deps): remove reviewers assignment from dependabot to avoid noise 2022-08-17 10:08:54 +02:00
StandardNotes CI ec4dc1d477 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].6
2022-08-16 09:42:00 +00:00
Aman Harwara 2ea9f862fe fix: note tag delete button not showing on iOS (#1403) 2022-08-16 14:40:03 +05:30
StandardNotes CI 901b1516d3 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].9
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].5
2022-08-15 13:15:07 +00:00
Aman Harwara 54ae4365a3 fix: selecting from "Photo Library" on iOS doesn't upload (#1401) 2022-08-15 18:13:29 +05:30
StandardNotes CI 5b910d4ae4 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].8
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].4
2022-08-11 20:06:21 +00:00
Aman Harwara 40d9392599 fix: optimize toasts for mobile (#1392) 2022-08-12 01:07:23 +05:30
StandardNotes CI a7dfeae650 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].7
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].3
2022-08-10 13:30:36 +00:00
Aman Harwara 77cbb6b06e fix: tags being dimmed on safari (#1389) 2022-08-10 18:34:05 +05:30
Aman Harwara 82a8bcc440 fix: tag context menu button opening notes list veiw (#1390) 2022-08-10 18:13:29 +05:30
53 changed files with 715 additions and 504 deletions
-69
View File
@@ -9,182 +9,113 @@ updates:
directory: "/"
schedule:
interval: "daily"
reviewers:
- "moughxyz"
- "karolsojko"
- package-ecosystem: "npm"
directory: "/packages/api"
schedule:
interval: "daily"
reviewers:
- "moughxyz"
- "karolsojko"
- package-ecosystem: "npm"
directory: "/packages/components"
schedule:
interval: "daily"
reviewers:
- "moughxyz"
- "karolsojko"
- package-ecosystem: "npm"
directory: "/packages/desktop"
schedule:
interval: "daily"
reviewers:
- "moughxyz"
- "karolsojko"
- package-ecosystem: "npm"
directory: "/packages/docs"
schedule:
interval: "daily"
reviewers:
- "moughxyz"
- "karolsojko"
- package-ecosystem: "npm"
directory: "/packages/encryption"
schedule:
interval: "daily"
reviewers:
- "moughxyz"
- "karolsojko"
- package-ecosystem: "npm"
directory: "/packages/features"
schedule:
interval: "daily"
reviewers:
- "moughxyz"
- "karolsojko"
- package-ecosystem: "npm"
directory: "/packages/filepicker"
schedule:
interval: "daily"
reviewers:
- "moughxyz"
- "karolsojko"
- package-ecosystem: "npm"
directory: "/packages/files"
schedule:
interval: "daily"
reviewers:
- "moughxyz"
- "karolsojko"
- package-ecosystem: "npm"
directory: "/packages/icons"
schedule:
interval: "daily"
reviewers:
- "moughxyz"
- "karolsojko"
- package-ecosystem: "npm"
directory: "/packages/mobile"
schedule:
interval: "daily"
reviewers:
- "moughxyz"
- "karolsojko"
- package-ecosystem: "npm"
directory: "/packages/models"
schedule:
interval: "daily"
reviewers:
- "moughxyz"
- "karolsojko"
- package-ecosystem: "npm"
directory: "/packages/releases"
schedule:
interval: "daily"
reviewers:
- "moughxyz"
- "karolsojko"
- package-ecosystem: "npm"
directory: "/packages/responses"
schedule:
interval: "daily"
reviewers:
- "moughxyz"
- "karolsojko"
- package-ecosystem: "npm"
directory: "/packages/services"
schedule:
interval: "daily"
reviewers:
- "moughxyz"
- "karolsojko"
- package-ecosystem: "npm"
directory: "/packages/sncrypto-common"
schedule:
interval: "daily"
reviewers:
- "moughxyz"
- "karolsojko"
- package-ecosystem: "npm"
directory: "/packages/sncrypto-web"
schedule:
interval: "daily"
reviewers:
- "moughxyz"
- "karolsojko"
- package-ecosystem: "npm"
directory: "/packages/snjs"
schedule:
interval: "daily"
reviewers:
- "moughxyz"
- "karolsojko"
- package-ecosystem: "npm"
directory: "/packages/styles"
schedule:
interval: "daily"
reviewers:
- "moughxyz"
- "karolsojko"
- package-ecosystem: "npm"
directory: "/packages/toast"
schedule:
interval: "daily"
reviewers:
- "moughxyz"
- "karolsojko"
- package-ecosystem: "npm"
directory: "/packages/utils"
schedule:
interval: "daily"
reviewers:
- "moughxyz"
- "karolsojko"
- package-ecosystem: "npm"
directory: "/packages/web"
schedule:
interval: "daily"
reviewers:
- "moughxyz"
- "karolsojko"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
reviewers:
- "moughxyz"
- "karolsojko"
+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.7.8](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-22)
### Bug Fixes
* trigger the `onChange` event of qr code uploading input when clicking on the button ([#1421](https://github.com/standardnotes/app/issues/1421)) ([2a976a0](https://github.com/standardnotes/app/commit/2a976a0de499ba33186a52a6bd2c10a709b86fee))
## [2.7.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-07-14)
### Bug Fixes
File diff suppressed because one or more lines are too long
+3 -3
View File
@@ -80,9 +80,9 @@
"binary": "7c6f499b8107f80ec5fd84e591c2c33291d1fc6db85f098df4f8308a0cda901d"
},
"org.standardnotes.token-vault": {
"version": "2.2.3",
"base64": "bf5c3a2aae3f119043ee744ab5535de4705eeed67d5ecf9e1d7b95817f92bc19",
"binary": "8ef8a1eaf19d22b0ac279ad0c4d27b29c057b0f9b0d5c5f4cd6183eb506feaa3"
"version": "2.2.4",
"base64": "fb004e8cae73b351fdb225ef910102a1b7c9b616b92de52f99d2c82d7b4dd5a1",
"binary": "9b00f950c868e20e059a5fe7dbd0dd14eac5d94b31817b8bf3c58c88ab5ce236"
},
"org.standardnotes.standard-sheets": {
"version": "1.5.1",
Binary file not shown.
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/components-meta",
"version": "2.7.7",
"version": "2.7.8",
"private": true,
"author": "Standard Notes.",
"main": "dist",
@@ -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.2.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-22)
### Bug Fixes
* trigger the `onChange` event of qr code uploading input when clicking on the button ([#1421](https://github.com/standardnotes/app/issues/1421)) ([2a976a0](https://github.com/standardnotes/app/commit/2a976a0de499ba33186a52a6bd2c10a709b86fee))
## [2.2.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-07-13)
**Note:** Version bump only for package @standardnotes/authenticator
@@ -28,6 +28,12 @@ const convertToGrayScale = (imageData) => {
}
export default class QRCodeReader extends React.Component {
constructor() {
super()
this.fileInputRef = React.createRef(null)
}
onImageSelected = (evt) => {
const file = evt.target.files[0]
const url = URL.createObjectURL(file)
@@ -70,9 +76,9 @@ export default class QRCodeReader extends React.Component {
render() {
return (
<div className="qr-code-reader-container">
<div className="sk-button info">
<div className="sk-button info" onClick={() => this.fileInputRef.current.click()}>
<div className="sk-label">Upload QR Code</div>
<input type="file" style={{ display: 'none' }} onChange={this.onImageSelected} />
<input type="file" style={{ display: 'none' }} ref={this.fileInputRef} onChange={this.onImageSelected} />
</div>
</div>
)
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/authenticator",
"version": "2.2.3",
"version": "2.2.4",
"main": "dist/dist.js",
"author": "Standard Notes",
"private": true,
+36
View File
@@ -3,6 +3,42 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.23.99](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-22)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.98](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-18)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.97](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-17)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.96](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-17)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.95](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-17)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.94](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-16)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.93](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-15)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.92](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-11)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.91](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-10)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.90](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-09)
**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.90",
"version": "3.23.99",
"license": "AGPL-3.0-or-later",
"author": "Standard Notes.",
"private": true,
+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.
# [0.2.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-17)
### Features
* **docs:** remove matomo in favour of plausible ([6d7bcd7](https://github.com/standardnotes/app/commit/6d7bcd7a8d2dfffb6dc69899406af57e41c071df))
# [0.1.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-07-11)
### Features
-1
View File
@@ -44,7 +44,6 @@ docs
│ ├── katex
│ ├── .nojekyll
│ ├── CNAME
│ └── matomo.js
├── .gitignore
├── .prettierrc
├── docusaurus.config.js
+2 -2
View File
@@ -156,8 +156,8 @@ module.exports = {
],
scripts: [
{
src: `/matomo.js`,
async: true,
src: 'https://plausible.standardnotes.com/js/plausible.js',
"data-domain": 'docs.standardnotes.com',
defer: true,
},
],
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/docs",
"version": "0.1.0",
"version": "0.2.0",
"license": "AGPL-3.0-or-later",
"author": "Standard Notes.",
"private": true,
-11
View File
@@ -1,11 +0,0 @@
var _paq = window._paq || [];
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="//matomo.standardnotes.org/";
_paq.push(['setTrackerUrl', u+'matomo.php']);
_paq.push(['setSiteId', '7']);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
})();
+36
View File
@@ -3,6 +3,42 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.31.15](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-22)
**Note:** Version bump only for package @standardnotes/mobile
## [3.31.14](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-18)
**Note:** Version bump only for package @standardnotes/mobile
## [3.31.13](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-17)
**Note:** Version bump only for package @standardnotes/mobile
## [3.31.12](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-17)
**Note:** Version bump only for package @standardnotes/mobile
## [3.31.11](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-17)
**Note:** Version bump only for package @standardnotes/mobile
## [3.31.10](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-16)
**Note:** Version bump only for package @standardnotes/mobile
## [3.31.9](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-15)
**Note:** Version bump only for package @standardnotes/mobile
## [3.31.8](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-11)
**Note:** Version bump only for package @standardnotes/mobile
## [3.31.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-10)
**Note:** Version bump only for package @standardnotes/mobile
## [3.31.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-09)
**Note:** Version bump only for package @standardnotes/mobile
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/mobile",
"version": "3.31.6",
"version": "3.31.15",
"author": "Standard Notes.",
"private": true,
"license": "AGPL-3.0-or-later",
+36
View File
@@ -3,6 +3,42 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.3.21](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-22)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.20](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-18)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.19](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-17)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.18](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-17)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.17](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-17)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.16](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-16)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.15](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-15)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.14](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-11)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.13](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-10)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.12](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-09)
**Note:** Version bump only for package @standardnotes/releases
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/releases",
"version": "1.3.12",
"version": "1.3.21",
"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.
## [1.3.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-11)
### Bug Fixes
* optimize toasts for mobile ([#1392](https://github.com/standardnotes/app/issues/1392)) ([40d9392](https://github.com/standardnotes/app/commit/40d9392599e871225abcabcddd51de6cc99a0fe9))
## [1.3.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-07-14)
**Note:** Version bump only for package @standardnotes/toast
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/toast",
"version": "1.3.4",
"version": "1.3.5",
"private": true,
"main": "./src/index.ts",
"scripts": {
+16 -16
View File
@@ -12,20 +12,20 @@ const prefersReducedMotion = () => {
const colorForToastType = (type: ToastType) => {
switch (type) {
case ToastType.Success:
return 'text-success'
return 'bg-success text-info-contrast md:text-success'
case ToastType.Error:
return 'text-danger'
return 'bg-danger text-info-contrast md:text-danger'
default:
return 'text-info'
return 'bg-info text-info-contrast md:text-info'
}
}
const iconForToastType = (type: ToastType) => {
switch (type) {
case ToastType.Success:
return <CheckCircleFilledIcon className={`h-5 w-5 ${colorForToastType(type)}`} />
return <CheckCircleFilledIcon className="text-success h-5 w-5" />
case ToastType.Error:
return <ClearCircleFilledIcon className={`h-5 w-5 ${colorForToastType(type)}`} />
return <ClearCircleFilledIcon className="text-danger h-5 w-5" />
case ToastType.Progress:
case ToastType.Loading:
return <div className="border-info h-4 w-4 animate-spin rounded-full border border-solid border-r-transparent" />
@@ -77,7 +77,7 @@ export const Toast = forwardRef(({ toast, index }: Props, ref: ForwardedRef<HTML
<div
data-index={index}
role="status"
className={`bg-passive-5 animation-fill-forwards relative mt-3 flex min-w-max select-none flex-col rounded opacity-0 ${currentAnimation}`}
className={`bg-passive-5 animation-fill-forwards relative mt-3 flex min-w-full select-none flex-col rounded opacity-0 md:min-w-max ${currentAnimation}`}
style={{
boxShadow: '0px 4px 12px rgba(0, 0, 0, 0.16)',
transition: shouldReduceMotion ? undefined : 'all 0.2s ease',
@@ -90,18 +90,18 @@ export const Toast = forwardRef(({ toast, index }: Props, ref: ForwardedRef<HTML
}}
ref={ref}
>
<div className={`flex w-full items-center ${hasActions ? 'p-2 pl-3' : hasProgress ? 'px-3 py-2.5' : 'p-3'}`}>
{icon ? <div className="sn-icon mr-2 flex flex-shrink-0 items-center justify-center">{icon}</div> : null}
<div className="text-text text-sm">{toast.message}</div>
<div
className={`flex w-full flex-wrap items-center gap-2 ${
hasActions ? 'p-2 pl-3' : hasProgress ? 'px-3 py-2.5' : 'p-3'
}`}
>
{icon ? <div className="sn-icon flex flex-shrink-0 items-center justify-center">{icon}</div> : null}
<div className="text-text text-sm [word-wrap:anywhere]">{toast.message}</div>
{hasActions && (
<div className="ml-4">
<>
{toast.actions?.map((action, index) => (
<button
style={{
paddingLeft: '0.45rem',
paddingRight: '0.45rem',
}}
className={`hover:bg-passive-3 cursor-pointer rounded border-0 bg-transparent py-1 text-sm font-semibold ${colorForToastType(
className={`hover:bg-passive-3 cursor-pointer rounded border-0 py-1 px-[0.45rem] text-sm font-semibold md:bg-transparent ${colorForToastType(
toast.type,
)} ${index !== 0 ? 'ml-2' : ''}`}
onClick={() => {
@@ -112,7 +112,7 @@ export const Toast = forwardRef(({ toast, index }: Props, ref: ForwardedRef<HTML
{action.label}
</button>
))}
</div>
</>
)}
</div>
{hasProgress && (
+1 -1
View File
@@ -11,7 +11,7 @@ export const ToastContainer: FunctionComponent = () => {
}
return (
<div className="z-toast fixed bottom-6 right-6 flex flex-col items-end">
<div className="z-toast fixed bottom-6 right-6 flex w-[calc(100%-3rem)] flex-col items-end md:w-auto">
{toasts.map((toast, index) => (
<ToastTimer toast={toast} index={index} key={toast.id} />
))}
-11
View File
@@ -55,14 +55,6 @@ export const ToastTimer: FunctionComponent<Props> = ({ toast, index }) => {
resumeTimer()
}, [resumeTimer])
const handlePageVisibility = useCallback(() => {
if (document.visibilityState === 'hidden') {
pauseTimer()
} else {
resumeTimer()
}
}, [pauseTimer, resumeTimer])
const handlePageFocus = useCallback(() => {
resumeTimer()
}, [resumeTimer])
@@ -83,7 +75,6 @@ export const ToastTimer: FunctionComponent<Props> = ({ toast, index }) => {
toastElement.addEventListener('mouseenter', handleMouseEnter)
toastElement.addEventListener('mouseleave', handleMouseLeave)
}
document.addEventListener('visibilitychange', handlePageVisibility)
window.addEventListener('focus', handlePageFocus)
window.addEventListener('blur', handlePageBlur)
@@ -93,7 +84,6 @@ export const ToastTimer: FunctionComponent<Props> = ({ toast, index }) => {
toastElement.removeEventListener('mouseenter', handleMouseEnter)
toastElement.removeEventListener('mouseleave', handleMouseLeave)
}
document.removeEventListener('visibilitychange', handlePageVisibility)
window.removeEventListener('focus', handlePageFocus)
window.removeEventListener('blur', handlePageBlur)
}
@@ -105,7 +95,6 @@ export const ToastTimer: FunctionComponent<Props> = ({ toast, index }) => {
handleMouseLeave,
handlePageBlur,
handlePageFocus,
handlePageVisibility,
resumeTimer,
shouldAutoClose,
toast.id,
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.1.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-11)
**Note:** Version bump only for package @standardnotes/ui-services
# 1.1.0 (2022-08-05)
### Bug Fixes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/ui-services",
"version": "1.1.0",
"version": "1.1.1",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+53
View File
@@ -3,6 +3,59 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.45.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-22)
**Note:** Version bump only for package @standardnotes/web
## [3.45.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-18)
### Bug Fixes
* hidden file input being clickable ([#1414](https://github.com/standardnotes/app/issues/1414)) ([779596b](https://github.com/standardnotes/app/commit/779596b9ae2df7d70dac9cdd17c85647d85e16b2))
## [3.45.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-17)
### Bug Fixes
* context menu on longpress on ios safari ([#1405](https://github.com/standardnotes/app/issues/1405)) ([818c306](https://github.com/standardnotes/app/commit/818c3066ccd92156dfc8c797074672cfb08de7bd))
# [3.45.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-17)
### Features
* move search bar back to notes column ([#1408](https://github.com/standardnotes/app/issues/1408)) ([3d1dc8f](https://github.com/standardnotes/app/commit/3d1dc8f38a883685b6c107bece2e75afe8119bf5))
## [3.44.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-17)
### Bug Fixes
* remove tablet specific responsive UI ([#1411](https://github.com/standardnotes/app/issues/1411)) ([a25923f](https://github.com/standardnotes/app/commit/a25923f0843bfa18e21883a040f95636f23e45ab))
## [3.44.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-16)
### Bug Fixes
* note tag delete button not showing on iOS ([#1403](https://github.com/standardnotes/app/issues/1403)) ([2ea9f86](https://github.com/standardnotes/app/commit/2ea9f862feb77a826af8b6ccf7cc2de1a1e50733))
## [3.44.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-15)
### Bug Fixes
* selecting from "Photo Library" on iOS doesn't upload ([#1401](https://github.com/standardnotes/app/issues/1401)) ([54ae436](https://github.com/standardnotes/app/commit/54ae4365a344cc3c6c796a3afb6d3020f5493a6b))
## [3.44.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-11)
### Bug Fixes
* optimize toasts for mobile ([#1392](https://github.com/standardnotes/app/issues/1392)) ([40d9392](https://github.com/standardnotes/app/commit/40d9392599e871225abcabcddd51de6cc99a0fe9))
## [3.44.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-10)
### Bug Fixes
* tag context menu button opening notes list veiw ([#1390](https://github.com/standardnotes/app/issues/1390)) ([82a8bcc](https://github.com/standardnotes/app/commit/82a8bcc4407fce2e255b06a0c31c5fd244f5973f))
* tags being dimmed on safari ([#1389](https://github.com/standardnotes/app/issues/1389)) ([77cbb6b](https://github.com/standardnotes/app/commit/77cbb6b06e901de9e0eccee98219f946b014fe21))
## [3.44.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-09)
### Bug Fixes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/web",
"version": "3.44.2",
"version": "3.45.3",
"license": "AGPL-3.0-or-later",
"main": "dist/app.js",
"author": "Standard Notes.",
@@ -194,6 +194,7 @@ const ApplicationView: FunctionComponent<Props> = ({ application, mainApplicatio
noteTagsController={viewControllerManager.noteTagsController}
notesController={viewControllerManager.notesController}
selectionController={viewControllerManager.selectionController}
searchOptionsController={viewControllerManager.searchOptionsController}
/>
<NoteGroupView application={application} />
</ResponsivePaneProvider>
@@ -10,6 +10,7 @@ import PopoverFileItem from './PopoverFileItem'
import { PopoverFileItemActionType } from './PopoverFileItemAction'
import { PopoverTabs } from './PopoverTabs'
import { FilesController } from '@/Controllers/FilesController'
import { StreamingFileReader } from '@standardnotes/filepicker'
type Props = {
application: WebApplication
@@ -32,6 +33,8 @@ const AttachedFilesPopover: FunctionComponent<Props> = ({
setCurrentTab,
attachedTabDisabled,
}) => {
const fileInputRef = useRef<HTMLInputElement>(null)
const [searchQuery, setSearchQuery] = useState('')
const searchInputRef = useRef<HTMLInputElement>(null)
@@ -42,13 +45,9 @@ const AttachedFilesPopover: FunctionComponent<Props> = ({
? filesList.filter((file) => file.name.toLowerCase().indexOf(searchQuery.toLowerCase()) !== -1)
: filesList
const handleAttachFilesClick = async () => {
const uploadedFiles = await filesController.uploadNewFile()
if (!uploadedFiles) {
return
}
const attachFilesIfRequired = (files: FileItem[]) => {
if (currentTab === PopoverTabs.AttachedFiles) {
uploadedFiles.forEach((file) => {
files.forEach((file) => {
filesController
.handleFileAction({
type: PopoverFileItemActionType.AttachFileToNote,
@@ -59,6 +58,19 @@ const AttachedFilesPopover: FunctionComponent<Props> = ({
}
}
const handleAttachFilesClick = async () => {
if (!StreamingFileReader.available()) {
fileInputRef.current?.click()
return
}
const uploadedFiles = await filesController.uploadNewFile()
if (!uploadedFiles) {
return
}
attachFilesIfRequired(uploadedFiles)
}
const previewHandler = (file: FileItem) => {
filesController
.handleFileAction({
@@ -161,6 +173,26 @@ const AttachedFilesPopover: FunctionComponent<Props> = ({
</div>
)}
</div>
<input
type="file"
className="absolute top-0 left-0 -z-50 h-px w-px opacity-0"
multiple
ref={fileInputRef}
onChange={async (event) => {
const files = event.currentTarget.files
if (!files) {
return
}
for (const file of files) {
const uploadedFiles = await filesController.uploadNewFile(file)
if (uploadedFiles) {
attachFilesIfRequired(uploadedFiles)
}
}
}}
/>
{filteredList.length > 0 && (
<button
className="flex w-full cursor-pointer items-center border-0 border-t border-solid border-border bg-transparent px-3 py-3 text-left text-sm text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none"
@@ -20,6 +20,10 @@ import ContentListHeader from './Header/ContentListHeader'
import ResponsivePaneContent from '../ResponsivePane/ResponsivePaneContent'
import { AppPaneId } from '../ResponsivePane/AppPaneMetadata'
import { useResponsiveAppPane } from '../ResponsivePane/ResponsivePaneProvider'
import { StreamingFileReader } from '@standardnotes/filepicker'
import SearchBar from '../SearchBar/SearchBar'
import { SearchOptionsController } from '@/Controllers/SearchOptionsController'
import { classNames } from '@/Utils/ConcatenateClassNames'
type Props = {
accountMenuController: AccountMenuController
@@ -31,6 +35,7 @@ type Props = {
noteTagsController: NoteTagsController
notesController: NotesController
selectionController: SelectedItemsController
searchOptionsController: SearchOptionsController
}
const ContentListView: FunctionComponent<Props> = ({
@@ -43,9 +48,11 @@ const ContentListView: FunctionComponent<Props> = ({
noteTagsController,
notesController,
selectionController,
searchOptionsController,
}) => {
const { toggleAppPane } = useResponsiveAppPane()
const fileInputRef = useRef<HTMLInputElement>(null)
const itemsViewPanelRef = useRef<HTMLDivElement>(null)
const {
@@ -68,7 +75,12 @@ const ContentListView: FunctionComponent<Props> = ({
const addNewItem = useCallback(async () => {
if (isFilesSmartView) {
void filesController.uploadNewFile()
if (StreamingFileReader.available()) {
void filesController.uploadNewFile()
return
}
fileInputRef.current?.click()
} else {
await createNewNote()
toggleAppPane(AppPaneId.Editor)
@@ -172,13 +184,33 @@ const ContentListView: FunctionComponent<Props> = ({
return (
<div
id="items-column"
className="sn-component section app-column flex flex-col border-b border-solid border-border xl:w-87.5 xsm-only:!w-full sm-only:!w-full md-only:!w-52 lg-only:!w-52"
className={classNames(
'sn-component section app-column flex flex-col border-b border-solid border-border ',
'xl:w-87.5 xsm-only:!w-full sm-only:!w-full md-only:!w-52 lg-only:!w-52',
)}
aria-label={'Notes & Files'}
ref={itemsViewPanelRef}
>
<ResponsivePaneContent paneId={AppPaneId.Items}>
<div id="items-title-bar" className="section-title-bar border-b border-solid border-border">
<div id="items-title-bar-container">
<input
type="file"
className="absolute top-0 left-0 -z-50 h-px w-px opacity-0"
multiple
ref={fileInputRef}
onChange={(event) => {
const files = event.currentTarget.files
if (!files) {
return
}
for (const file of files) {
void filesController.uploadNewFile(file)
}
}}
/>
<ContentListHeader
application={application}
panelTitle={panelTitle}
@@ -187,6 +219,7 @@ const ContentListView: FunctionComponent<Props> = ({
isFilesSmartView={isFilesSmartView}
optionsSubtitle={optionsSubtitle}
/>
<SearchBar itemListController={itemListController} searchOptionsController={searchOptionsController} />
<NoAccountWarning
accountMenuController={accountMenuController}
noAccountWarningController={noAccountWarningController}
@@ -1,6 +1,6 @@
import { FileItem } from '@standardnotes/snjs'
import { observer } from 'mobx-react-lite'
import { FunctionComponent, useCallback } from 'react'
import { FunctionComponent, useCallback, useRef } from 'react'
import { getFileIconComponent } from '../AttachedFilesPopover/getFileIconComponent'
import ListItemConflictIndicator from './ListItemConflictIndicator'
import ListItemFlagIcons from './ListItemFlagIcons'
@@ -9,6 +9,7 @@ import ListItemMetadata from './ListItemMetadata'
import { DisplayableListItemProps } from './Types/DisplayableListItemProps'
import { useResponsiveAppPane } from '../ResponsivePane/ResponsivePaneProvider'
import { AppPaneId } from '../ResponsivePane/AppPaneMetadata'
import { useContextMenuEvent } from '@/Hooks/useContextMenuEvent'
const FileListItem: FunctionComponent<DisplayableListItemProps> = ({
application,
@@ -24,8 +25,11 @@ const FileListItem: FunctionComponent<DisplayableListItemProps> = ({
}) => {
const { toggleAppPane } = useResponsiveAppPane()
const listItemRef = useRef<HTMLDivElement>(null)
const openFileContextMenu = useCallback(
(posX: number, posY: number) => {
filesController.setShowFileContextMenu(false)
filesController.setFileContextMenuLocation({
x: posX,
y: posY,
@@ -66,17 +70,16 @@ const FileListItem: FunctionComponent<DisplayableListItemProps> = ({
'w-5 h-5 flex-shrink-0',
)
useContextMenuEvent(listItemRef, openContextMenu)
return (
<div
ref={listItemRef}
className={`content-list-item flex w-full cursor-pointer items-stretch text-text ${
selected && 'selected border-l-2px border-solid border-info'
}`}
id={item.uuid}
onClick={onClick}
onContextMenu={(event) => {
event.preventDefault()
void openContextMenu(event.clientX, event.clientY)
}}
>
{!hideIcon ? (
<div className="mr-0 flex flex-col items-center justify-between p-4.5 pr-3">
@@ -1,7 +1,7 @@
import { PLAIN_EDITOR_NAME } from '@/Constants/Constants'
import { sanitizeHtmlString, SNNote } from '@standardnotes/snjs'
import { observer } from 'mobx-react-lite'
import { FunctionComponent, useCallback } from 'react'
import { FunctionComponent, useCallback, useRef } from 'react'
import Icon from '@/Components/Icon/Icon'
import ListItemConflictIndicator from './ListItemConflictIndicator'
import ListItemFlagIcons from './ListItemFlagIcons'
@@ -10,6 +10,7 @@ import ListItemMetadata from './ListItemMetadata'
import { DisplayableListItemProps } from './Types/DisplayableListItemProps'
import { useResponsiveAppPane } from '../ResponsivePane/ResponsivePaneProvider'
import { AppPaneId } from '../ResponsivePane/AppPaneMetadata'
import { useContextMenuEvent } from '@/Hooks/useContextMenuEvent'
const NoteListItem: FunctionComponent<DisplayableListItemProps> = ({
application,
@@ -26,12 +27,15 @@ const NoteListItem: FunctionComponent<DisplayableListItemProps> = ({
}) => {
const { toggleAppPane } = useResponsiveAppPane()
const listItemRef = useRef<HTMLDivElement>(null)
const editorForNote = application.componentManager.editorForNote(item as SNNote)
const editorName = editorForNote?.name ?? PLAIN_EDITOR_NAME
const [icon, tint] = application.iconsController.getIconAndTintForNoteType(editorForNote?.package_info.note_type)
const hasFiles = application.items.getFilesForNote(item as SNNote).length > 0
const openNoteContextMenu = (posX: number, posY: number) => {
notesController.setContextMenuOpen(false)
notesController.setContextMenuClickLocation({
x: posX,
y: posY,
@@ -62,17 +66,16 @@ const NoteListItem: FunctionComponent<DisplayableListItemProps> = ({
}
}, [item.uuid, selectionController, toggleAppPane])
useContextMenuEvent(listItemRef, openContextMenu)
return (
<div
ref={listItemRef}
className={`content-list-item flex w-full cursor-pointer items-stretch text-text ${
selected && 'selected border-l-2 border-solid border-info'
}`}
id={item.uuid}
onClick={onClick}
onContextMenu={(event) => {
event.preventDefault()
void openContextMenu(event.clientX, event.clientY)
}}
>
{!hideIcon ? (
<div className="mr-0 flex flex-col items-center justify-between p-4 pr-4">
@@ -6,11 +6,9 @@ import { ApplicationEvent, PrefKey } from '@standardnotes/snjs'
import { observer } from 'mobx-react-lite'
import { FunctionComponent, useCallback, useEffect, useMemo, useRef, useState } from 'react'
import PanelResizer, { PanelSide, ResizeFinishCallback, PanelResizeType } from '@/Components/PanelResizer/PanelResizer'
import SearchBar from '@/Components/SearchBar/SearchBar'
import ResponsivePaneContent from '@/Components/ResponsivePane/ResponsivePaneContent'
import { AppPaneId } from '@/Components/ResponsivePane/AppPaneMetadata'
import { classNames } from '@/Utils/ConcatenateClassNames'
import Icon from '@/Components/Icon/Icon'
type Props = {
application: WebApplication
@@ -20,7 +18,6 @@ const Navigation: FunctionComponent<Props> = ({ application }) => {
const viewControllerManager = useMemo(() => application.getViewControllerManager(), [application])
const ref = useRef<HTMLDivElement>(null)
const [panelWidth, setPanelWidth] = useState<number>(0)
const [isPanelExpanded, setIsPanelExpanded] = useState(true)
useEffect(() => {
const removeObserver = application.addEventObserver(async () => {
@@ -51,37 +48,16 @@ const Navigation: FunctionComponent<Props> = ({ application }) => {
return (
<div
id="navigation"
className={classNames(
'sn-component section app-column xl:w-[220px] xsm-only:!w-full sm-only:!w-full md-only:transition-width lg-only:transition-width',
isPanelExpanded ? 'md-only:!w-[220px] lg-only:!w-[220px]' : 'md-only:!w-18 lg-only:!w-18',
)}
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">
{isPanelExpanded && (
<SearchBar
itemListController={viewControllerManager.itemListController}
searchOptionsController={viewControllerManager.searchOptionsController}
selectedViewTitle={viewControllerManager.navigationController.selected?.title}
/>
)}
<div className={'flex justify-end'}>
<div className={classNames('section-title-bar block w-full xl:block', !isPanelExpanded && 'hidden')}>
<div className="section-title-bar-header">
<div className="title text-sm">
<span className="font-bold">Views</span>
</div>
<div className={'section-title-bar'}>
<div className="section-title-bar-header">
<div className="title text-sm">
<span className="font-bold">Views</span>
</div>
</div>
<div
className={classNames(
'hidden items-end self-end rounded-full rounded-tr-none rounded-br-none bg-default p-1 text-foreground md:flex xl:hidden',
isPanelExpanded ? 'mb-1 w-fit' : 'mt-4.5 mb-3 ml-3 w-full',
)}
onClick={() => setIsPanelExpanded(!isPanelExpanded)}
>
<Icon type="chevron-down" className={isPanelExpanded ? 'rotate-90' : '-rotate-90'} />
</div>
</div>
<div
className={classNames(
@@ -90,8 +66,8 @@ const Navigation: FunctionComponent<Props> = ({ application }) => {
'md:hover:[overflow-y:_overlay]',
)}
>
<SmartViewsSection viewControllerManager={viewControllerManager} isCollapsed={!isPanelExpanded} />
<TagsSection viewControllerManager={viewControllerManager} isCollapsed={!isPanelExpanded} />
<SmartViewsSection viewControllerManager={viewControllerManager} />
<TagsSection viewControllerManager={viewControllerManager} />
</div>
</ResponsivePaneContent>
{ref.current && (
@@ -11,6 +11,8 @@ import {
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import { SNTag } from '@standardnotes/snjs'
import { observer } from 'mobx-react-lite'
import { useResponsiveAppPane } from '../ResponsivePane/ResponsivePaneProvider'
import { AppPaneId } from '../ResponsivePane/AppPaneMetadata'
type Props = {
viewControllerManager: ViewControllerManager
@@ -18,6 +20,8 @@ type Props = {
}
const NoteTag = ({ viewControllerManager, tag }: Props) => {
const { toggleAppPane } = useResponsiveAppPane()
const noteTags = viewControllerManager.noteTagsController
const { autocompleteInputFocused, focusedTagUuid, tags } = noteTags
@@ -46,15 +50,17 @@ const NoteTag = ({ viewControllerManager, tag }: Props) => {
)
const onTagClick: MouseEventHandler = useCallback(
(event) => {
async (event) => {
if (tagClicked && event.target !== deleteTagRef.current) {
setTagClicked(false)
void viewControllerManager.navigationController.setSelectedTag(tag)
await viewControllerManager.navigationController.setSelectedTag(tag)
toggleAppPane(AppPaneId.Items)
} else {
setTagClicked(true)
tagRef.current?.focus()
}
},
[viewControllerManager, tagClicked, tag],
[viewControllerManager, tagClicked, tag, toggleAppPane],
)
const onFocus = useCallback(() => {
@@ -132,7 +138,7 @@ const NoteTag = ({ viewControllerManager, tag }: Props) => {
{showDeleteButton && (
<a
ref={deleteTagRef}
type="button"
role="button"
className="ml-2 -mr-1 flex cursor-pointer border-0 bg-transparent p-0"
onBlur={onBlur}
onClick={onDeleteTagClick}
@@ -36,6 +36,7 @@ import {
import { reloadFont } from './FontFunctions'
import { NoteViewProps } from './NoteViewProps'
import IndicatorCircle from '../IndicatorCircle/IndicatorCircle'
import { classNames } from '@/Utils/ConcatenateClassNames'
const MINIMUM_STATUS_DURATION = 400
const TEXTAREA_DEBOUNCE = 100
@@ -911,7 +912,7 @@ class NoteView extends PureComponent<NoteViewProps, State> {
{this.note && (
<div id="editor-title-bar" className="content-title-bar section-title-bar z-editor-title-bar w-full">
<div className="mb-2 flex flex-wrap items-center justify-between gap-2 md:mb-0 md:flex-nowrap md:gap-0">
<div className="mb-2 flex flex-wrap items-start justify-between gap-2 md:mb-0 md:flex-nowrap md:gap-0 xl:items-center">
<div className={(this.state.noteLocked ? 'locked' : '') + ' flex-grow'}>
<div className="title overflow-auto">
<input
@@ -929,9 +930,14 @@ class NoteView extends PureComponent<NoteViewProps, State> {
/>
</div>
</div>
<div className="flex flex-col flex-wrap items-start gap-3 md:flex-row md:flex-nowrap md:items-center">
<div
className={classNames(
'flex flex-col flex-wrap items-start gap-3 md:flex-col-reverse md:items-end',
'xl:flex-row xl:flex-nowrap xl:items-center',
)}
>
{this.state.noteStatus?.message?.length && (
<div id="save-status-container">
<div id="save-status-container" className={'xl:mr-5 xl:max-w-[16ch]'}>
<div id="save-status">
<div
className={
@@ -8,12 +8,11 @@ import DecoratedInput from '../Input/DecoratedInput'
import { observer } from 'mobx-react-lite'
type Props = {
selectedViewTitle?: string
itemListController: ItemListController
searchOptionsController: SearchOptionsController
}
const SearchBar = ({ itemListController, searchOptionsController, selectedViewTitle = 'Notes' }: Props) => {
const SearchBar = ({ itemListController, searchOptionsController }: Props) => {
const searchInputRef = useRef<HTMLInputElement>(null)
const { noteFilterText, setNoteFilterText, clearFilterText, onFilterEnter } = itemListController
@@ -45,15 +44,14 @@ const SearchBar = ({ itemListController, searchOptionsController, selectedViewTi
}, [clearFilterText])
return (
<div className="px-2.5 pt-4 pb-0.5" role="search">
<div className="pt-3 pb-0.5" role="search">
<DecoratedInput
autocomplete={false}
title="Searches notes and files in the currently selected tag"
className={{
container: 'px-1',
input: 'placeholder:text-passive-0',
}}
placeholder={`Search in ${selectedViewTitle}`}
placeholder={'Search...'}
value={noteFilterText}
ref={searchInputRef}
onBlur={onSearchBlur}
@@ -70,7 +70,7 @@ const AutocompleteTagResult = ({ viewControllerManager, tagResult, closeOnBlur }
<button
ref={tagResultRef}
type="button"
className="flex w-full cursor-pointer items-center border-0 bg-transparent px-3 py-1.5 text-left text-sm text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:bg-info focus:text-info-contrast focus:shadow-none"
className="flex w-full cursor-pointer items-center border-0 bg-transparent px-3 py-1.5 text-left text-sm text-text hover:bg-contrast hover:text-foreground focus:bg-info focus:text-info-contrast focus:shadow-none"
onClick={() => onTagOptionClick(tagResult)}
onFocus={onFocus}
onBlur={onBlur}
@@ -5,10 +5,9 @@ import SmartViewsListItem from './SmartViewsListItem'
type Props = {
viewControllerManager: ViewControllerManager
isCollapsed: boolean
}
const SmartViewsList: FunctionComponent<Props> = ({ viewControllerManager, isCollapsed }: Props) => {
const SmartViewsList: FunctionComponent<Props> = ({ viewControllerManager }: Props) => {
const allViews = viewControllerManager.navigationController.smartViews
return (
@@ -20,7 +19,6 @@ const SmartViewsList: FunctionComponent<Props> = ({ viewControllerManager, isCol
view={view}
tagsState={viewControllerManager.navigationController}
features={viewControllerManager.featuresController}
isCollapsed={isCollapsed}
/>
)
})}
@@ -21,7 +21,6 @@ type Props = {
view: SmartView
tagsState: NavigationController
features: FeaturesController
isCollapsed: boolean
}
const PADDING_BASE_PX = 14
@@ -47,7 +46,7 @@ const smartViewIconType = (view: SmartView, isSelected: boolean): IconType => {
return 'hashtag'
}
const SmartViewsListItem: FunctionComponent<Props> = ({ view, tagsState, isCollapsed }) => {
const SmartViewsListItem: FunctionComponent<Props> = ({ view, tagsState }) => {
const { toggleAppPane } = useResponsiveAppPane()
const [title, setTitle] = useState(view.title || '')
@@ -113,45 +112,36 @@ const SmartViewsListItem: FunctionComponent<Props> = ({ view, tagsState, isColla
return (
<>
<div
className={classNames(
'tag',
isSelected && 'selected',
isFaded && 'opacity-50',
isCollapsed && '!bg-transparent',
)}
className={classNames('tag', isSelected && 'selected', isFaded && 'opacity-50')}
onClick={selectCurrentTag}
style={{
paddingLeft: `${level * PADDING_PER_LEVEL_PX + PADDING_BASE_PX}px`,
}}
>
<div className="tag-info relative">
<div
className={classNames(
isCollapsed
? `relative flex h-[40px] w-[40px] items-center justify-center
${isSelected ? 'transparent-info-color-background' : 'transparent-info-color-background-hover'}`
: 'tag-icon mr-2',
)}
>
<div className="tag-info">
<div className={'tag-icon mr-2'}>
<Icon type={iconType} className={isSelected ? 'text-info' : 'text-neutral'} />
</div>
<input
className={classNames('title', isEditing ? 'editing' : '', isCollapsed ? 'hidden' : 'block')}
disabled={!isEditing}
id={`react-tag-${view.uuid}`}
onBlur={onBlur}
onInput={onInput}
value={title}
onKeyUp={onKeyUp}
spellCheck={false}
ref={inputRef}
/>
<div className={classNames('count', isCollapsed ? 'absolute top-0 right-0' : '')}>
{view.uuid === SystemViewId.AllNotes && tagsState.allNotesCount}
</div>
{isEditing ? (
<input
className={'title editing'}
id={`react-tag-${view.uuid}`}
onBlur={onBlur}
onInput={onInput}
value={title}
onKeyUp={onKeyUp}
spellCheck={false}
ref={inputRef}
/>
) : (
<div className={'title overflow-hidden text-left'} id={`react-tag-${view.uuid}`}>
{title}
</div>
)}
<div className={'count'}>{view.uuid === SystemViewId.AllNotes && tagsState.allNotesCount}</div>
</div>
{!isSystemView(view) && !isCollapsed && (
{!isSystemView(view) && (
<div className="meta">
{view.conflictOf && (
<div className="danger text-[0.625rem] font-bold">Conflicted Copy {view.conflictOf}</div>
@@ -5,13 +5,12 @@ import SmartViewsList from './SmartViewsList'
type Props = {
viewControllerManager: ViewControllerManager
isCollapsed: boolean
}
const SmartViewsSection: FunctionComponent<Props> = ({ viewControllerManager, isCollapsed }) => {
const SmartViewsSection: FunctionComponent<Props> = ({ viewControllerManager }) => {
return (
<section>
<SmartViewsList viewControllerManager={viewControllerManager} isCollapsed={isCollapsed} />
<SmartViewsList viewControllerManager={viewControllerManager} />
</section>
)
}
@@ -9,10 +9,9 @@ import { TagsListItem } from './TagsListItem'
type Props = {
viewControllerManager: ViewControllerManager
isCollapsed: boolean
}
const TagsList: FunctionComponent<Props> = ({ viewControllerManager, isCollapsed }: Props) => {
const TagsList: FunctionComponent<Props> = ({ viewControllerManager }: Props) => {
const tagsState = viewControllerManager.navigationController
const allTags = tagsState.allLocalRootTags
@@ -53,7 +52,6 @@ const TagsList: FunctionComponent<Props> = ({ viewControllerManager, isCollapsed
tagsState={tagsState}
features={viewControllerManager.featuresController}
onContextMenu={onContextMenu}
isCollapsed={isCollapsed}
/>
)
})}
@@ -22,7 +22,6 @@ import { useDrag, useDrop } from 'react-dnd'
import { DropItem, DropProps, ItemTypes } from './DragNDrop'
import { useResponsiveAppPane } from '../ResponsivePane/ResponsivePaneProvider'
import { AppPaneId } from '../ResponsivePane/AppPaneMetadata'
import { classNames } from '@/Utils/ConcatenateClassNames'
type Props = {
tag: SNTag
@@ -30,160 +29,160 @@ type Props = {
features: FeaturesController
level: number
onContextMenu: (tag: SNTag, posX: number, posY: number) => void
isCollapsed: boolean
}
const PADDING_BASE_PX = 14
const PADDING_BASE_WHEN_COLLAPSED_PX = 6
const PADDING_PER_LEVEL_PX = 21
const PADDING_PER_LEVEL_WHEN_COLLAPSED_PX = 10
export const TagsListItem: FunctionComponent<Props> = observer(
({ tag, features, tagsState, level, onContextMenu, isCollapsed }) => {
const { toggleAppPane } = useResponsiveAppPane()
export const TagsListItem: FunctionComponent<Props> = observer(({ tag, features, tagsState, level, onContextMenu }) => {
const { toggleAppPane } = useResponsiveAppPane()
const [title, setTitle] = useState(tag.title || '')
const [subtagTitle, setSubtagTitle] = useState('')
const inputRef = useRef<HTMLInputElement>(null)
const subtagInputRef = useRef<HTMLInputElement>(null)
const menuButtonRef = useRef<HTMLAnchorElement>(null)
const [title, setTitle] = useState(tag.title || '')
const [subtagTitle, setSubtagTitle] = useState('')
const inputRef = useRef<HTMLInputElement>(null)
const subtagInputRef = useRef<HTMLInputElement>(null)
const menuButtonRef = useRef<HTMLAnchorElement>(null)
const isSelected = tagsState.selected === tag
const isEditing = tagsState.editingTag === tag
const isAddingSubtag = tagsState.addingSubtagTo === tag
const noteCounts = computed(() => tagsState.getNotesCount(tag))
const isSelected = tagsState.selected === tag
const isEditing = tagsState.editingTag === tag
const isAddingSubtag = tagsState.addingSubtagTo === tag
const noteCounts = computed(() => tagsState.getNotesCount(tag))
const childrenTags = computed(() => tagsState.getChildren(tag)).get()
const hasChildren = childrenTags.length > 0
const childrenTags = computed(() => tagsState.getChildren(tag)).get()
const hasChildren = childrenTags.length > 0
const hasFolders = features.hasFolders
const hasAtLeastOneFolder = tagsState.hasAtLeastOneFolder
const hasFolders = features.hasFolders
const hasAtLeastOneFolder = tagsState.hasAtLeastOneFolder
const premiumModal = usePremiumModal()
const premiumModal = usePremiumModal()
const [showChildren, setShowChildren] = useState(tag.expanded)
const [hadChildren, setHadChildren] = useState(hasChildren)
const [showChildren, setShowChildren] = useState(tag.expanded)
const [hadChildren, setHadChildren] = useState(hasChildren)
useEffect(() => {
if (!hadChildren && hasChildren) {
setShowChildren(true)
}
setHadChildren(hasChildren)
}, [hadChildren, hasChildren])
useEffect(() => {
if (!hadChildren && hasChildren) {
setShowChildren(true)
}
setHadChildren(hasChildren)
}, [hadChildren, hasChildren])
useEffect(() => {
setTitle(tag.title || '')
}, [setTitle, tag])
useEffect(() => {
setTitle(tag.title || '')
}, [setTitle, tag])
const toggleChildren: MouseEventHandler = useCallback(
(e) => {
e.stopPropagation()
setShowChildren((x) => {
tagsState.setExpanded(tag, !x)
return !x
})
},
[setShowChildren, tag, tagsState],
)
const toggleChildren: MouseEventHandler = useCallback(
(e) => {
e.stopPropagation()
setShowChildren((x) => {
tagsState.setExpanded(tag, !x)
return !x
})
},
[setShowChildren, tag, tagsState],
)
const selectCurrentTag = useCallback(async () => {
await tagsState.setSelectedTag(tag)
toggleAppPane(AppPaneId.Items)
}, [tagsState, tag, toggleAppPane])
const selectCurrentTag = useCallback(async () => {
await tagsState.setSelectedTag(tag)
toggleAppPane(AppPaneId.Items)
}, [tagsState, tag, toggleAppPane])
const onBlur = useCallback(() => {
tagsState.save(tag, title).catch(console.error)
setTitle(tag.title)
}, [tagsState, tag, title, setTitle])
const onBlur = useCallback(() => {
tagsState.save(tag, title).catch(console.error)
setTitle(tag.title)
}, [tagsState, tag, title, setTitle])
const onInput: FormEventHandler = useCallback(
(e) => {
const value = (e.target as HTMLInputElement).value
setTitle(value)
},
[setTitle],
)
const onKeyDown: KeyboardEventHandler = useCallback(
(e) => {
if (e.key === KeyboardKey.Enter) {
inputRef.current?.blur()
e.preventDefault()
}
},
[inputRef],
)
useEffect(() => {
if (isEditing) {
inputRef.current?.focus()
}
}, [inputRef, isEditing])
const onSubtagInput = useCallback((e) => {
const onInput: FormEventHandler = useCallback(
(e) => {
const value = (e.target as HTMLInputElement).value
setSubtagTitle(value)
}, [])
setTitle(value)
},
[setTitle],
)
const onSubtagInputBlur = useCallback(() => {
tagsState.createSubtagAndAssignParent(tag, subtagTitle).catch(console.error)
setSubtagTitle('')
}, [subtagTitle, tag, tagsState])
const onSubtagKeyDown: KeyboardEventHandler = useCallback(
(e) => {
if (e.key === KeyboardKey.Enter) {
e.preventDefault()
subtagInputRef.current?.blur()
}
},
[subtagInputRef],
)
useEffect(() => {
if (isAddingSubtag) {
subtagInputRef.current?.focus()
const onKeyDown: KeyboardEventHandler = useCallback(
(e) => {
if (e.key === KeyboardKey.Enter) {
inputRef.current?.blur()
e.preventDefault()
}
}, [subtagInputRef, isAddingSubtag])
},
[inputRef],
)
const [, dragRef] = useDrag(
() => ({
type: ItemTypes.TAG,
item: { uuid: tag.uuid },
canDrag: () => {
return true
},
collect: (monitor) => ({
isDragging: !!monitor.isDragging(),
}),
useEffect(() => {
if (isEditing) {
inputRef.current?.focus()
}
}, [inputRef, isEditing])
const onSubtagInput = useCallback((e) => {
const value = (e.target as HTMLInputElement).value
setSubtagTitle(value)
}, [])
const onSubtagInputBlur = useCallback(() => {
tagsState.createSubtagAndAssignParent(tag, subtagTitle).catch(console.error)
setSubtagTitle('')
}, [subtagTitle, tag, tagsState])
const onSubtagKeyDown: KeyboardEventHandler = useCallback(
(e) => {
if (e.key === KeyboardKey.Enter) {
e.preventDefault()
subtagInputRef.current?.blur()
}
},
[subtagInputRef],
)
useEffect(() => {
if (isAddingSubtag) {
subtagInputRef.current?.focus()
}
}, [subtagInputRef, isAddingSubtag])
const [, dragRef] = useDrag(
() => ({
type: ItemTypes.TAG,
item: { uuid: tag.uuid },
canDrag: () => {
return true
},
collect: (monitor) => ({
isDragging: !!monitor.isDragging(),
}),
[tag],
)
}),
[tag],
)
const [{ isOver, canDrop }, dropRef] = useDrop<DropItem, void, DropProps>(
() => ({
accept: ItemTypes.TAG,
canDrop: (item) => {
return tagsState.isValidTagParent(tag, item as SNTag)
},
drop: (item) => {
if (!hasFolders) {
premiumModal.activate(TAG_FOLDERS_FEATURE_NAME)
return
}
tagsState.assignParent(item.uuid, tag.uuid).catch(console.error)
},
collect: (monitor) => ({
isOver: !!monitor.isOver(),
canDrop: !!monitor.canDrop(),
}),
const [{ isOver, canDrop }, dropRef] = useDrop<DropItem, void, DropProps>(
() => ({
accept: ItemTypes.TAG,
canDrop: (item) => {
return tagsState.isValidTagParent(tag, item as SNTag)
},
drop: (item) => {
if (!hasFolders) {
premiumModal.activate(TAG_FOLDERS_FEATURE_NAME)
return
}
tagsState.assignParent(item.uuid, tag.uuid).catch(console.error)
},
collect: (monitor) => ({
isOver: !!monitor.isOver(),
canDrop: !!monitor.canDrop(),
}),
[tag, tagsState, hasFolders, premiumModal],
)
}),
[tag, tagsState, hasFolders, premiumModal],
)
const readyToDrop = isOver && canDrop
const readyToDrop = isOver && canDrop
const toggleContextMenu: MouseEventHandler<HTMLAnchorElement> = useCallback(
(event) => {
event.preventDefault()
event.stopPropagation()
const toggleContextMenu = useCallback(() => {
if (!menuButtonRef.current) {
return
}
@@ -196,54 +195,45 @@ export const TagsListItem: FunctionComponent<Props> = observer(
} else {
onContextMenu(tag, menuButtonRect.right, menuButtonRect.top)
}
}, [onContextMenu, tagsState, tag])
},
[onContextMenu, tagsState, tag],
)
return (
<>
<button
className={`tag focus:shadow-inner ${isSelected ? 'selected' : ''} ${readyToDrop ? 'is-drag-over' : ''}`}
onClick={selectCurrentTag}
ref={dragRef}
style={{
paddingLeft: `${
isCollapsed
? level * PADDING_PER_LEVEL_WHEN_COLLAPSED_PX + PADDING_BASE_WHEN_COLLAPSED_PX
: level * PADDING_PER_LEVEL_PX + PADDING_BASE_PX
}px`,
}}
onContextMenu={(e) => {
e.preventDefault()
onContextMenu(tag, e.clientX, e.clientY)
}}
>
<div className="tag-info" title={title} ref={dropRef}>
{hasAtLeastOneFolder && (
<div className="tag-fold-container">
<a
role="button"
className={`tag-fold focus:shadow-inner ${showChildren ? 'opened' : 'closed'} ${
!hasChildren ? 'invisible' : ''
}`}
onClick={hasChildren ? toggleChildren : undefined}
>
<Icon className={'text-neutral'} type={showChildren ? 'menu-arrow-down-alt' : 'menu-arrow-right'} />
</a>
</div>
)}
<div
className={classNames('tag-icon draggable mr-2', isCollapsed ? 'md-only:!hidden lg-only:!hidden' : '')}
ref={dragRef}
>
<Icon type="hashtag" className={`${isSelected ? 'text-info' : 'text-neutral'}`} />
return (
<>
<button
className={`tag focus:shadow-inner ${isSelected ? 'selected' : ''} ${readyToDrop ? 'is-drag-over' : ''}`}
onClick={selectCurrentTag}
ref={dragRef}
style={{
paddingLeft: `${level * PADDING_PER_LEVEL_PX + PADDING_BASE_PX}px`,
}}
onContextMenu={(e) => {
e.preventDefault()
onContextMenu(tag, e.clientX, e.clientY)
}}
>
<div className="tag-info" title={title} ref={dropRef}>
{hasAtLeastOneFolder && (
<div className="tag-fold-container">
<a
role="button"
className={`tag-fold focus:shadow-inner ${showChildren ? 'opened' : 'closed'} ${
!hasChildren ? 'invisible' : ''
}`}
onClick={hasChildren ? toggleChildren : undefined}
>
<Icon className={'text-neutral'} type={showChildren ? 'menu-arrow-down-alt' : 'menu-arrow-right'} />
</a>
</div>
)}
<div className={'tag-icon draggable mr-2'} ref={dragRef}>
<Icon type="hashtag" className={`${isSelected ? 'text-info' : 'text-neutral'}`} />
</div>
{isEditing ? (
<input
className={classNames(
'title focus:shadow-none focus:outline-none',
isEditing ? 'editing' : '',
isCollapsed ? 'md-only:!w-min lg-only:!w-min' : '',
)}
className={'title editing focus:shadow-none focus:outline-none'}
id={`react-tag-${tag.uuid}`}
disabled={!isEditing}
onBlur={onBlur}
onInput={onInput}
value={title}
@@ -251,69 +241,75 @@ export const TagsListItem: FunctionComponent<Props> = observer(
spellCheck={false}
ref={inputRef}
/>
<div className="flex items-center">
<a
role="button"
className={`mr-2 cursor-pointer border-0 bg-transparent hover:bg-contrast focus:shadow-inner ${
isSelected ? 'visible' : 'invisible'
}`}
onClick={toggleContextMenu}
ref={menuButtonRef}
>
<Icon type="more" className="text-neutral" />
</a>
<div className="count">{noteCounts.get()}</div>
) : (
<div
className={'title overflow-hidden text-left focus:shadow-none focus:outline-none'}
id={`react-tag-${tag.uuid}`}
>
{title}
</div>
)}
<div className="flex items-center">
<a
role="button"
className={`mr-2 cursor-pointer border-0 bg-transparent hover:bg-contrast focus:shadow-inner ${
isSelected ? 'visible' : 'invisible'
}`}
onClick={toggleContextMenu}
ref={menuButtonRef}
>
<Icon type="more" className="text-neutral" />
</a>
<div className="count">{noteCounts.get()}</div>
</div>
</div>
<div className={`meta ${hasAtLeastOneFolder ? 'with-folders' : ''}`}>
{tag.conflictOf && <div className="danger text-[0.625rem] font-bold">Conflicted Copy {tag.conflictOf}</div>}
</div>
</button>
{isAddingSubtag && (
<div
className="tag overflow-hidden"
style={{
paddingLeft: `${(level + 1) * PADDING_PER_LEVEL_PX + PADDING_BASE_PX}px`,
}}
>
<div className="tag-info">
<div className="flex h-full min-w-[22px] items-center border-0 bg-transparent p-0" />
<div className="tag-icon mr-1">
<Icon type="hashtag" className="mr-1 text-neutral" />
</div>
<input
className="title w-full focus:shadow-none focus:outline-none"
type="text"
ref={subtagInputRef}
onBlur={onSubtagInputBlur}
onKeyDown={onSubtagKeyDown}
value={subtagTitle}
onInput={onSubtagInput}
/>
<div className={`meta ${hasAtLeastOneFolder ? 'with-folders' : ''}`}>
{tag.conflictOf && <div className="danger text-[0.625rem] font-bold">Conflicted Copy {tag.conflictOf}</div>}
</div>
</button>
{isAddingSubtag && (
<div
className="tag overflow-hidden"
style={{
paddingLeft: `${(level + 1) * PADDING_PER_LEVEL_PX + PADDING_BASE_PX}px`,
}}
>
<div className="tag-info">
<div className="flex h-full min-w-[22px] items-center border-0 bg-transparent p-0" />
<div className="tag-icon mr-1">
<Icon type="hashtag" className="mr-1 text-neutral" />
</div>
<input
className="title w-full focus:shadow-none focus:outline-none"
type="text"
ref={subtagInputRef}
onBlur={onSubtagInputBlur}
onKeyDown={onSubtagKeyDown}
value={subtagTitle}
onInput={onSubtagInput}
/>
</div>
)}
{showChildren && (
<>
{childrenTags.map((tag) => {
return (
<TagsListItem
level={level + 1}
key={tag.uuid}
tag={tag}
tagsState={tagsState}
features={features}
onContextMenu={onContextMenu}
isCollapsed={isCollapsed}
/>
)
})}
</>
)}
</>
)
},
)
</div>
)}
{showChildren && (
<>
{childrenTags.map((tag) => {
return (
<TagsListItem
level={level + 1}
key={tag.uuid}
tag={tag}
tagsState={tagsState}
features={features}
onContextMenu={onContextMenu}
/>
)
})}
</>
)}
</>
)
})
TagsListItem.displayName = 'TagsListItem'
@@ -5,14 +5,12 @@ import { observer } from 'mobx-react-lite'
import { FunctionComponent, useCallback, useEffect, useState } from 'react'
import TagsSectionAddButton from './TagsSectionAddButton'
import TagsSectionTitle from './TagsSectionTitle'
import { classNames } from '@/Utils/ConcatenateClassNames'
type Props = {
viewControllerManager: ViewControllerManager
isCollapsed: boolean
}
const TagsSection: FunctionComponent<Props> = ({ viewControllerManager, isCollapsed }) => {
const TagsSection: FunctionComponent<Props> = ({ viewControllerManager }) => {
const [hasMigration, setHasMigration] = useState<boolean>(false)
const checkIfMigrationNeeded = useCallback(() => {
@@ -55,7 +53,7 @@ const TagsSection: FunctionComponent<Props> = ({ viewControllerManager, isCollap
return (
<section>
<div className={classNames('section-title-bar', isCollapsed ? 'md-only:hidden lg-only:hidden' : '')}>
<div className={'section-title-bar'}>
<div className="section-title-bar-header">
<TagsSectionTitle
features={viewControllerManager.featuresController}
@@ -68,13 +66,7 @@ const TagsSection: FunctionComponent<Props> = ({ viewControllerManager, isCollap
/>
</div>
</div>
<div
className={classNames(
'hidden',
isCollapsed ? 'mt-6 mb-7 border border-border md-only:block lg-only:block' : '',
)}
/>
<TagsList viewControllerManager={viewControllerManager} isCollapsed={isCollapsed} />
<TagsList viewControllerManager={viewControllerManager} />
</section>
)
}
@@ -7,16 +7,15 @@ import { FunctionComponent } from 'react'
type Props = {
tags: NavigationController
features: FeaturesController
className?: string
}
const TagsSectionAddButton: FunctionComponent<Props> = ({ tags, className = '' }) => {
const TagsSectionAddButton: FunctionComponent<Props> = ({ tags }) => {
return (
<IconButton
focusable={true}
icon="add"
title="Create a new tag"
className={`p-0 text-neutral ${className}`}
className="p-0 text-neutral"
onClick={() => tags.createNewTemplate()}
/>
)
@@ -9,10 +9,9 @@ type Props = {
features: FeaturesController
hasMigration: boolean
onClickMigration: () => void
className?: string
}
const TagsSectionTitle: FunctionComponent<Props> = ({ features, hasMigration, onClickMigration, className = '' }) => {
const TagsSectionTitle: FunctionComponent<Props> = ({ features, hasMigration, onClickMigration }) => {
const entitledToFolders = features.hasFolders
const modal = usePremiumModal()
@@ -23,7 +22,7 @@ const TagsSectionTitle: FunctionComponent<Props> = ({ features, hasMigration, on
if (entitledToFolders) {
return (
<>
<div className={`title text-sm ${className}`}>
<div className="title text-sm">
<span className="font-bold">Folders</span>
{hasMigration && (
<label className="ml-1 cursor-pointer font-bold text-info" onClick={onClickMigration}>
@@ -37,7 +36,7 @@ const TagsSectionTitle: FunctionComponent<Props> = ({ features, hasMigration, on
return (
<>
<div className={`title text-sm ${className}`}>
<div className="title text-sm">
<span className="font-bold">Tags</span>
<Tooltip label={TAG_FOLDERS_FEATURE_TOOLTIP}>
<label className="ml-1 cursor-pointer font-bold text-passive-2" onClick={showPremiumAlert}>
@@ -302,7 +302,7 @@ export class FilesController extends AbstractViewController {
const selectedFiles =
fileOrHandle instanceof File
? [fileOrHandle]
: StreamingFileReader.available() && fileOrHandle instanceof FileSystemFileHandle
: shouldUseStreamingReader && fileOrHandle instanceof FileSystemFileHandle
? await StreamingFileReader.getFilesFromHandles([fileOrHandle])
: await picker.selectFiles()
@@ -0,0 +1,38 @@
import { isIOS } from '@/Utils'
import { RefObject, useCallback, useEffect } from 'react'
import { useLongPressEvent } from './useLongPress'
export const useContextMenuEvent = (elementRef: RefObject<HTMLElement>, listener: (x: number, y: number) => void) => {
const { attachEvents, cleanupEvents } = useLongPressEvent(elementRef, listener)
const handleContextMenuEvent = useCallback(
(event: MouseEvent) => {
event.preventDefault()
listener(event.clientX, event.clientY)
},
[listener],
)
useEffect(() => {
const element = elementRef.current
if (!element) {
return
}
const shouldUseLongPress = isIOS()
element.addEventListener('contextmenu', handleContextMenuEvent)
if (shouldUseLongPress) {
attachEvents()
}
return () => {
element.removeEventListener('contextmenu', handleContextMenuEvent)
if (shouldUseLongPress) {
cleanupEvents()
}
}
}, [attachEvents, cleanupEvents, elementRef, handleContextMenuEvent, listener])
}
@@ -0,0 +1,59 @@
import { RefObject, useCallback, useMemo, useRef } from 'react'
// According to https://reactnative.dev/docs/touchablewithoutfeedback#onlongpress
const ReactNativeLongpressDelay = 370
export const useLongPressEvent = (
elementRef: RefObject<HTMLElement>,
listener: (x: number, y: number) => void,
delay = ReactNativeLongpressDelay,
) => {
const longPressTimeout = useRef<number>()
const clearLongPressTimeout = useCallback(() => {
if (longPressTimeout.current) {
clearTimeout(longPressTimeout.current)
}
}, [])
const createLongPressTimeout = useCallback(
(event: PointerEvent) => {
clearLongPressTimeout()
longPressTimeout.current = window.setTimeout(() => {
const x = event.clientX
const y = event.clientY
listener(x, y)
}, delay)
},
[clearLongPressTimeout, delay, listener],
)
const attachEvents = useCallback(() => {
if (!elementRef.current) {
return
}
elementRef.current.addEventListener('pointerdown', createLongPressTimeout)
elementRef.current.addEventListener('pointercancel', clearLongPressTimeout)
}, [clearLongPressTimeout, createLongPressTimeout, elementRef])
const cleanupEvents = useCallback(() => {
if (!elementRef.current) {
return
}
elementRef.current.removeEventListener('pointerdown', createLongPressTimeout)
elementRef.current.removeEventListener('pointercancel', clearLongPressTimeout)
}, [clearLongPressTimeout, createLongPressTimeout, elementRef])
const memoizedReturn = useMemo(
() => ({
attachEvents,
cleanupEvents,
}),
[attachEvents, cleanupEvents],
)
return memoizedReturn
}
+6 -4
View File
@@ -172,6 +172,11 @@ export const convertStringifiedBooleanToBoolean = (value: string) => {
return value !== 'false'
}
// https://stackoverflow.com/questions/9038625/detect-if-device-is-ios/9039885#9039885
export const isIOS = () =>
(/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream) ||
(navigator.userAgent.includes('Mac') && 'ontouchend' in document && navigator.maxTouchPoints > 1)
// https://stackoverflow.com/a/57527009/2504429
export const disableIosTextFieldZoom = () => {
const addMaximumScaleToMetaViewport = () => {
@@ -194,10 +199,7 @@ export const disableIosTextFieldZoom = () => {
}
}
// https://stackoverflow.com/questions/9038625/detect-if-device-is-ios/9039885#9039885
const checkIsIOS = () => /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream
if (checkIsIOS()) {
if (isIOS()) {
addMaximumScaleToMetaViewport()
}
}
@@ -67,11 +67,6 @@ $heading-height: 75px;
position: relative;
min-width: 16ch;
overflow: visible;
margin-right: 20px;
@media screen and (min-width: 768px) {
max-width: 16ch;
}
}
#save-status {
-15
View File
@@ -132,21 +132,6 @@
@include DimmedBackground(var(--sn-stylekit-info-color), 0.08);
}
.transparent-info-color-background {
&::after {
@include DimmedBackground(var(--sn-stylekit-info-color), .12);
border-radius: 100px;
}
}
.transparent-info-color-background-hover {
&:hover {
&::after {
@extend .transparent-info-color-background
}
}
}
svg.sk-circular-progress {
$pi: 3.14159265358979;