diff --git a/README.md b/README.md
index f235868f..aab25c0e 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,8 @@ Phanpy
+**π£οΈ Pronunciation**: [`/fΓ¦npi/`](https://ythi.net/how-do-you-pronounce/phanpy/english/) ([`FAN-pee`](https://www.smogon.com/forums/threads/the-official-name-pronunciation-guide.3474941/)) [π Listen](https://www.youtube.com/watch?v=DIUbWe-ysJI)
+
This is an alternative web client for [Mastodon](https://joinmastodon.org/).
- π’ **Production**: https://phanpy.social
@@ -23,13 +25,7 @@ This is an alternative web client for [Mastodon](https://joinmastodon.org/).
π Follow [@phanpy on Mastodon](https://hachyderm.io/@phanpy) for updates β¨
-Everything is designed and engineered for my own use case, following my taste and vision. This is a personal side project for me to learn about Mastodon and experiment with new UI/UX ideas.
-
-π§π§π§π§π§π§π§π§π§π§π§π§π§π§π§π§π§π§π§π§π§π§π§π§
-
-**π This is an early ALPHA project. Many features are missing, many bugs are present. Please report issues as detailed as possible. Thanks π**
-
-π§π§π§π§π§π§π§π§π§π§π§π§π§π§π§π§π§π§π§π§π§π§π§π§
+Everything is designed and engineered following my taste and vision. This is a personal side project for me to learn about Mastodon and experiment with new UI/UX ideas.
## Features
@@ -37,7 +33,7 @@ Everything is designed and engineered for my own use case, following my taste an
- πͺ Compose window pop-out/in
- π Light/dark/auto theme
- π Grouped notifications
-- πͺΊ Nested replies view
+- πͺΊ Nested comments thread
- π¬Β Unsent draft recovery
- π Β Boosts Carouselβ’οΈ
- β‘ Shortcutsβ’οΈ with view modes like multi-column or tab bar
@@ -51,6 +47,33 @@ Everything is designed and engineered for my own use case, following my taste an
- **No autoplay for video/GIF/whatever in timeline**.
The timeline is already a huge mess with lots of people, brands, news and media trying to grab your attention. Let's not make it worse. (Current exception now would be animated emojis.)
- **Hash-based URLs**.
This web app is not meant to be a full-fledged replacement to Mastodon's existing front-end. There's no SEO, database, serverless or any long-running servers. I could be wrong one day.
+## Subtle UI implementations
+
+### User name display
+
+![User name display](readme-assets/user-name-display.jpg)
+
+- On the timeline, the user name is displayed as `[NAME] @[username]`.
+- For the `@[username]`, always exclude the instance domain name.
+- If the `[NAME]` *looks the same* as the `@[username]`, then the `@[username]` is excluded as well.
+
+### Boosts Carousel
+
+![Boosts Carousel](readme-assets/boosts-carousel.jpg)
+
+- From the fetched posts (e.g. 20 posts per fetch), if number of boosts are more than quarter of total posts or more than 3 consecutive boosts, boosts carousel UI will be triggered.
+- If number of boosts are more than 3 quarters of total posts, boosts carousel UI will be slotted at the end of total posts fetched (per "page").
+- Else, boosts carousel UI will be slotted in between the posts.
+
+### Thread number badge (e.g. Thread 1/X)
+
+![Thread number badge](readme-assets/thread-number-badge.jpg)
+
+- Check every post for `inReplyToId` from cache or additional API requests, until the root post is found.
+- If root post is found, badge will show the index number of the post in the thread.
+- Limit up to 3 API requests as the root post may be very old or the thread is super long.
+- If index number couldn't be found, badge will fallback to showing `Thread` without the number.
+
## Development
Prerequisites: Node.js 18+
@@ -63,6 +86,12 @@ Prerequisites: Node.js 18+
- requires `.env.dev` file with `INSTANCES_SOCIAL_SECRET_TOKEN` variable set
- `npm run sourcemap` - Run `source-map-explorer` on the production build
+## Self-hosting
+
+This is a **pure static web app**. You can host it anywhere you want. Build it by running `npm run build` and serve the `dist` folder.
+
+Try search for "how to self-host static sites" as there are many ways to do it.
+
## Tech stack
- [Vite](https://vitejs.dev/) - Build tool
diff --git a/package-lock.json b/package-lock.json
index 906d5451..ac8811d4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,16 +10,16 @@
"dependencies": {
"@formatjs/intl-localematcher": "~0.2.32",
"@github/text-expander-element": "~2.3.0",
- "@iconify-icons/mingcute": "~1.2.4",
+ "@iconify-icons/mingcute": "~1.2.5",
"@justinribeiro/lite-youtube": "~1.5.0",
- "@szhsin/react-menu": "~3.5.2",
+ "@szhsin/react-menu": "~3.5.3",
"dayjs": "~1.11.7",
"dayjs-twitter": "~0.5.0",
"fast-blurhash": "~1.1.2",
"fast-deep-equal": "~3.1.3",
- "idb-keyval": "~6.2.0",
+ "idb-keyval": "~6.2.1",
"just-debounce-it": "~3.2.0",
- "masto": "~5.11.2",
+ "masto": "~5.11.3",
"mem": "~9.0.2",
"p-retry": "~5.1.2",
"p-throttle": "~5.0.0",
@@ -33,7 +33,7 @@
"toastify-js": "~1.12.0",
"uid": "~2.0.2",
"use-debounce": "~9.0.4",
- "use-long-press": "~3.1.0",
+ "use-long-press": "~3.1.3",
"use-resize-observer": "~9.1.0",
"valtio": "1.9.0"
},
@@ -44,7 +44,7 @@
"postcss-dark-theme-class": "~0.7.3",
"postcss-preset-env": "~8.3.2",
"twitter-text": "~3.1.0",
- "vite": "~4.3.3",
+ "vite": "~4.3.5",
"vite-plugin-generate-file": "~0.0.4",
"vite-plugin-html-config": "~1.0.11",
"vite-plugin-pwa": "~0.14.7",
@@ -2667,9 +2667,9 @@
}
},
"node_modules/@iconify-icons/mingcute": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/@iconify-icons/mingcute/-/mingcute-1.2.4.tgz",
- "integrity": "sha512-4aaWYa6GxSdYmJg8iBVx6VDuKUcTDEbio929+GrswoxfyTsPUkOOgw2wffUDHjE3JDUAnrWj9teQTnBkFm7Gyg==",
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/@iconify-icons/mingcute/-/mingcute-1.2.5.tgz",
+ "integrity": "sha512-fTzhb0TVYuD89Do9sUR9mu2RYZ2XGOyOxzoZL2W53R9w+j0myuo0bnRpoGlbnXPV+/N+P8vUBJEsQRWvmEPQfw==",
"dependencies": {
"@iconify/types": "*"
}
@@ -2962,9 +2962,9 @@
}
},
"node_modules/@szhsin/react-menu": {
- "version": "3.5.2",
- "resolved": "https://registry.npmjs.org/@szhsin/react-menu/-/react-menu-3.5.2.tgz",
- "integrity": "sha512-eR7dzDBrwlt9RSgGmLXjfA1Rd5tYqD5mnqjQgZJysf3Jt3vBPkrbDT1oW21nLpfUCkyUQOuZ38n2IdhWl9KkzQ==",
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/@szhsin/react-menu/-/react-menu-3.5.3.tgz",
+ "integrity": "sha512-jxo8oaRwxmVjUzkyOi/ZJiXaZiuFPMIxFzyJdUKfnhBLYiEOVTU9M2CiPuEkirILoareR2GJj2K3y8a81CBPlw==",
"dependencies": {
"prop-types": "^15.7.2",
"react-transition-state": "^1.1.5"
@@ -4293,12 +4293,9 @@
"dev": true
},
"node_modules/idb-keyval": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.0.tgz",
- "integrity": "sha512-uw+MIyQn2jl3+hroD7hF8J7PUviBU7BPKWw4f/ISf32D4LoGu98yHjrzWWJDASu9QNrX10tCJqk9YY0ClWm8Ng==",
- "dependencies": {
- "safari-14-idb-fix": "^3.0.0"
- }
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.1.tgz",
+ "integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg=="
},
"node_modules/inflight": {
"version": "1.0.6",
@@ -4860,9 +4857,9 @@
}
},
"node_modules/masto": {
- "version": "5.11.2",
- "resolved": "https://registry.npmjs.org/masto/-/masto-5.11.2.tgz",
- "integrity": "sha512-1F2O4itZXCchqmGh/Dor+AfgyxKGfUrquLK81H+Adw9vs5BoOtdNThuFhXf1m2enXzbVEvJUwxBVd82s2x5FSg==",
+ "version": "5.11.3",
+ "resolved": "https://registry.npmjs.org/masto/-/masto-5.11.3.tgz",
+ "integrity": "sha512-GtSnrqm5fHPaaU0iwag4LCmvpp82rDng6yOZinmOJHHlUfo6Gnq5QY6x3lJCxCnsPIXpTu1yaX42bWrSQyoQPA==",
"dependencies": {
"@mastojs/ponyfills": "^1.0.4",
"change-case": "^4.1.2",
@@ -4870,7 +4867,7 @@
"isomorphic-ws": "^5.0.0",
"qs": "^6.11.0",
"semver": "^7.3.7",
- "ws": "^8.12.0"
+ "ws": "^8.13.0"
}
},
"node_modules/masto/node_modules/semver": {
@@ -6198,11 +6195,6 @@
"queue-microtask": "^1.2.2"
}
},
- "node_modules/safari-14-idb-fix": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/safari-14-idb-fix/-/safari-14-idb-fix-3.0.0.tgz",
- "integrity": "sha512-eBNFLob4PMq8JA1dGyFn6G97q3/WzNtFK4RnzT1fnLq+9RyrGknzYiM/9B12MnKAxuj1IXr7UKYtTNtjyKMBog=="
- },
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@@ -6739,9 +6731,9 @@
}
},
"node_modules/use-long-press": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/use-long-press/-/use-long-press-3.1.0.tgz",
- "integrity": "sha512-SSCCgsIlGql/gWRf5v/5CoWxUkSccFuLiMO2tjggUdf0qt5FGb/TD1l0aJ2j+G3J0BT2a7jsJQIDsmUiUuhRTg==",
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/use-long-press/-/use-long-press-3.1.3.tgz",
+ "integrity": "sha512-RAK+i3mIPAFL10Q9wVqfzjDTIg/oXSB60c+bbwNkc1GzIWNF7UfRydJ2VX8IQ+yG2eptzEuWb1CmJc2UNu6fOg==",
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
@@ -6793,9 +6785,9 @@
}
},
"node_modules/vite": {
- "version": "4.3.3",
- "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.3.tgz",
- "integrity": "sha512-MwFlLBO4udZXd+VBcezo3u8mC77YQk+ik+fbc0GZWGgzfbPP+8Kf0fldhARqvSYmtIWoAJ5BXPClUbMTlqFxrA==",
+ "version": "4.3.5",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.5.tgz",
+ "integrity": "sha512-0gEnL9wiRFxgz40o/i/eTBwm+NEbpUeTWhzKrZDSdKm6nplj+z4lKz8ANDgildxHm47Vg8EUia0aicKbawUVVA==",
"dev": true,
"dependencies": {
"esbuild": "^0.17.5",
@@ -7334,9 +7326,9 @@
"dev": true
},
"node_modules/ws": {
- "version": "8.12.0",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.12.0.tgz",
- "integrity": "sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==",
+ "version": "8.13.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
+ "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
"engines": {
"node": ">=10.0.0"
},
@@ -8964,9 +8956,9 @@
}
},
"@iconify-icons/mingcute": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/@iconify-icons/mingcute/-/mingcute-1.2.4.tgz",
- "integrity": "sha512-4aaWYa6GxSdYmJg8iBVx6VDuKUcTDEbio929+GrswoxfyTsPUkOOgw2wffUDHjE3JDUAnrWj9teQTnBkFm7Gyg==",
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/@iconify-icons/mingcute/-/mingcute-1.2.5.tgz",
+ "integrity": "sha512-fTzhb0TVYuD89Do9sUR9mu2RYZ2XGOyOxzoZL2W53R9w+j0myuo0bnRpoGlbnXPV+/N+P8vUBJEsQRWvmEPQfw==",
"requires": {
"@iconify/types": "*"
}
@@ -9198,9 +9190,9 @@
}
},
"@szhsin/react-menu": {
- "version": "3.5.2",
- "resolved": "https://registry.npmjs.org/@szhsin/react-menu/-/react-menu-3.5.2.tgz",
- "integrity": "sha512-eR7dzDBrwlt9RSgGmLXjfA1Rd5tYqD5mnqjQgZJysf3Jt3vBPkrbDT1oW21nLpfUCkyUQOuZ38n2IdhWl9KkzQ==",
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/@szhsin/react-menu/-/react-menu-3.5.3.tgz",
+ "integrity": "sha512-jxo8oaRwxmVjUzkyOi/ZJiXaZiuFPMIxFzyJdUKfnhBLYiEOVTU9M2CiPuEkirILoareR2GJj2K3y8a81CBPlw==",
"requires": {
"prop-types": "^15.7.2",
"react-transition-state": "^1.1.5"
@@ -10204,12 +10196,9 @@
"dev": true
},
"idb-keyval": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.0.tgz",
- "integrity": "sha512-uw+MIyQn2jl3+hroD7hF8J7PUviBU7BPKWw4f/ISf32D4LoGu98yHjrzWWJDASu9QNrX10tCJqk9YY0ClWm8Ng==",
- "requires": {
- "safari-14-idb-fix": "^3.0.0"
- }
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.1.tgz",
+ "integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg=="
},
"inflight": {
"version": "1.0.6",
@@ -10621,9 +10610,9 @@
}
},
"masto": {
- "version": "5.11.2",
- "resolved": "https://registry.npmjs.org/masto/-/masto-5.11.2.tgz",
- "integrity": "sha512-1F2O4itZXCchqmGh/Dor+AfgyxKGfUrquLK81H+Adw9vs5BoOtdNThuFhXf1m2enXzbVEvJUwxBVd82s2x5FSg==",
+ "version": "5.11.3",
+ "resolved": "https://registry.npmjs.org/masto/-/masto-5.11.3.tgz",
+ "integrity": "sha512-GtSnrqm5fHPaaU0iwag4LCmvpp82rDng6yOZinmOJHHlUfo6Gnq5QY6x3lJCxCnsPIXpTu1yaX42bWrSQyoQPA==",
"requires": {
"@mastojs/ponyfills": "^1.0.4",
"change-case": "^4.1.2",
@@ -10631,7 +10620,7 @@
"isomorphic-ws": "^5.0.0",
"qs": "^6.11.0",
"semver": "^7.3.7",
- "ws": "^8.12.0"
+ "ws": "^8.13.0"
},
"dependencies": {
"semver": {
@@ -11455,11 +11444,6 @@
"queue-microtask": "^1.2.2"
}
},
- "safari-14-idb-fix": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/safari-14-idb-fix/-/safari-14-idb-fix-3.0.0.tgz",
- "integrity": "sha512-eBNFLob4PMq8JA1dGyFn6G97q3/WzNtFK4RnzT1fnLq+9RyrGknzYiM/9B12MnKAxuj1IXr7UKYtTNtjyKMBog=="
- },
"safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@@ -11857,9 +11841,9 @@
"requires": {}
},
"use-long-press": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/use-long-press/-/use-long-press-3.1.0.tgz",
- "integrity": "sha512-SSCCgsIlGql/gWRf5v/5CoWxUkSccFuLiMO2tjggUdf0qt5FGb/TD1l0aJ2j+G3J0BT2a7jsJQIDsmUiUuhRTg==",
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/use-long-press/-/use-long-press-3.1.3.tgz",
+ "integrity": "sha512-RAK+i3mIPAFL10Q9wVqfzjDTIg/oXSB60c+bbwNkc1GzIWNF7UfRydJ2VX8IQ+yG2eptzEuWb1CmJc2UNu6fOg==",
"requires": {}
},
"use-resize-observer": {
@@ -11892,9 +11876,9 @@
}
},
"vite": {
- "version": "4.3.3",
- "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.3.tgz",
- "integrity": "sha512-MwFlLBO4udZXd+VBcezo3u8mC77YQk+ik+fbc0GZWGgzfbPP+8Kf0fldhARqvSYmtIWoAJ5BXPClUbMTlqFxrA==",
+ "version": "4.3.5",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.5.tgz",
+ "integrity": "sha512-0gEnL9wiRFxgz40o/i/eTBwm+NEbpUeTWhzKrZDSdKm6nplj+z4lKz8ANDgildxHm47Vg8EUia0aicKbawUVVA==",
"dev": true,
"requires": {
"esbuild": "^0.17.5",
@@ -12314,9 +12298,9 @@
"dev": true
},
"ws": {
- "version": "8.12.0",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.12.0.tgz",
- "integrity": "sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==",
+ "version": "8.13.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
+ "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
"requires": {}
},
"yallist": {
diff --git a/package.json b/package.json
index 91a72cd4..54eff130 100644
--- a/package.json
+++ b/package.json
@@ -12,16 +12,16 @@
"dependencies": {
"@formatjs/intl-localematcher": "~0.2.32",
"@github/text-expander-element": "~2.3.0",
- "@iconify-icons/mingcute": "~1.2.4",
+ "@iconify-icons/mingcute": "~1.2.5",
"@justinribeiro/lite-youtube": "~1.5.0",
- "@szhsin/react-menu": "~3.5.2",
+ "@szhsin/react-menu": "~3.5.3",
"dayjs": "~1.11.7",
"dayjs-twitter": "~0.5.0",
"fast-blurhash": "~1.1.2",
"fast-deep-equal": "~3.1.3",
- "idb-keyval": "~6.2.0",
+ "idb-keyval": "~6.2.1",
"just-debounce-it": "~3.2.0",
- "masto": "~5.11.2",
+ "masto": "~5.11.3",
"mem": "~9.0.2",
"p-retry": "~5.1.2",
"p-throttle": "~5.0.0",
@@ -35,7 +35,7 @@
"toastify-js": "~1.12.0",
"uid": "~2.0.2",
"use-debounce": "~9.0.4",
- "use-long-press": "~3.1.0",
+ "use-long-press": "~3.1.3",
"use-resize-observer": "~9.1.0",
"valtio": "1.9.0"
},
@@ -46,7 +46,7 @@
"postcss-dark-theme-class": "~0.7.3",
"postcss-preset-env": "~8.3.2",
"twitter-text": "~3.1.0",
- "vite": "~4.3.3",
+ "vite": "~4.3.5",
"vite-plugin-generate-file": "~0.0.4",
"vite-plugin-html-config": "~1.0.11",
"vite-plugin-pwa": "~0.14.7",
diff --git a/readme-assets/boosts-carousel.jpg b/readme-assets/boosts-carousel.jpg
new file mode 100644
index 00000000..610f23df
Binary files /dev/null and b/readme-assets/boosts-carousel.jpg differ
diff --git a/readme-assets/thread-number-badge.jpg b/readme-assets/thread-number-badge.jpg
new file mode 100644
index 00000000..8519e062
Binary files /dev/null and b/readme-assets/thread-number-badge.jpg differ
diff --git a/readme-assets/user-name-display.jpg b/readme-assets/user-name-display.jpg
new file mode 100644
index 00000000..01802ec0
Binary files /dev/null and b/readme-assets/user-name-display.jpg differ
diff --git a/src/app.css b/src/app.css
index 10c41f09..753688e9 100644
--- a/src/app.css
+++ b/src/app.css
@@ -256,6 +256,11 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
.timeline.contextual > li.descendant:not(.thread) > .status-link {
padding-left: 40px;
}
+.timeline.contextual .replies[data-scroll-left]:not([data-scroll-left='0']) {
+ background-color: var(--bg-color);
+ box-shadow: inset 0 -3px var(--comment-line-color),
+ inset 0 3px var(--comment-line-color);
+}
.timeline.contextual .replies[data-comments-level='4'] {
overflow: auto;
}
@@ -272,7 +277,7 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
.replies[data-comments-level='4']
.replies[data-comments-level-overflow='true']
.status {
- min-width: min(15em, 75vw);
+ min-width: min(20em, 80vw);
}
.timeline.contextual
> li.descendant.thread
@@ -432,7 +437,7 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
.timeline.contextual > li .replies {
margin-top: -12px;
}
-.timeline.contextual > li .replies :is(ul, li) {
+.timeline.contextual > li .replies :is(ul, li):not(.content *) {
margin: 0;
padding: 0;
list-style: none;
@@ -478,10 +483,10 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
.timeline.contextual > li .replies .replies-summary[hidden] {
display: none;
}
-.timeline.contextual > li .replies li {
+.timeline.contextual > li .replies li:not(.content li) {
position: relative;
}
-.timeline.contextual > li .replies li {
+.timeline.contextual > li .replies li:not(.content li) {
--line-start: calc(
var(--thread-start) + var(--line-margin-end) * var(--comments-level)
);
@@ -503,7 +508,7 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
.timeline.contextual > li .replies .replies .replies li {
--line-start: calc(var(--thread-start) + (var(--line-margin-end) * 3));
} */
-.timeline.contextual > li.thread .replies li {
+.timeline.contextual > li.thread .replies li:not(.content li) {
--line-start: calc(
var(--avatar-size) + var(--avatar-margin-start) + var(--avatar-margin-end) +
(var(--line-margin-end) * (var(--comments-level) - 1))
@@ -521,10 +526,10 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
(var(--line-margin-end) * 2)
);
} */
-.timeline.contextual > li .replies li:last-child {
+.timeline.contextual > li .replies li:not(.content li):last-child {
background-size: 100% 20px;
}
-.timeline.contextual > li .replies li:before {
+.timeline.contextual > li .replies li:not(.content li):before {
content: '';
position: absolute;
top: 10px;
@@ -547,7 +552,7 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
var(--thread-start) + var(--line-margin-end) + (var(--line-margin-end) * 2)
);
} */
-.timeline.contextual > li.thread .replies li:before {
+.timeline.contextual > li.thread .replies li:not(.content li):before {
--line-start: calc(
var(--avatar-size) + var(--avatar-margin-start) + var(--avatar-margin-end) +
(var(--line-margin-end) * (var(--comments-level) - 1))
@@ -709,7 +714,7 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
color: var(--carousel-color);
text-shadow: 0 1px var(--bg-color);
}
-.status-carousel ul {
+.status-carousel > ul {
display: flex;
overflow-x: auto;
overflow-y: hidden;
@@ -721,7 +726,7 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
align-items: flex-start;
counter-reset: index;
}
-.status-carousel ul > li {
+.status-carousel > ul > li {
scroll-snap-align: center;
scroll-snap-stop: always;
flex-shrink: 0;
@@ -736,8 +741,11 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
counter-increment: index;
position: relative;
}
+.status-carousel > ul > li:is(:empty, :has(> a:empty)) {
+ display: none;
+}
@media (hover: hover) or (pointer: fine) or (min-width: 40em) {
- .status-carousel ul {
+ .status-carousel > ul {
scroll-snap-type: none;
}
}
@@ -759,7 +767,7 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) {
.status-carousel.boosts-carousel .status-reblog {
background-image: none;
}
-.status-carousel.boosts-carousel ul > li:before {
+.status-carousel.boosts-carousel > ul > li:before {
content: counter(index);
position: absolute;
left: 0;
@@ -1158,12 +1166,12 @@ body:has(.media-modal-container + .status-deck) .media-post-link {
padding: 16px;
background-color: var(--button-bg-blur-color);
backdrop-filter: blur(16px);
- z-index: 1;
+ z-index: 10;
box-shadow: 0 3px 8px -1px var(--drop-shadow-color),
0 10px 36px -4px var(--button-bg-blur-color);
transition: all 0.3s ease-in-out;
}
-#home-page:has(header[hidden]) ~ #compose-button,
+.deck-container:has(header[hidden]) ~ #compose-button,
#compose-button[hidden] {
transform: translateY(200%);
pointer-events: none;
@@ -1309,6 +1317,9 @@ body:has(.media-modal-container + .status-deck) .media-post-link {
.tag .icon {
vertical-align: middle;
}
+.tag.collapsed {
+ margin: 0;
+}
/* MENU POPUP */
@@ -1897,6 +1908,9 @@ ul.link-list li a .icon {
);
align-items: center;
}
+.filter-bar.centered {
+ justify-content: center;
+}
@media (min-width: 40em) {
.filter-bar {
background-color: transparent;
diff --git a/src/app.jsx b/src/app.jsx
index a2b4c2b3..63357bff 100644
--- a/src/app.jsx
+++ b/src/app.jsx
@@ -21,6 +21,7 @@ import { useSnapshot } from 'valtio';
import AccountSheet from './components/account-sheet';
import Compose from './components/compose';
import Drafts from './components/drafts';
+import Icon from './components/icon';
import Loader from './components/loader';
import MediaModal from './components/media-modal';
import Modal from './components/modal';
@@ -55,6 +56,7 @@ import {
initPreferences,
} from './utils/api';
import { getAccessToken } from './utils/auth';
+import openCompose from './utils/open-compose';
import showToast from './utils/show-toast';
import states, { getStatus, saveStatus } from './utils/states';
import store from './utils/store';
@@ -110,7 +112,7 @@ function App() {
const masto = initClient({ instance: instanceURL, accessToken });
await Promise.allSettled([
- initInstance(masto),
+ initInstance(masto, instanceURL),
initAccount(masto, instanceURL, accessToken),
]);
initPreferences(masto);
@@ -122,13 +124,13 @@ function App() {
const account = getCurrentAccount();
if (account) {
store.session.set('currentAccount', account.info.id);
- const { masto } = api({ account });
+ const { masto, instance } = api({ account });
console.log('masto', masto);
initPreferences(masto);
setUIState('loading');
(async () => {
try {
- await initInstance(masto);
+ await initInstance(masto, instance);
} catch (e) {
} finally {
setIsLoggedIn(true);
@@ -263,13 +265,30 @@ function App() {
Also followed by{' '}
@@ -521,7 +524,7 @@ function RelatedActions({ info, instance, authenticated }) {
Following you
) : !!lastStatusAt ? (
- Last status:{' '}
+ Last post:{' '}
{niceDateTime(lastStatusAt, {
hideTime: true,
})}
@@ -778,6 +781,9 @@ function RelatedActions({ info, instance, authenticated }) {
>
)}
+ {!relationship && relationshipUIState === 'loading' && (
+