v2.0.0: Dependency Freeze #56
15 changed files with 87 additions and 67 deletions
|
@ -1 +0,0 @@
|
||||||
>0.3% and not dead, firefox>=98, safari>=15.4, chrome>=84
|
|
12
README.md
12
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:
|
The code is built against those targets and Tutu must run on those platforms:
|
||||||
|
|
||||||
| Firefox | Safari | iOS | Chrome | Edge |
|
| Firefox | Safari | iOS | Chrome & Edge |
|
||||||
| ------- | ------ | ----- | ------ | ---- |
|
| ------- | ------ | ----- | ------------- |
|
||||||
| 98 | 15.4 | 15.4 | 84 | 87 |
|
| 115 | 15.6 | 15.6 | 108 |
|
||||||
|
|
||||||
Tutu trys to push the Web technology to its limit. Some features might not be available on the platform does not meet the requirement.
|
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 "Next" Branch
|
## The "Nightly" Branch
|
||||||
|
|
||||||
The "next" branch of the app is built on every commit pushed into "master". You can tatse latest change but risks your data.
|
Tutu built on the latest code, called the nightly version. You can tatse latest change but risks your data.
|
||||||
|
|
||||||
[Launch Tutu (Next)](https://master.tututheapp.pages.dev)
|
[Launch Tutu (Nightly)](https://master.tututheapp.pages.dev)
|
||||||
|
|
||||||
## Build & Depoly
|
## Build & Depoly
|
||||||
|
|
||||||
|
|
BIN
bun.lockb
BIN
bun.lockb
Binary file not shown.
32
docs/versioning.md
Normal file
32
docs/versioning.md
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
# 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.
|
32
package.json
32
package.json
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/package",
|
"$schema": "https://json.schemastore.org/package",
|
||||||
"name": "tutu",
|
"name": "tutu",
|
||||||
"version": "1.1.0",
|
"version": "2.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
@ -17,33 +17,33 @@
|
||||||
"author": "Rubicon",
|
"author": "Rubicon",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@solid-devtools/overlay": "^0.30.1",
|
"@solid-devtools/overlay": "^0.33.0",
|
||||||
"@suid/vite-plugin": "^0.3.1",
|
"@suid/vite-plugin": "^0.3.1",
|
||||||
"@testing-library/webdriverio": "^3.2.1",
|
"@testing-library/webdriverio": "^3.2.1",
|
||||||
"@types/hammerjs": "^2.0.46",
|
"@types/hammerjs": "^2.0.46",
|
||||||
"@types/masonry-layout": "^4.2.8",
|
"@types/masonry-layout": "^4.2.8",
|
||||||
"@vite-pwa/assets-generator": "^0.2.6",
|
"@vite-pwa/assets-generator": "^0.2.6",
|
||||||
"@wdio/cli": "^9.4.5",
|
"@wdio/cli": "^9.5.1",
|
||||||
"@wdio/lighthouse-service": "^9.4.5",
|
"@wdio/lighthouse-service": "^9.5.1",
|
||||||
"@wdio/local-runner": "^9.4.5",
|
"@wdio/local-runner": "^9.5.1",
|
||||||
"@wdio/mocha-framework": "^9.4.4",
|
"@wdio/mocha-framework": "^9.5.0",
|
||||||
"@wdio/spec-reporter": "^9.4.4",
|
"@wdio/spec-reporter": "^9.5.0",
|
||||||
"postcss": "^8.4.49",
|
"postcss": "^8.4.49",
|
||||||
"prettier": "^3.3.3",
|
"prettier": "^3.4.2",
|
||||||
"tsx": "^4.19.2",
|
"tsx": "^4.19.2",
|
||||||
"typescript": "^5.6.3",
|
"typescript": "^5.7.2",
|
||||||
"vite": "^5.4.11",
|
"vite": "^6.0.7",
|
||||||
"vite-plugin-package-version": "^1.1.0",
|
"vite-plugin-package-version": "^1.1.0",
|
||||||
"vite-plugin-pwa": "^0.20.5",
|
"vite-plugin-pwa": "^0.21.1",
|
||||||
"vite-plugin-solid": "^2.10.2",
|
"vite-plugin-solid": "^2.11.0",
|
||||||
"vite-plugin-solid-styled": "^0.11.1",
|
"vite-plugin-solid-styled": "^0.11.1",
|
||||||
"wdio-vite-service": "^2.0.0",
|
"wdio-vite-service": "^2.0.0",
|
||||||
"wdio-wait-for": "^3.0.11",
|
"wdio-wait-for": "^3.0.11",
|
||||||
"workbox-build": "^7.3.0",
|
"workbox-build": "^7.3.0",
|
||||||
"wrangler": "^3.86.1"
|
"wrangler": "^3.99.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@formatjs/intl-localematcher": "^0.5.7",
|
"@formatjs/intl-localematcher": "^0.5.10",
|
||||||
"@nanostores/persistent": "^0.10.2",
|
"@nanostores/persistent": "^0.10.2",
|
||||||
"@nanostores/solid": "^0.5.0",
|
"@nanostores/solid": "^0.5.0",
|
||||||
"@solid-primitives/event-listener": "^2.3.3",
|
"@solid-primitives/event-listener": "^2.3.3",
|
||||||
|
@ -52,7 +52,7 @@
|
||||||
"@solid-primitives/map": "^0.4.13",
|
"@solid-primitives/map": "^0.4.13",
|
||||||
"@solid-primitives/page-visibility": "^2.0.17",
|
"@solid-primitives/page-visibility": "^2.0.17",
|
||||||
"@solid-primitives/resize-observer": "^2.0.26",
|
"@solid-primitives/resize-observer": "^2.0.26",
|
||||||
"@solidjs/router": "^0.15.1",
|
"@solidjs/router": "^0.15.2",
|
||||||
"@suid/icons-material": "^0.8.1",
|
"@suid/icons-material": "^0.8.1",
|
||||||
"@suid/material": "^0.18.0",
|
"@suid/material": "^0.18.0",
|
||||||
"blurhash": "^2.0.5",
|
"blurhash": "^2.0.5",
|
||||||
|
@ -65,7 +65,7 @@
|
||||||
"masto": "^6.10.1",
|
"masto": "^6.10.1",
|
||||||
"nanostores": "^0.11.3",
|
"nanostores": "^0.11.3",
|
||||||
"normalize.css": "^8.0.1",
|
"normalize.css": "^8.0.1",
|
||||||
"solid-devtools": "^0.30.1",
|
"solid-devtools": "^0.33.0",
|
||||||
"solid-js": "^1.9.3",
|
"solid-js": "^1.9.3",
|
||||||
"solid-styled": "^0.11.1",
|
"solid-styled": "^0.11.1",
|
||||||
"solid-transition-group": "^0.2.3",
|
"solid-transition-group": "^0.2.3",
|
||||||
|
|
|
@ -51,7 +51,7 @@ function animateSlideInFromBottom(element: HTMLElement, reverse?: boolean) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const BottomSheet: ParentComponent<BottomSheetProps> = (props) => {
|
const BottomSheet: ParentComponent<BottomSheetProps> = (props) => {
|
||||||
let element: HTMLDialogElement;
|
let element!: HTMLDialogElement;
|
||||||
let animation: Animation | undefined;
|
let animation: Animation | undefined;
|
||||||
const child = children(() => props.children);
|
const child = children(() => props.children);
|
||||||
|
|
||||||
|
|
|
@ -108,7 +108,7 @@ function animateGrowFromTopLeft(
|
||||||
* - Use {@link MenuItem} from SUID as children.
|
* - Use {@link MenuItem} from SUID as children.
|
||||||
*/
|
*/
|
||||||
const Menu: Component<MenuProps> = (oprops) => {
|
const Menu: Component<MenuProps> = (oprops) => {
|
||||||
let root: HTMLDialogElement;
|
let root!: HTMLDialogElement;
|
||||||
const windowSize = useWindowSize();
|
const windowSize = useWindowSize();
|
||||||
const [props, rest] = splitProps(oprops, [
|
const [props, rest] = splitProps(oprops, [
|
||||||
"open",
|
"open",
|
||||||
|
|
|
@ -1,38 +1,27 @@
|
||||||
//! This module has side effect.
|
//! This module has side effect.
|
||||||
//! It recommended to include the module by <script> tag.
|
//! It recommended to include the module by <script> tag.
|
||||||
if (typeof window.crypto.randomUUID === "undefined") {
|
|
||||||
// TODO: this polyfill can be removed in 2.0, see https://code.lightstands.xyz/Rubicon/tutu/issues/36
|
|
||||||
// Chrome/Edge 92+
|
|
||||||
// https://stackoverflow.com/a/2117523/2800218
|
|
||||||
// LICENSE: https://creativecommons.org/licenses/by-sa/4.0/legalcode
|
|
||||||
window.crypto.randomUUID =
|
|
||||||
function randomUUID(): `${string}-${string}-${string}-${string}-${string}` {
|
|
||||||
return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, (c) =>
|
|
||||||
(
|
|
||||||
+c ^
|
|
||||||
(crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (+c / 4)))
|
|
||||||
).toString(16),
|
|
||||||
) as `${string}-${string}-${string}-${string}-${string}`;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (typeof Promise.withResolvers === "undefined") {
|
if (typeof Promise.withResolvers === "undefined") {
|
||||||
// Chrome/Edge 119, Firefox 121, Safari/iOS 17.4
|
// Chrome/Edge 119, Firefox 121, Safari/iOS 17.4
|
||||||
|
|
||||||
// Promise.withResolvers is generic and works with subclasses - the typescript built-in decl
|
// Promise.withResolvers is generic and works with subclasses - the typescript built-in decl
|
||||||
// could not handle the subclassing case.
|
// could not handle the subclassing case.
|
||||||
(Promise.prototype as any).withResolvers = function <T>(this: AnyPromiseConstructor<T>) {
|
(Promise.prototype as any).withResolvers = function <T>(
|
||||||
let resolve!: PromiseWithResolvers<T>["resolve"], reject!: PromiseWithResolvers<T>["reject"];
|
this: AnyPromiseConstructor<T>,
|
||||||
|
) {
|
||||||
|
let resolve!: PromiseWithResolvers<T>["resolve"],
|
||||||
|
reject!: PromiseWithResolvers<T>["reject"];
|
||||||
// These variables are expected to be set after `new this()`
|
// These variables are expected to be set after `new this()`
|
||||||
|
|
||||||
const promise = new this((resolve0, reject0) => {
|
const promise = new this((resolve0, reject0) => {
|
||||||
resolve = resolve0;
|
resolve = resolve0;
|
||||||
reject = reject0;
|
reject = reject0;
|
||||||
})
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
promise, resolve, reject
|
promise,
|
||||||
}
|
resolve,
|
||||||
}
|
reject,
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ function clamp(input: number, min: number, max: number) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const MediaViewer: ParentComponent<MediaViewerProps> = (props) => {
|
const MediaViewer: ParentComponent<MediaViewerProps> = (props) => {
|
||||||
let rootRef: HTMLDialogElement;
|
let rootRef!: HTMLDialogElement;
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
ref?: HTMLElement;
|
ref?: HTMLElement;
|
||||||
|
|
|
@ -17,7 +17,7 @@ const PullDownToRefresh: Component<{
|
||||||
linkedElement?: HTMLElement;
|
linkedElement?: HTMLElement;
|
||||||
onRefresh?: () => void;
|
onRefresh?: () => void;
|
||||||
}> = (props) => {
|
}> = (props) => {
|
||||||
let rootElement: HTMLDivElement;
|
let rootElement!: HTMLDivElement;
|
||||||
const [pullDown, setPullDown] = createSignal(0);
|
const [pullDown, setPullDown] = createSignal(0);
|
||||||
|
|
||||||
const stopPos = () => 160;
|
const stopPos = () => 160;
|
||||||
|
|
|
@ -23,7 +23,7 @@ type ChooseTootLangProps = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const ChooseTootLang: Component<ChooseTootLangProps> = (props) => {
|
const ChooseTootLang: Component<ChooseTootLangProps> = (props) => {
|
||||||
let listRef: HTMLUListElement;
|
let listRef!: HTMLUListElement;
|
||||||
const [t] = createTranslator(
|
const [t] = createTranslator(
|
||||||
(code) =>
|
(code) =>
|
||||||
import(`./i18n/${code}.json`) as Promise<{
|
import(`./i18n/${code}.json`) as Promise<{
|
||||||
|
|
|
@ -17,7 +17,7 @@ export function PreviewCard(props: {
|
||||||
src: mastodon.v1.PreviewCard;
|
src: mastodon.v1.PreviewCard;
|
||||||
alwaysCompact?: boolean;
|
alwaysCompact?: boolean;
|
||||||
}) {
|
}) {
|
||||||
let root: HTMLAnchorElement;
|
let root!: HTMLAnchorElement;
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
if (props.alwaysCompact) {
|
if (props.alwaysCompact) {
|
||||||
|
|
|
@ -33,7 +33,7 @@ type TootPollProps = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const TootPoll: Component<TootPollProps> = (props) => {
|
const TootPoll: Component<TootPollProps> = (props) => {
|
||||||
let list: HTMLUListElement;
|
let list!: HTMLUListElement;
|
||||||
const { vote } = useTootEnv();
|
const { vote } = useTootEnv();
|
||||||
|
|
||||||
const now = useTimeSource();
|
const now = useTimeSource();
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"target": "ESNext",
|
"target": "ESNext",
|
||||||
"module": "esnext",
|
"module": "ESNext",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "bundler",
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
|
|
|
@ -4,7 +4,7 @@ import solidStyled from "vite-plugin-solid-styled";
|
||||||
import suid from "@suid/vite-plugin";
|
import suid from "@suid/vite-plugin";
|
||||||
import { VitePWA } from "vite-plugin-pwa";
|
import { VitePWA } from "vite-plugin-pwa";
|
||||||
import version from "vite-plugin-package-version";
|
import version from "vite-plugin-package-version";
|
||||||
import manifest from "./manifest.config";
|
import manifest from "./manifest.config.js";
|
||||||
import { GetManualChunk } from "rollup";
|
import { GetManualChunk } from "rollup";
|
||||||
import devtools from "solid-devtools/vite";
|
import devtools from "solid-devtools/vite";
|
||||||
import { resolve } from "node:path";
|
import { resolve } from "node:path";
|
||||||
|
@ -70,17 +70,17 @@ export default defineConfig(({ mode }) => {
|
||||||
plugins: [
|
plugins: [
|
||||||
devtools({
|
devtools({
|
||||||
autoname: true,
|
autoname: true,
|
||||||
locator: {
|
locator: devConf["DEV_LOCATOR_EDITOR"]
|
||||||
targetIDE:
|
? {
|
||||||
(devConf["DEV_LOCATOR_EDITOR"] as
|
targetIDE: devConf["DEV_LOCATOR_EDITOR"] as
|
||||||
| "vscode"
|
| "vscode"
|
||||||
| "atom"
|
| "atom"
|
||||||
| "webstorm"
|
| "webstorm"
|
||||||
| "vscode-insiders"
|
| "vscode-insiders",
|
||||||
| "") || undefined,
|
componentLocation: true,
|
||||||
componentLocation: true,
|
jsxLocation: true,
|
||||||
jsxLocation: true,
|
}
|
||||||
},
|
: undefined,
|
||||||
}),
|
}),
|
||||||
suid(),
|
suid(),
|
||||||
solid(),
|
solid(),
|
||||||
|
@ -147,7 +147,7 @@ export default defineConfig(({ mode }) => {
|
||||||
devSourcemap: true,
|
devSourcemap: true,
|
||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
target: ["firefox98", "safari15.4", "ios15.4", "chrome84", "edge87"],
|
target: ["firefox115", "safari15.6", "ios15.6", "chrome108", "edge108"],
|
||||||
sourcemap: true,
|
sourcemap: true,
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
output: {
|
output: {
|
||||||
|
|
Loading…
Add table
Reference in a new issue