diff --git a/Cargo.lock b/Cargo.lock index 68856b5..ab263e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ "gimli", ] @@ -186,9 +186,9 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "async-compression" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c90a406b4495d129f00461241616194cb8a032c8d1c53c657f0961d5f8e0498" +checksum = "cd066d0b4ef8ecb03a55319dc13aa6910616d0f44008a045bb1835af830abff5" dependencies = [ "brotli", "futures-core", @@ -335,9 +335,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "17c6a35df3749d2e8bb1b7b21a976d82b15548788d2735b9d82f329268f71a11" dependencies = [ "addr2line", "cc", @@ -483,6 +483,7 @@ dependencies = [ "serde", "serde_json", "thiserror", + "tracing", "url", ] @@ -557,9 +558,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "4.0.0" +version = "4.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6221fe77a248b9117d431ad93761222e1cf8ff282d9d1d5d9f53d6299a1cf76" +checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -1315,9 +1316,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" [[package]] name = "h2" @@ -1540,9 +1541,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d8d52be92d09acc2e01dddb7fde3ad983fc6489c7db4837e605bc3fca4cb63e" +checksum = "7b875924a60b96e5d7b9ae7b066540b1dd1cbd90d1828f54c92e02a283351c56" dependencies = [ "bytes", "futures-channel", @@ -1954,11 +1955,10 @@ dependencies = [ [[package]] name = "native-tls" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" dependencies = [ - "lazy_static", "libc", "log", "openssl", @@ -2099,9 +2099,9 @@ dependencies = [ [[package]] name = "object" -version = "0.32.2" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e" dependencies = [ "memchr", ] @@ -3581,9 +3581,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.37.0" +version = "1.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" dependencies = [ "backtrace", "bytes", @@ -3598,9 +3598,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", @@ -4343,9 +4343,9 @@ checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winnow" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d" +checksum = "86c949fede1d13936a99f14fafd3e76fd642b556dd2ce96287fbe2e0151bfac6" dependencies = [ "memchr", ] diff --git a/crates/blend-feed/Cargo.toml b/crates/blend-feed/Cargo.toml index ff55f92..7f57fb9 100644 --- a/crates/blend-feed/Cargo.toml +++ b/crates/blend-feed/Cargo.toml @@ -19,4 +19,5 @@ reqwest = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } thiserror = { workspace = true } +tracing = { workspace = true } url = { workspace = true } diff --git a/crates/blend-feed/src/extract/mod.rs b/crates/blend-feed/src/extract/mod.rs index 8b983c0..dccc0b8 100644 --- a/crates/blend-feed/src/extract/mod.rs +++ b/crates/blend-feed/src/extract/mod.rs @@ -5,33 +5,3 @@ mod text; pub use html::*; pub use stylistic::*; pub use text::*; - -/// Test if given input is likely HTML, based on the difference between the parsed style/inline tags vs. the sanitized HTML. -pub fn likely_html(src: &str) -> bool { - let stylistic = extract_stylistic_html(src, ""); - let html = extract_html(src, ""); - - stylistic != html -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn returns_true_for_html() { - assert_eq!(likely_html(r#"

Some HTML

"#), true); - assert_eq!(likely_html(r#"
Some HTML
"#), true); - assert_eq!(likely_html(r#"
Some HTML
"#), true); - } - - #[test] - fn returns_false_for_non_html() { - assert_eq!(likely_html(r#"Some HTML"#), false); - assert_eq!(likely_html(r#"Some HTML"#), false); - assert_eq!( - likely_html(r#"Some HTML"#), - false - ); - } -} diff --git a/crates/blend-feed/src/lib.rs b/crates/blend-feed/src/lib.rs index 75db612..e9817fa 100644 --- a/crates/blend-feed/src/lib.rs +++ b/crates/blend-feed/src/lib.rs @@ -7,7 +7,7 @@ mod model; mod parse; mod readability; mod scrape; -mod util; +pub(crate) mod util; pub use error::FeedError as Error; pub use extract::*; diff --git a/crates/blend-feed/src/parse/entry.rs b/crates/blend-feed/src/parse/entry.rs index af87cc2..ff6a788 100644 --- a/crates/blend-feed/src/parse/entry.rs +++ b/crates/blend-feed/src/parse/entry.rs @@ -1,5 +1,5 @@ use super::{get_feed, parse_url}; -use crate::{error::FeedResult, extract::*, ParsedEntry}; +use crate::{error::FeedResult, extract::*, util::*, ParsedEntry}; /// Number of characters after which we can just assume the summary is the content, without needing to guess that it's HTML const MAX_SUMMARY_LENGTH: usize = 1000; @@ -43,9 +43,9 @@ pub async fn parse_entries(url: &str) -> FeedResult> { // Some feeds may return article content as the summary/teaser, so if it's likely HTML, let's swap these fields if content_html.is_none() - && summary_html - .as_ref() - .is_some_and(|value| value.len() >= MAX_SUMMARY_LENGTH || likely_html(value)) + && entry.summary.as_ref().is_some_and(|text| { + text.content.len() >= MAX_SUMMARY_LENGTH || likely_html(&text.content) + }) { content_html = entry.summary.map(|text| extract_html(&text.content, base_url)); summary_html = None; diff --git a/crates/blend-feed/src/util/likely_html.rs b/crates/blend-feed/src/util/likely_html.rs new file mode 100644 index 0000000..f3aacc1 --- /dev/null +++ b/crates/blend-feed/src/util/likely_html.rs @@ -0,0 +1,48 @@ +use crate::{extract_html, extract_stylistic_html}; + +/// Test if given input is likely HTML, based on the difference between the parsed style/inline tags vs. the sanitized HTML. +pub fn likely_html(src: &str) -> bool { + let stylistic = extract_stylistic_html(src, ""); + let html = extract_html(src, ""); + + stylistic != html +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn returns_true_for_html() { + assert_eq!(likely_html(r#"

Some HTML

"#), true); + assert_eq!(likely_html(r#"
Some HTML
"#), true); + assert_eq!(likely_html(r#"
Some HTML
"#), true); + } + + #[test] + fn returns_false_for_non_html() { + assert_eq!(likely_html(r#"Some HTML"#), false); + assert_eq!(likely_html(r#"Some HTML"#), false); + assert_eq!( + likely_html(r#"Some HTML"#), + false + ); + } + + #[test] + fn it_works_on_real_example() { + let src = r#" +

+ + Some image. + +

+

Some long description.

+

+ [Read More] +

+ "#; + + assert_eq!(likely_html(src), true); + } +} diff --git a/crates/blend-feed/src/util/mod.rs b/crates/blend-feed/src/util/mod.rs new file mode 100644 index 0000000..31598fd --- /dev/null +++ b/crates/blend-feed/src/util/mod.rs @@ -0,0 +1,5 @@ +mod likely_html; +mod request; + +pub use likely_html::*; +pub use request::*; diff --git a/crates/blend-feed/src/util.rs b/crates/blend-feed/src/util/request.rs similarity index 100% rename from crates/blend-feed/src/util.rs rename to crates/blend-feed/src/util/request.rs diff --git a/package.json b/package.json index 285b4bc..f26cce4 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "typeshare:generate": "typeshare ./ --lang typescript --output-file ./ui/src/types/bindings.ts && biome check --apply ./ui/src/types/bindings.ts" }, "dependencies": { - "@kobalte/core": "^0.13.1", + "@kobalte/core": "^0.13.2", "@kobalte/tailwindcss": "^0.9.0", "@solid-primitives/active-element": "^2.0.20", "@solid-primitives/bounds": "^0.0.121", @@ -23,7 +23,7 @@ "@solid-primitives/resize-observer": "^2.0.25", "@solid-primitives/scheduled": "^1.4.3", "@solid-primitives/scroll": "^2.0.23", - "@solidjs/router": "^0.13.3", + "@solidjs/router": "^0.13.4", "@tanstack/solid-query": "^5.40.0", "@tanstack/solid-query-devtools": "^5.40.0", "class-variance-authority": "^0.7.0", @@ -34,7 +34,7 @@ }, "devDependencies": { "@biomejs/biome": "1.7.3", - "@swc/core": "^1.5.7", + "@swc/core": "^1.5.24", "@swc/jest": "^0.2.36", "@tailwindcss/forms": "^0.5.7", "@tailwindcss/typography": "^0.5.13", @@ -46,7 +46,7 @@ "solid-devtools": "^0.30.1", "tailwindcss": "^3.4.3", "typescript": "^5.4.5", - "vite": "^5.2.11", + "vite": "^5.2.12", "vite-plugin-solid": "^2.10.2", "vite-tsconfig-paths": "^4.3.2" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2f492a4..6484106 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,8 +6,8 @@ settings: dependencies: '@kobalte/core': - specifier: ^0.13.1 - version: 0.13.1(solid-js@1.8.17) + specifier: ^0.13.2 + version: 0.13.2(solid-js@1.8.17) '@kobalte/tailwindcss': specifier: ^0.9.0 version: 0.9.0(tailwindcss@3.4.3) @@ -30,8 +30,8 @@ dependencies: specifier: ^2.0.23 version: 2.0.23(solid-js@1.8.17) '@solidjs/router': - specifier: ^0.13.3 - version: 0.13.3(solid-js@1.8.17) + specifier: ^0.13.4 + version: 0.13.4(solid-js@1.8.17) '@tanstack/solid-query': specifier: ^5.40.0 version: 5.40.0(solid-js@1.8.17) @@ -59,11 +59,11 @@ devDependencies: specifier: 1.7.3 version: 1.7.3 '@swc/core': - specifier: ^1.5.7 - version: 1.5.7 + specifier: ^1.5.24 + version: 1.5.24 '@swc/jest': specifier: ^0.2.36 - version: 0.2.36(@swc/core@1.5.7) + version: 0.2.36(@swc/core@1.5.24) '@tailwindcss/forms': specifier: ^0.5.7 version: 0.5.7(tailwindcss@3.4.3) @@ -87,7 +87,7 @@ devDependencies: version: 8.4.38 solid-devtools: specifier: ^0.30.1 - version: 0.30.1(solid-js@1.8.17)(vite@5.2.11) + version: 0.30.1(solid-js@1.8.17)(vite@5.2.12) tailwindcss: specifier: ^3.4.3 version: 3.4.3 @@ -95,14 +95,14 @@ devDependencies: specifier: ^5.4.5 version: 5.4.5 vite: - specifier: ^5.2.11 - version: 5.2.11 + specifier: ^5.2.12 + version: 5.2.12 vite-plugin-solid: specifier: ^2.10.2 - version: 2.10.2(solid-js@1.8.17)(vite@5.2.11) + version: 2.10.2(solid-js@1.8.17)(vite@5.2.12) vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(typescript@5.4.5)(vite@5.2.11) + version: 4.3.2(typescript@5.4.5)(vite@5.2.12) packages: @@ -146,7 +146,7 @@ packages: '@babel/traverse': 7.24.6 '@babel/types': 7.24.6 convert-source-map: 2.0.0 - debug: 4.3.4 + debug: 4.3.5 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -433,7 +433,7 @@ packages: '@babel/helper-split-export-declaration': 7.24.6 '@babel/parser': 7.24.6 '@babel/types': 7.24.6 - debug: 4.3.4 + debug: 4.3.5 globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -817,7 +817,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 20.12.12 + '@types/node': 20.12.13 chalk: 4.1.2 jest-message-util: 29.7.0 jest-util: 29.7.0 @@ -838,14 +838,14 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.12 + '@types/node': 20.12.13 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.9.0 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.12.12) + jest-config: 29.7.0(@types/node@20.12.13) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -880,7 +880,7 @@ packages: dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.12 + '@types/node': 20.12.13 jest-mock: 29.7.0 dev: true @@ -907,7 +907,7 @@ packages: dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 20.12.12 + '@types/node': 20.12.13 jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -940,7 +940,7 @@ packages: '@jest/transform': 29.7.0 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.25 - '@types/node': 20.12.12 + '@types/node': 20.12.13 chalk: 4.1.2 collect-v8-coverage: 1.0.2 exit: 0.1.2 @@ -1028,7 +1028,7 @@ packages: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 20.12.12 + '@types/node': 20.12.13 '@types/yargs': 17.0.32 chalk: 4.1.2 dev: true @@ -1058,8 +1058,8 @@ packages: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.4.15 - /@kobalte/core@0.13.1(solid-js@1.8.17): - resolution: {integrity: sha512-ROFTM2EZhOS+PxCTD+a2LKvzi8ZA7uiDvAt9/rAHzlaAykJPWXCpRuB/PYKiA7iPssGU3Fno3GT5bgRoZAc3KQ==} + /@kobalte/core@0.13.2(solid-js@1.8.17): + resolution: {integrity: sha512-267BCL0zA+6fv7ysHsqUXHielS0BT0Y2trBAUmZ0W/xt/JMhR2nCngInSIAEXKV22TP3ZuClnsInldIcCsprOw==} peerDependencies: solid-js: ^1.8.15 dependencies: @@ -1506,16 +1506,16 @@ packages: dependencies: solid-js: 1.8.17 - /@solidjs/router@0.13.3(solid-js@1.8.17): - resolution: {integrity: sha512-p8zznlvnN3KySMXqT8irhubgDNTETNa/guaGHU/cZl7kuiPO3PmkWNYfoNCygtEpoxLmLpf62/ZKeyhFdZexsw==} + /@solidjs/router@0.13.4(solid-js@1.8.17): + resolution: {integrity: sha512-UvL/8TkP3ExE/Z5KDs0wdqesWasISsRTrrredcTbxQx/eNdRXr8BXFsa3GV2f6VSQVjbukWG5cRAcIzV76nl/g==} peerDependencies: solid-js: ^1.8.6 dependencies: solid-js: 1.8.17 dev: false - /@swc/core-darwin-arm64@1.5.7: - resolution: {integrity: sha512-bZLVHPTpH3h6yhwVl395k0Mtx8v6CGhq5r4KQdAoPbADU974Mauz1b6ViHAJ74O0IVE5vyy7tD3OpkQxL/vMDQ==} + /@swc/core-darwin-arm64@1.5.24: + resolution: {integrity: sha512-M7oLOcC0sw+UTyAuL/9uyB9GeO4ZpaBbH76JSH6g1m0/yg7LYJZGRmplhDmwVSDAR5Fq4Sjoi1CksmmGkgihGA==} engines: {node: '>=10'} cpu: [arm64] os: [darwin] @@ -1523,8 +1523,8 @@ packages: dev: true optional: true - /@swc/core-darwin-x64@1.5.7: - resolution: {integrity: sha512-RpUyu2GsviwTc2qVajPL0l8nf2vKj5wzO3WkLSHAHEJbiUZk83NJrZd1RVbEknIMO7+Uyjh54hEh8R26jSByaw==} + /@swc/core-darwin-x64@1.5.24: + resolution: {integrity: sha512-MfcFjGGYognpSBSos2pYUNYJSmqEhuw5ceGr6qAdME7ddbjGXliza4W6FggsM+JnWwpqa31+e7/R+GetW4WkaQ==} engines: {node: '>=10'} cpu: [x64] os: [darwin] @@ -1532,8 +1532,8 @@ packages: dev: true optional: true - /@swc/core-linux-arm-gnueabihf@1.5.7: - resolution: {integrity: sha512-cTZWTnCXLABOuvWiv6nQQM0hP6ZWEkzdgDvztgHI/+u/MvtzJBN5lBQ2lue/9sSFYLMqzqff5EHKlFtrJCA9dQ==} + /@swc/core-linux-arm-gnueabihf@1.5.24: + resolution: {integrity: sha512-amI2pwtcWV3E/m/nf+AQtn1LWDzKLZyjCmWd3ms7QjEueWYrY8cU1Y4Wp7wNNsxIoPOi8zek1Uj2wwFD/pttNQ==} engines: {node: '>=10'} cpu: [arm] os: [linux] @@ -1541,8 +1541,8 @@ packages: dev: true optional: true - /@swc/core-linux-arm64-gnu@1.5.7: - resolution: {integrity: sha512-hoeTJFBiE/IJP30Be7djWF8Q5KVgkbDtjySmvYLg9P94bHg9TJPSQoC72tXx/oXOgXvElDe/GMybru0UxhKx4g==} + /@swc/core-linux-arm64-gnu@1.5.24: + resolution: {integrity: sha512-sTSvmqMmgT1ynH/nP75Pc51s+iT4crZagHBiDOf5cq+kudUYjda9lWMs7xkXB/TUKFHPCRK0HGunl8bkwiIbuw==} engines: {node: '>=10'} cpu: [arm64] os: [linux] @@ -1550,8 +1550,8 @@ packages: dev: true optional: true - /@swc/core-linux-arm64-musl@1.5.7: - resolution: {integrity: sha512-+NDhK+IFTiVK1/o7EXdCeF2hEzCiaRSrb9zD7X2Z7inwWlxAntcSuzZW7Y6BRqGQH89KA91qYgwbnjgTQ22PiQ==} + /@swc/core-linux-arm64-musl@1.5.24: + resolution: {integrity: sha512-vd2/hfOBGbrX21FxsFdXCUaffjkHvlZkeE2UMRajdXifwv79jqOHIJg3jXG1F3ZrhCghCzirFts4tAZgcG8XWg==} engines: {node: '>=10'} cpu: [arm64] os: [linux] @@ -1559,8 +1559,8 @@ packages: dev: true optional: true - /@swc/core-linux-x64-gnu@1.5.7: - resolution: {integrity: sha512-25GXpJmeFxKB+7pbY7YQLhWWjkYlR+kHz5I3j9WRl3Lp4v4UD67OGXwPe+DIcHqcouA1fhLhsgHJWtsaNOMBNg==} + /@swc/core-linux-x64-gnu@1.5.24: + resolution: {integrity: sha512-Zrdzi7NqzQxm2BvAG5KyOSBEggQ7ayrxh599AqqevJmsUXJ8o2nMiWQOBvgCGp7ye+Biz3pvZn1EnRzAp+TpUg==} engines: {node: '>=10'} cpu: [x64] os: [linux] @@ -1568,8 +1568,8 @@ packages: dev: true optional: true - /@swc/core-linux-x64-musl@1.5.7: - resolution: {integrity: sha512-0VN9Y5EAPBESmSPPsCJzplZHV26akC0sIgd3Hc/7S/1GkSMoeuVL+V9vt+F/cCuzr4VidzSkqftdP3qEIsXSpg==} + /@swc/core-linux-x64-musl@1.5.24: + resolution: {integrity: sha512-1F8z9NRi52jdZQCGc5sflwYSctL6omxiVmIFVp8TC9nngjQKc00TtX/JC2Eo2HwvgupkFVl5YQJidAck9YtmJw==} engines: {node: '>=10'} cpu: [x64] os: [linux] @@ -1577,8 +1577,8 @@ packages: dev: true optional: true - /@swc/core-win32-arm64-msvc@1.5.7: - resolution: {integrity: sha512-RtoNnstBwy5VloNCvmvYNApkTmuCe4sNcoYWpmY7C1+bPR+6SOo8im1G6/FpNem8AR5fcZCmXHWQ+EUmRWJyuA==} + /@swc/core-win32-arm64-msvc@1.5.24: + resolution: {integrity: sha512-cKpP7KvS6Xr0jFSTBXY53HZX/YfomK5EMQYpCVDOvfsZeYHN20sQSKXfpVLvA/q2igVt1zzy1XJcOhpJcgiKLg==} engines: {node: '>=10'} cpu: [arm64] os: [win32] @@ -1586,8 +1586,8 @@ packages: dev: true optional: true - /@swc/core-win32-ia32-msvc@1.5.7: - resolution: {integrity: sha512-Xm0TfvcmmspvQg1s4+USL3x8D+YPAfX2JHygvxAnCJ0EHun8cm2zvfNBcsTlnwYb0ybFWXXY129aq1wgFC9TpQ==} + /@swc/core-win32-ia32-msvc@1.5.24: + resolution: {integrity: sha512-IoPWfi0iwqjZuf7gE223+B97/ZwkKbu7qL5KzGP7g3hJrGSKAvv7eC5Y9r2iKKtLKyv5R/T6Ho0kFR/usi7rHw==} engines: {node: '>=10'} cpu: [ia32] os: [win32] @@ -1595,8 +1595,8 @@ packages: dev: true optional: true - /@swc/core-win32-x64-msvc@1.5.7: - resolution: {integrity: sha512-tp43WfJLCsKLQKBmjmY/0vv1slVywR5Q4qKjF5OIY8QijaEW7/8VwPyUyVoJZEnDgv9jKtUTG5PzqtIYPZGnyg==} + /@swc/core-win32-x64-msvc@1.5.24: + resolution: {integrity: sha512-zHgF2k1uVJL8KIW+PnVz1To4a3Cz9THbh2z2lbehaF/gKHugH4c3djBozU4das1v35KOqf5jWIEviBLql2wDLQ==} engines: {node: '>=10'} cpu: [x64] os: [win32] @@ -1604,12 +1604,12 @@ packages: dev: true optional: true - /@swc/core@1.5.7: - resolution: {integrity: sha512-U4qJRBefIJNJDRCCiVtkfa/hpiZ7w0R6kASea+/KLp+vkus3zcLSB8Ub8SvKgTIxjWpwsKcZlPf5nrv4ls46SQ==} + /@swc/core@1.5.24: + resolution: {integrity: sha512-Eph9zvO4xvqWZGVzTdtdEJ0Vqf0VIML/o/e4Qd2RLOqtfgnlRi7avmMu5C0oqciJ0tk+hqdUKVUZ4JPoPaiGvQ==} engines: {node: '>=10'} requiresBuild: true peerDependencies: - '@swc/helpers': ^0.5.0 + '@swc/helpers': '*' peerDependenciesMeta: '@swc/helpers': optional: true @@ -1617,16 +1617,16 @@ packages: '@swc/counter': 0.1.3 '@swc/types': 0.1.7 optionalDependencies: - '@swc/core-darwin-arm64': 1.5.7 - '@swc/core-darwin-x64': 1.5.7 - '@swc/core-linux-arm-gnueabihf': 1.5.7 - '@swc/core-linux-arm64-gnu': 1.5.7 - '@swc/core-linux-arm64-musl': 1.5.7 - '@swc/core-linux-x64-gnu': 1.5.7 - '@swc/core-linux-x64-musl': 1.5.7 - '@swc/core-win32-arm64-msvc': 1.5.7 - '@swc/core-win32-ia32-msvc': 1.5.7 - '@swc/core-win32-x64-msvc': 1.5.7 + '@swc/core-darwin-arm64': 1.5.24 + '@swc/core-darwin-x64': 1.5.24 + '@swc/core-linux-arm-gnueabihf': 1.5.24 + '@swc/core-linux-arm64-gnu': 1.5.24 + '@swc/core-linux-arm64-musl': 1.5.24 + '@swc/core-linux-x64-gnu': 1.5.24 + '@swc/core-linux-x64-musl': 1.5.24 + '@swc/core-win32-arm64-msvc': 1.5.24 + '@swc/core-win32-ia32-msvc': 1.5.24 + '@swc/core-win32-x64-msvc': 1.5.24 dev: true /@swc/counter@0.1.3: @@ -1639,14 +1639,14 @@ packages: tslib: 2.6.2 dev: false - /@swc/jest@0.2.36(@swc/core@1.5.7): + /@swc/jest@0.2.36(@swc/core@1.5.24): resolution: {integrity: sha512-8X80dp81ugxs4a11z1ka43FPhP+/e+mJNXJSxiNYk8gIX/jPBtY4gQTrKu/KIoco8bzKuPI5lUxjfLiGsfvnlw==} engines: {npm: '>= 7.0.0'} peerDependencies: '@swc/core': '*' dependencies: '@jest/create-cache-key-function': 29.7.0 - '@swc/core': 1.5.7 + '@swc/core': 1.5.24 '@swc/counter': 0.1.3 jsonc-parser: 3.2.1 dev: true @@ -1746,7 +1746,7 @@ packages: /@types/graceful-fs@4.1.9: resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} dependencies: - '@types/node': 20.12.12 + '@types/node': 20.12.13 dev: true /@types/istanbul-lib-coverage@2.0.6: @@ -1772,8 +1772,8 @@ packages: pretty-format: 29.7.0 dev: true - /@types/node@20.12.12: - resolution: {integrity: sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==} + /@types/node@20.12.13: + resolution: {integrity: sha512-gBGeanV41c1L171rR7wjbMiEpEI/l5XFQdLLfhr/REwpgDy/4U8y89+i8kRiLzDyZdOkXh+cRaTetUnCYutoXA==} dependencies: undici-types: 5.26.5 dev: true @@ -1856,7 +1856,7 @@ packages: postcss: ^8.1.0 dependencies: browserslist: 4.23.0 - caniuse-lite: 1.0.30001623 + caniuse-lite: 1.0.30001625 fraction.js: 4.3.7 normalize-range: 0.1.2 picocolors: 1.0.1 @@ -1988,8 +1988,8 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001623 - electron-to-chromium: 1.4.783 + caniuse-lite: 1.0.30001625 + electron-to-chromium: 1.4.787 node-releases: 2.0.14 update-browserslist-db: 1.0.16(browserslist@4.23.0) dev: true @@ -2023,8 +2023,8 @@ packages: engines: {node: '>=10'} dev: true - /caniuse-lite@1.0.30001623: - resolution: {integrity: sha512-X/XhAVKlpIxWPpgRTnlgZssJrF0m6YtRA0QDWgsBNT12uZM6LPRydR7ip405Y3t1LamD8cP2TZFEDZFBf5ApcA==} + /caniuse-lite@1.0.30001625: + resolution: {integrity: sha512-4KE9N2gcRH+HQhpeiRZXd+1niLB/XNLAhSy4z7fI8EzcbcPoAqjNInxVHTiTwWfTIV4w096XG8OtCOCQQKPv3w==} dev: true /chalk@2.4.2: @@ -2141,7 +2141,7 @@ packages: chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@20.12.12) + jest-config: 29.7.0(@types/node@20.12.13) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -2167,8 +2167,8 @@ packages: /csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} - /debug@4.3.4: - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + /debug@4.3.5: + resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' @@ -2212,8 +2212,8 @@ packages: /eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - /electron-to-chromium@1.4.783: - resolution: {integrity: sha512-bT0jEz/Xz1fahQpbZ1D7LgmPYZ3iHVY39NcWWro1+hA2IvjiPeaXtfSqrQ+nXjApMvQRE2ASt1itSLRrebHMRQ==} + /electron-to-chromium@1.4.787: + resolution: {integrity: sha512-d0EFmtLPjctczO3LogReyM2pbBiiZbnsKnGF+cdZhsYzHm/A0GV7W94kqzLD8SN4O3f3iHlgLUChqghgyznvCQ==} dev: true /emittery@0.13.1: @@ -2603,7 +2603,7 @@ packages: resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} engines: {node: '>=10'} dependencies: - debug: 4.3.4 + debug: 4.3.5 istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: @@ -2643,7 +2643,7 @@ packages: '@jest/expect': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.12 + '@types/node': 20.12.13 chalk: 4.1.2 co: 4.6.0 dedent: 1.5.3 @@ -2681,7 +2681,7 @@ packages: create-jest: 29.7.0 exit: 0.1.2 import-local: 3.1.0 - jest-config: 29.7.0(@types/node@20.12.12) + jest-config: 29.7.0(@types/node@20.12.13) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -2692,7 +2692,7 @@ packages: - ts-node dev: true - /jest-config@29.7.0(@types/node@20.12.12): + /jest-config@29.7.0(@types/node@20.12.13): resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: @@ -2707,7 +2707,7 @@ packages: '@babel/core': 7.24.6 '@jest/test-sequencer': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.12 + '@types/node': 20.12.13 babel-jest: 29.7.0(@babel/core@7.24.6) chalk: 4.1.2 ci-info: 3.9.0 @@ -2767,7 +2767,7 @@ packages: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.12 + '@types/node': 20.12.13 jest-mock: 29.7.0 jest-util: 29.7.0 dev: true @@ -2783,7 +2783,7 @@ packages: dependencies: '@jest/types': 29.6.3 '@types/graceful-fs': 4.1.9 - '@types/node': 20.12.12 + '@types/node': 20.12.13 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -2834,7 +2834,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 20.12.12 + '@types/node': 20.12.13 jest-util: 29.7.0 dev: true @@ -2889,7 +2889,7 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.12 + '@types/node': 20.12.13 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -2920,7 +2920,7 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.12 + '@types/node': 20.12.13 chalk: 4.1.2 cjs-module-lexer: 1.3.1 collect-v8-coverage: 1.0.2 @@ -2972,7 +2972,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 20.12.12 + '@types/node': 20.12.13 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -2997,7 +2997,7 @@ packages: dependencies: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.12 + '@types/node': 20.12.13 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -3009,7 +3009,7 @@ packages: resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@types/node': 20.12.12 + '@types/node': 20.12.13 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -3561,7 +3561,7 @@ packages: engines: {node: '>=8'} dev: true - /solid-devtools@0.30.1(solid-js@1.8.17)(vite@5.2.11): + /solid-devtools@0.30.1(solid-js@1.8.17)(vite@5.2.12): resolution: {integrity: sha512-axpXL4JV1dnGhuei+nSGS8ewGeNkmIgFDsAlO90YyYY5t8wU1R0aYAQtL+I+5KICLKPBvfkzdcFa2br7AV4lAw==} peerDependencies: solid-js: ^1.8.0 @@ -3579,7 +3579,7 @@ packages: '@solid-devtools/debugger': 0.23.4(solid-js@1.8.17) '@solid-devtools/shared': 0.13.2(solid-js@1.8.17) solid-js: 1.8.17 - vite: 5.2.11 + vite: 5.2.12 transitivePeerDependencies: - supports-color dev: true @@ -3803,8 +3803,8 @@ packages: /ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - /tsconfck@3.0.3(typescript@5.4.5): - resolution: {integrity: sha512-4t0noZX9t6GcPTfBAbIbbIU4pfpCwh0ueq3S4O/5qXI1VwK1outmxhe9dOiEWqMz3MW2LKgDTpqWV+37IWuVbA==} + /tsconfck@3.1.0(typescript@5.4.5): + resolution: {integrity: sha512-CMjc5zMnyAjcS9sPLytrbFmj89st2g+JYtY/c02ug4Q+CZaAtCgbyviI0n1YvjZE/pzoc6FbNsINS13DOL1B9w==} engines: {node: ^18 || >=20} hasBin: true peerDependencies: @@ -3867,7 +3867,7 @@ packages: resolution: {integrity: sha512-hGdgQozCsQJMyfK5urgFcWEqsSSrK63Awe0t/IMR0bZ0QMtnuaiHzThW81guu3qx9abLi99NEuiaN6P9gVYsNg==} dev: true - /vite-plugin-solid@2.10.2(solid-js@1.8.17)(vite@5.2.11): + /vite-plugin-solid@2.10.2(solid-js@1.8.17)(vite@5.2.12): resolution: {integrity: sha512-AOEtwMe2baBSXMXdo+BUwECC8IFHcKS6WQV/1NEd+Q7vHPap5fmIhLcAzr+DUJ04/KHx/1UBU0l1/GWP+rMAPQ==} peerDependencies: '@testing-library/jest-dom': ^5.16.6 || ^5.17.0 || ^6.* @@ -3883,13 +3883,13 @@ packages: merge-anything: 5.1.7 solid-js: 1.8.17 solid-refresh: 0.6.3(solid-js@1.8.17) - vite: 5.2.11 - vitefu: 0.2.5(vite@5.2.11) + vite: 5.2.12 + vitefu: 0.2.5(vite@5.2.12) transitivePeerDependencies: - supports-color dev: true - /vite-tsconfig-paths@4.3.2(typescript@5.4.5)(vite@5.2.11): + /vite-tsconfig-paths@4.3.2(typescript@5.4.5)(vite@5.2.12): resolution: {integrity: sha512-0Vd/a6po6Q+86rPlntHye7F31zA2URZMbH8M3saAZ/xR9QoGN/L21bxEGfXdWmFdNkqPpRdxFT7nmNe12e9/uA==} peerDependencies: vite: '*' @@ -3897,17 +3897,17 @@ packages: vite: optional: true dependencies: - debug: 4.3.4 + debug: 4.3.5 globrex: 0.1.2 - tsconfck: 3.0.3(typescript@5.4.5) - vite: 5.2.11 + tsconfck: 3.1.0(typescript@5.4.5) + vite: 5.2.12 transitivePeerDependencies: - supports-color - typescript dev: true - /vite@5.2.11: - resolution: {integrity: sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ==} + /vite@5.2.12: + resolution: {integrity: sha512-/gC8GxzxMK5ntBwb48pR32GGhENnjtY30G4A0jemunsBkiEZFw60s8InGpN8gkhHEkjnRK1aSAxeQgwvFhUHAA==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -3941,7 +3941,7 @@ packages: fsevents: 2.3.3 dev: true - /vitefu@0.2.5(vite@5.2.11): + /vitefu@0.2.5(vite@5.2.12): resolution: {integrity: sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==} peerDependencies: vite: ^3.0.0 || ^4.0.0 || ^5.0.0 @@ -3949,7 +3949,7 @@ packages: vite: optional: true dependencies: - vite: 5.2.11 + vite: 5.2.12 dev: true /walker@1.0.8: diff --git a/ui/src/components/feed/feed-item.tsx b/ui/src/components/feed/feed-item.tsx index e2b7f16..88cd4d2 100644 --- a/ui/src/components/feed/feed-item.tsx +++ b/ui/src/components/feed/feed-item.tsx @@ -7,7 +7,6 @@ import { Dynamic } from 'solid-js/web'; import { useFeedsStats } from '~/hooks/queries/use-feeds-stats'; import { useQueryState } from '~/hooks/use-query-state'; import type { Feed } from '~/types/bindings'; -import { MenuFeed } from '../menus/menu-feed'; type FeedItemProps = { feed: Feed; @@ -36,9 +35,6 @@ export const FeedItem: Component = props => { setOpen={setOpen} unread_count={getStats()?.count_unread} favicon_src={getFaviconSrc()} - menu={() => ( - - )} /> ); }; @@ -52,20 +48,19 @@ type BaseFeedItemProps = { setOpen: Setter; favicon_src?: string; icon?: () => JSX.Element; - menu: () => JSX.Element; }; export const BaseFeedItem: Component = props => (
@@ -85,14 +80,10 @@ export const BaseFeedItem: Component = props => ( {props.title} - + {props.unread_count} - - ); diff --git a/ui/src/components/feed/feed-list.tsx b/ui/src/components/feed/feed-list.tsx index 4fdb43b..1daeb41 100644 --- a/ui/src/components/feed/feed-list.tsx +++ b/ui/src/components/feed/feed-list.tsx @@ -4,7 +4,6 @@ import { For, Match, Switch, createSignal } from 'solid-js'; import { useFeeds } from '~/hooks/queries/use-feeds'; import { useFeedsStats } from '~/hooks/queries/use-feeds-stats'; import { useQueryState } from '~/hooks/use-query-state'; -import { MenuFeeds } from '../menus/menu-feeds'; import { BaseFeedItem, FeedItem } from './feed-item'; export const FeedList = () => { @@ -26,13 +25,12 @@ export const FeedList = () => { active={location.pathname === '/'} setOpen={setAllFeedsMenuOpen} unread_count={totalStats()?.count_unread} - menu={() => ( - - )} />
-

Feeds

+

+ Feeds +

Error: {feeds.error?.message}

diff --git a/ui/src/components/layout/sidebar.tsx b/ui/src/components/layout/sidebar.tsx index e4db0aa..eab2d9e 100644 --- a/ui/src/components/layout/sidebar.tsx +++ b/ui/src/components/layout/sidebar.tsx @@ -2,7 +2,6 @@ import { cx } from 'class-variance-authority'; import { type Component, createSignal } from 'solid-js'; import { FeedList } from '../feed/feed-list'; import { MenuSettings } from '../menus/menu-settings'; -import { CreateFeed } from '../modals/create-feed'; import { LogoSquare } from './logo'; type SidebarProps = { @@ -20,7 +19,6 @@ export const Sidebar: Component = props => {
-
); }; diff --git a/ui/src/components/menus/menu-feed.tsx b/ui/src/components/menus/menu-feed.tsx index c262fa7..a9ec281 100644 --- a/ui/src/components/menus/menu-feed.tsx +++ b/ui/src/components/menus/menu-feed.tsx @@ -1,3 +1,4 @@ +import { HiSolidArrowPath, HiSolidPencilSquare, HiSolidTrash } from 'solid-icons/hi'; import { type Component, mergeProps } from 'solid-js'; import { useRefreshFeed } from '~/hooks/queries/use-refresh-feed'; import { Menu, type MenuProps } from './menu'; @@ -23,10 +24,16 @@ export const MenuFeed: Component = props => { }; return ( - - Refresh - Rename - Delete + + + Refresh + + + Rename + + + Delete + ); }; diff --git a/ui/src/components/menus/menu-feeds.tsx b/ui/src/components/menus/menu-feeds.tsx index e7dddea..02c5241 100644 --- a/ui/src/components/menus/menu-feeds.tsx +++ b/ui/src/components/menus/menu-feeds.tsx @@ -1,3 +1,4 @@ +import { HiSolidArrowPath } from 'solid-icons/hi'; import { type Component, mergeProps } from 'solid-js'; import { useRefreshFeeds } from '~/hooks/queries/use-refresh-feeds'; import { Menu, type MenuProps } from './menu'; @@ -19,8 +20,10 @@ export const MenuFeeds: Component = props => { }; return ( - - Refresh all feeds + + + Refresh all feeds + ); }; diff --git a/ui/src/components/menus/menu-settings.tsx b/ui/src/components/menus/menu-settings.tsx index 00e526e..ff452a7 100644 --- a/ui/src/components/menus/menu-settings.tsx +++ b/ui/src/components/menus/menu-settings.tsx @@ -1,8 +1,18 @@ +import { + HiSolidArrowDownTray, + HiSolidArrowRightOnRectangle, + HiSolidCog, + HiSolidCog6Tooth, + HiSolidPlus, +} from 'solid-icons/hi'; import { TiCog } from 'solid-icons/ti'; -import { type Component, mergeProps } from 'solid-js'; +import { type Component, createSignal, mergeProps } from 'solid-js'; +import { CreateFeedModal } from '../modals/create-feed'; import { Menu, type MenuProps } from './menu'; export const MenuSettings: Component = props => { + const [createFeedModalOpen, setCreateFeedModalOpen] = createSignal(false); + const local = mergeProps( { triggerClass: 'h-6 w-6 rounded-md', @@ -12,11 +22,28 @@ export const MenuSettings: Component = props => { props, ); + const handleAddFeed = () => { + setCreateFeedModalOpen(true); + }; + return ( - - Import/export - Settings - Sign out - + <> + + + Add feed + + + Import/export + + + Settings + + + Sign out + + + + + ); }; diff --git a/ui/src/components/menus/menu.tsx b/ui/src/components/menus/menu.tsx index e8832c2..66d6671 100644 --- a/ui/src/components/menus/menu.tsx +++ b/ui/src/components/menus/menu.tsx @@ -4,19 +4,15 @@ import { type DropdownMenuRootProps, type DropdownMenuTriggerProps, } from '@kobalte/core/dropdown-menu'; -import { cx } from 'class-variance-authority'; +import { type VariantProps, cx } from 'class-variance-authority'; import type { IconTypes } from 'solid-icons'; import { HiSolidEllipsisHorizontal } from 'solid-icons/hi'; import { type ParentComponent, type Setter, splitProps } from 'solid-js'; import { Dynamic } from 'solid-js/web'; - -type SharedMenuProps = { - forceFocus?: boolean; - onlyDisplayForGroup?: boolean; -}; +import * as menuClasses from '~/constants/ui/menu'; export type MenuProps = Omit & - SharedMenuProps & { + MenuContentProps & { open: boolean; setOpen: Setter; triggerIcon?: IconTypes; @@ -26,83 +22,64 @@ export type MenuProps = Omit & const MenuRoot: ParentComponent = props => { const [local, rest] = splitProps(props, [ + 'size', 'children', 'open', 'setOpen', - 'forceFocus', 'triggerIcon', 'triggerClass', 'triggerIconClass', - 'onlyDisplayForGroup', ]); return ( - + - {local.children} + {local.children} ); }; -type MenuTrigger = DropdownMenuTriggerProps & - SharedMenuProps & { - class?: string; - }; +type MenuTrigger = DropdownMenuTriggerProps & { + class?: string; +}; const MenuTrigger: ParentComponent = props => { - const [local, rest] = splitProps(props, ['onlyDisplayForGroup', 'forceFocus', 'class']); + const [local, rest] = splitProps(props, ['class']); return ( - + {props.children} ); }; -const MenuItem: ParentComponent = props => ( - - {props.children} - -); +type MenuItemProps = DropdownMenuItemProps & { + icon?: IconTypes; +}; + +const MenuItem: ParentComponent = props => { + const [local, rest] = splitProps(props, ['icon']); + + return ( + + + {props.children} + + ); +}; + +type MenuContentProps = VariantProps; -const MenuContent: ParentComponent = props => ( +const MenuContent: ParentComponent = props => ( -
{props.children}
+
{props.children}
); diff --git a/ui/src/components/modals/create-feed.tsx b/ui/src/components/modals/create-feed.tsx index 73beb2a..0687379 100644 --- a/ui/src/components/modals/create-feed.tsx +++ b/ui/src/components/modals/create-feed.tsx @@ -1,26 +1,24 @@ -import type { PolymorphicCallbackProps } from '@kobalte/core'; -import { Dialog, type DialogTriggerOptions } from '@kobalte/core/dialog'; +import { Dialog } from '@kobalte/core/dialog'; import { TextField } from '@kobalte/core/text-field'; import { useNavigate } from '@solidjs/router'; import { createMutation, useQueryClient } from '@tanstack/solid-query'; -import { cx } from 'class-variance-authority'; -import { HiSolidPlus, HiSolidXMark } from 'solid-icons/hi'; -import { type Component, createSignal } from 'solid-js'; +import { HiSolidXMark } from 'solid-icons/hi'; +import { type Component, type Setter, createSignal } from 'solid-js'; import { addFeed } from '~/api/feeds'; import { QUERY_KEYS } from '~/constants/query'; import { inputClass } from '~/constants/ui/input'; -import { Button, type ButtonProps } from '../ui/button'; +import { Button } from '../ui/button'; import { Spinner } from '../ui/spinner'; type CreateFeedProps = { - triggerClass?: string; + open: boolean; + setOpen: Setter; }; -export const CreateFeed: Component = props => { +export const CreateFeedModal: Component = props => { const queryClient = useQueryClient(); const navigate = useNavigate(); - const [open, setOpen] = createSignal(false); const [value, setValue] = createSignal(''); const [inputElement, setInputElement] = createSignal(); @@ -40,7 +38,7 @@ export const CreateFeed: Component = props => { const feed = await add.mutateAsync({ url: value() }); queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.FEEDS] }); navigate(`/feeds/${feed.uuid}`); - setOpen(false); + props.setOpen(false); add.reset(); setValue(''); }; @@ -51,69 +49,53 @@ export const CreateFeed: Component = props => { }; return ( - <> - - ) => ( - - )} - /> - - - - -
- -
-
- Add a new feed - - - - -
- - Add an RSS feed link or the website's URL. Feed entries will be fetched in the background. - -
- -
-
- - URL - - - -
- - - {isDisabled() && } -
-
- - {add.isError &&

Error: {add.error?.message}

} + + + + +
+ +
+
+ Add a new feed + + + +
- -
- -
- + + Add an RSS feed link or the website's URL. Feed entries will be fetched in the background. + +
+ +
+
+ + URL + + + +
+ + + {isDisabled() && } +
+
+ + {add.isError &&

Error: {add.error?.message}

} +
+
+
+
+
); }; diff --git a/ui/src/components/nav/nav-row.tsx b/ui/src/components/nav/nav-row.tsx index 03ff73f..bd54bb2 100644 --- a/ui/src/components/nav/nav-row.tsx +++ b/ui/src/components/nav/nav-row.tsx @@ -3,10 +3,11 @@ import type { TooltipTriggerProps } from '@kobalte/core/tooltip'; import { useNavigate } from '@solidjs/router'; import { cx } from 'class-variance-authority'; import { HiOutlineQueueList, HiSolidArrowLeft, HiSolidXMark } from 'solid-icons/hi'; -import type { Component, Setter } from 'solid-js'; +import { type Component, type Setter, createSignal } from 'solid-js'; import { Dynamic } from 'solid-js/web'; import { useQueryState } from '~/hooks/use-query-state'; import { LogoSquare } from '../layout/logo'; +import { MenuSettings } from '../menus/menu-settings'; import { Tooltip } from '../ui/tooltip'; type NavRowProps = { @@ -21,9 +22,12 @@ export const NavRow: Component = props => { const state = useQueryState(); const navigate = useNavigate(); + const [settingsOpen, setSettingsOpen] = createSignal(false); + return (
+
{props.showFeedSwitch && ( diff --git a/ui/src/components/nav/nav-view-switcher.tsx b/ui/src/components/nav/nav-view-switcher.tsx index 67bed70..581b608 100644 --- a/ui/src/components/nav/nav-view-switcher.tsx +++ b/ui/src/components/nav/nav-view-switcher.tsx @@ -12,7 +12,7 @@ export const NavViewSwitcher = () => { state.setView(value as View)} - class="flex w-full self-stretch rounded-lg bg-gray-200/40 font-medium text-gray-600 text-xs backdrop-blur-sm dark:bg-gray-400/25 dark:text-white" + class="flex w-full select-none self-stretch rounded-lg bg-gray-200/40 font-medium text-gray-600 text-xs backdrop-blur-sm dark:bg-gray-400/25 dark:text-white" > diff --git a/ui/src/constants/ui/menu.ts b/ui/src/constants/ui/menu.ts new file mode 100644 index 0000000..a5a34fc --- /dev/null +++ b/ui/src/constants/ui/menu.ts @@ -0,0 +1,37 @@ +import { cva } from 'class-variance-authority'; + +export const trigger = cva([ + 'flex shrink-0 appearance-none items-center justify-center border border-gray-200 transition dark:border-gray-700', + 'bg-white focus:border-gray-400 hover:bg-gray-100 group-hover:opacity-100 focus:outline-none dark:focus:ring-gray-600 focus:ring-1 focus:ring-gray-200', + 'dark:hover:border-gray-700 hover:border-gray-300 dark:bg-gray-800 dark:hover:bg-gray-600', +]); + +export const item = cva([ + 'flex select-none appearance-none items-center gap-2 rounded px-2 py-1 text-left', + 'ui-disabled:cursor-not-allowed ui-disabled:opacity-50', + 'active:bg-gray-100 focus:bg-gray-100 hover:bg-gray-100 focus:outline-none', + 'dark:active:bg-gray-700 dark:focus:bg-gray-700 dark:hover:bg-gray-700 dark:focus:outline-none', +]); + +export const content = cva( + [ + 'z-50 overflow-hidden rounded-md border shadow-sm', + 'border-gray-200 bg-white text-gray-600', + 'dark:border-gray-700 dark:bg-gray-900 dark:text-gray-200', + 'animate-content-hide ui-expanded:animate-content-show', + ], + { + variants: { + size: { + sm: 'min-w-28', + md: 'min-w-36', + lg: 'min-w-40', + }, + }, + defaultVariants: { + size: 'md', + }, + }, +); + +export const contentInner = cva(['flex flex-col gap-0.5 p-1 text-sm']); diff --git a/ui/src/routes/feed.tsx b/ui/src/routes/feed.tsx index 6e35884..52baea0 100644 --- a/ui/src/routes/feed.tsx +++ b/ui/src/routes/feed.tsx @@ -98,6 +98,8 @@ export default () => { {showPanel() && !showFeeds() && ( <> + +
{state.params.feed_uuid ? ( @@ -114,8 +116,6 @@ export default () => {
)}
- - )}