diff --git a/.browserlist b/.browserlist
new file mode 100644
index 0000000..b547231
--- /dev/null
+++ b/.browserlist
@@ -0,0 +1 @@
+>0.3% and not dead, firefox>=98, safari>=15.4, chrome>=84
\ No newline at end of file
diff --git a/README.md b/README.md
index a4c432a..0bb7288 100644
--- a/README.md
+++ b/README.md
@@ -8,17 +8,17 @@ Tutu is a comfortable experience for tooting. Designed to work on any device - d
The code is built against those targets and Tutu must run on those platforms:
-| Firefox | Safari | iOS | Chrome & Edge |
-| ------- | ------ | ----- | ------------- |
-| 115 | 15.6 | 15.6 | 108 |
+| Firefox | Safari | iOS | Chrome | Edge |
+| ------- | ------ | ----- | ------ | ---- |
+| 98 | 15.4 | 15.4 | 84 | 87 |
Tutu trys to push the Web technology to its limit. Some features might not be available on the platform does not meet the requirement.
-## The "Nightly" Branch
+## The "Next" Branch
-Tutu built on the latest code, called the nightly version. You can tatse latest change but risks your data.
+The "next" branch of the app is built on every commit pushed into "master". You can tatse latest change but risks your data.
-[Launch Tutu (Nightly)](https://master.tututheapp.pages.dev)
+[Launch Tutu (Next)](https://master.tututheapp.pages.dev)
## Build & Depoly
diff --git a/bun.lockb b/bun.lockb
index cd4221a..bec25b1 100755
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/docs/devnotes.md b/docs/devnotes.md
index 6e10652..577c968 100644
--- a/docs/devnotes.md
+++ b/docs/devnotes.md
@@ -84,64 +84,3 @@ But, sometimes you need a redesigned (sometimes better) tool for the generic usa
- *What* this new tool does?
- *How* this tool works?
- Clean up code regularly. Don't keep the unused code forever.
-
-## Managing CSS
-
-Two techniques are still:
-
-- Styled compoenent (solid-styled)
-- Native CSS with CSS layering
-
-The second is recommended for massive use. A stylesheet for a component can be placed alongside
-the component's file. The stylesheet must use the same name as the component's file name, but replace the extension with
-`.css`. Say there is a component file "PreviewCard.tsx", the corresponding stylesheet is "PreviewCard.css". They are imported
-by the component file, so the side effect will be applied by the bundler.
-
-The speicifc component uses a root class to scope the rulesets' scope. This convention allows the component's style can be influenced
-by the other stylesheets. It works because Tutu is an end-user application, we gain the control of all stylesheets in the app (kind of).
-Keep in mind that the native stylesheets will be applied globally at any time, you must carefully craft the stylesheet to avoid leaking
-of style.
-
-Three additional CSS layers are declared as:
-
-- compat: Compatibility rules, like normalize.css
-- theme: The theme rules
-- material: The internal material styles
-
-When working on the material package, if the style is intended to work with the user styles,
-it must be declared under the material layer. Otherwise the unlayer, which has the
-highest priority in the author's, can be used.
-
-Styled component is still existing. Though styled component, using attributes for scoping,
-may not be as performant as the techniques with CSS class names;
-it's still provided in the code infrastructure for its ease.
-
-The following is an example of the recommended usage of solid-styled:
-
-```tsx
-// An example of using solid-styled
-import { css } from "solid-styled";
-import { createSignal } from "solid-js";
-
-const Component = () => {
- const [width, setWidth] = createSignal(100);
-
- css`
- .root {
- width: ${width()}%;
- }
- `
- return
-};
-```
-
-When developing new component, you can use styled component at first, and migrate
-to native css slowly.
-
-Before v2.0.0, there are CSS modules in use, but they are removed:
-
-- Duplicated loads
-- Unaware of order (failed composing)
-- Not-ready for hot reload
-
-In short, CSS module does not works well if the stylesheet will be accessed from more than one component.
diff --git a/docs/versioning.md b/docs/versioning.md
deleted file mode 100644
index 4d50356..0000000
--- a/docs/versioning.md
+++ /dev/null
@@ -1,32 +0,0 @@
-# Versioning & Development Cycle
-
-The versioning policy follows the [Semantic Versioning](https://semver.org/).
-Since Tutu is an app for the end user, we redefine the some words in the policy:
-
-- API changes: the app is no longer available on certain platforms.
-
-## Development Cycle
-
-Dependency Freeze -> Development -> Release
-
-### Dependency Freeze
-
-This step is for:
-
-- Update dependencies
-- Prepare the new version (like, bump the version number).
-
-New dependencies should not be added in this step.
-
-### Development
-
-In this step, dependencies can only be updated if it's required to fix bugs.
-
-New dependencies should be added as their use, in this step.
-
-### Release
-
-The version is released to production in this step.
-
-Before the next development step, new versions can still be released to
-fix bugs.
diff --git a/package.json b/package.json
index 69b71d9..6222ecd 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package",
"name": "tutu",
- "version": "2.0.0",
+ "version": "1.1.0",
"description": "",
"private": true,
"type": "module",
@@ -10,40 +10,30 @@
"preview": "vite preview",
"dist": "vite build",
"count-source-lines": "exec scripts/src-lc.sh",
- "typecheck": "tsc --noEmit --skipLibCheck",
- "wdio": "wdio run ./wdio.conf.ts"
+ "typecheck": "tsc --noEmit --skipLibCheck"
},
"keywords": [],
"author": "Rubicon",
"license": "Apache-2.0",
"devDependencies": {
- "@solid-devtools/overlay": "^0.33.0",
+ "@solid-devtools/overlay": "^0.30.1",
"@suid/vite-plugin": "^0.3.1",
- "@testing-library/webdriverio": "^3.2.1",
"@types/hammerjs": "^2.0.46",
"@types/masonry-layout": "^4.2.8",
"@vite-pwa/assets-generator": "^0.2.6",
- "@wdio/cli": "^9.5.1",
- "@wdio/lighthouse-service": "^9.5.1",
- "@wdio/local-runner": "^9.5.1",
- "@wdio/mocha-framework": "^9.5.0",
- "@wdio/spec-reporter": "^9.5.0",
"postcss": "^8.4.49",
- "prettier": "^3.4.2",
- "tsx": "^4.19.2",
- "typescript": "^5.7.2",
- "vite": "^6.0.7",
+ "prettier": "^3.3.3",
+ "typescript": "^5.6.3",
+ "vite": "^5.4.11",
"vite-plugin-package-version": "^1.1.0",
- "vite-plugin-pwa": "^0.21.1",
- "vite-plugin-solid": "^2.11.0",
+ "vite-plugin-pwa": "^0.20.5",
+ "vite-plugin-solid": "^2.10.2",
"vite-plugin-solid-styled": "^0.11.1",
- "wdio-vite-service": "^2.0.0",
- "wdio-wait-for": "^3.0.11",
"workbox-build": "^7.3.0",
- "wrangler": "^3.99.0"
+ "wrangler": "^3.86.1"
},
"dependencies": {
- "@formatjs/intl-localematcher": "^0.5.10",
+ "@formatjs/intl-localematcher": "^0.5.7",
"@nanostores/persistent": "^0.10.2",
"@nanostores/solid": "^0.5.0",
"@solid-primitives/event-listener": "^2.3.3",
@@ -52,8 +42,8 @@
"@solid-primitives/map": "^0.4.13",
"@solid-primitives/page-visibility": "^2.0.17",
"@solid-primitives/resize-observer": "^2.0.26",
- "@solidjs/router": "^0.15.2",
"@solid-primitives/rootless": "^1.4.5",
+ "@solidjs/router": "^0.15.1",
"@suid/icons-material": "^0.8.1",
"@suid/material": "^0.18.0",
"blurhash": "^2.0.5",
@@ -66,10 +56,9 @@
"masto": "^6.10.1",
"nanostores": "^0.11.3",
"normalize.css": "^8.0.1",
- "solid-devtools": "^0.33.0",
+ "solid-devtools": "^0.30.1",
"solid-js": "^1.9.3",
"solid-styled": "^0.11.1",
- "solid-transition-group": "^0.2.3",
"stacktrace-js": "^2.0.2",
"workbox-core": "^7.3.0",
"workbox-precaching": "^7.3.0"
diff --git a/src/App.css b/src/App.css
index d2643a9..70ee2fb 100644
--- a/src/App.css
+++ b/src/App.css
@@ -1,46 +1,41 @@
-@layer compat, theme, material;
+@import "normalize.css/normalize.css";
+@import "./material/theme.css";
-@import "normalize.css/normalize.css" layer(compat);
-@import "./material/theme.css" layer(theme);
-@import "./material/material.css" layer(material);
+:root {
+ --safe-area-inset-top: env(safe-area-inset-top);
+ --safe-area-inset-left: env(safe-area-inset-left);
+ --safe-area-inset-bottom: env(safe-area-inset-bottom);
+ --safe-area-inset-right: env(safe-area-inset-right);
+ background-color: var(--tutu-color-surface, transparent);
+}
-@layer compat {
- :root {
- --safe-area-inset-top: env(safe-area-inset-top);
- --safe-area-inset-left: env(safe-area-inset-left);
- --safe-area-inset-bottom: env(safe-area-inset-bottom);
- --safe-area-inset-right: env(safe-area-inset-right);
- background-color: var(--tutu-color-surface, transparent);
+/*
+Fix the bottom gap on iOS standalone.
+https://stackoverflow.com/questions/66005655/pwa-ios-child-of-body-not-taking-100-height-gap-on-bottom
+*/
+@media screen and (display-mode: standalone) {
+ body {
+ width: 100%;
+ height: 100vh;
}
- /*
- Fix the bottom gap on iOS standalone.
- https://stackoverflow.com/questions/66005655/pwa-ios-child-of-body-not-taking-100-height-gap-on-bottom
- */
- @media screen and (display-mode: standalone) {
- body {
- width: 100%;
- height: 100vh;
- }
-
- #root {
- position: fixed;
- top: 0;
- left: 0;
- height: 100vh;
- width: 100vw;
- }
- }
-
- h1 {
- margin: 0;
- }
-
- * {
- user-select: none;
+ #root {
+ position: fixed;
+ top: 0;
+ left: 0;
+ height: 100vh;
+ width: 100vw;
}
}
.custom-emoji {
width: 1em;
-}
\ No newline at end of file
+}
+
+h1 {
+ margin: 0;
+}
+
+* {
+ user-select: none;
+}
diff --git a/src/accounts/MastodonOAuth2Callback.css b/src/accounts/MastodonOAuth2Callback.css
deleted file mode 100644
index c150d03..0000000
--- a/src/accounts/MastodonOAuth2Callback.css
+++ /dev/null
@@ -1,22 +0,0 @@
-.MastodonOAuth2Callback {
- position: absolute;
- left: 50%;
- top: 50%;
- transform: translate(-50%, -50%);
- width: 448px;
-
- @media (max-width: 600px) {
- & {
- position: static;
- height: 100%;
- width: 100%;
- left: 0;
- right: 0;
- transform: none;
- display: grid;
- grid-template-rows: 1fr auto;
- height: 100vh;
- overflow: auto;
- }
- }
-}
\ No newline at end of file
diff --git a/src/accounts/MastodonOAuth2Callback.tsx b/src/accounts/MastodonOAuth2Callback.tsx
index d530095..398d79d 100644
--- a/src/accounts/MastodonOAuth2Callback.tsx
+++ b/src/accounts/MastodonOAuth2Callback.tsx
@@ -8,13 +8,13 @@ import {
} from "solid-js";
import { acceptAccountViaAuthCode } from "./stores";
import { $settings } from "../settings/stores";
-import "~material/cards.css";
+import { useDocumentTitle } from "../utils";
+import cards from "~material/cards.module.css";
import { LinearProgress } from "@suid/material";
import Img from "~material/Img";
import { createRestAPIClient } from "masto";
import { Title } from "~material/typography";
import { useNavigator } from "~platform/StackedRouter";
-import DocumentTitle from "~platform/DocumentTitle";
type OAuth2CallbackParams = {
code?: string;
@@ -27,12 +27,13 @@ const MastodonOAuth2Callback: Component = () => {
const titleId = createUniqueId();
const [params] = useSearchParams();
const { push: navigate } = useNavigator();
+ const setDocumentTitle = useDocumentTitle("Back from Mastodon...");
const [siteImg, setSiteImg] = createSignal<{
src: string;
srcset?: string;
blurhash: string;
}>();
- const [siteTitle, setSiteTitle] = createSignal("Mastodon");
+ const [siteTitle, setSiteTitle] = createSignal("the Mastodon server");
onMount(async () => {
const onGoingOAuth2Process = $settings.get().onGoingOAuth2Process;
@@ -41,6 +42,7 @@ const MastodonOAuth2Callback: Component = () => {
url: onGoingOAuth2Process,
});
const ins = await client.v2.instance.fetch();
+ setDocumentTitle(`Back from ${ins.title}...`);
setSiteTitle(ins.title);
const srcset = [];
@@ -91,45 +93,42 @@ const MastodonOAuth2Callback: Component = () => {
});
});
return (
- <>
- Back from {siteTitle()}
-
-