Compare commits
	
		
			9 commits
		
	
	
		
			70a8e15be9
			...
			1f77da4dbe
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 1f77da4dbe | |||
| 
							 | 
						937efe1107 | ||
| 
							 | 
						e617f344f8 | ||
| 
							 | 
						5945f07ce8 | ||
| 
							 | 
						d04731e64c | ||
| 
							 | 
						d4f41330de | ||
| 
							 | 
						203eeb9761 | ||
| 
							 | 
						99efa6b42c | ||
| 
							 | 
						654bb749fb | 
					 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:
 | 
			
		||||
 | 
			
		||||
| Firefox | Safari |  iOS  | Chrome | Edge |
 | 
			
		||||
| ------- | ------ | ----- | ------ | ---- |
 | 
			
		||||
|   98    |  15.4  | 15.4  |   84   |  87  |
 | 
			
		||||
| Firefox | Safari |  iOS  | Chrome & Edge |
 | 
			
		||||
| ------- | ------ | ----- | ------------- |
 | 
			
		||||
|   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.
 | 
			
		||||
 | 
			
		||||
## 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
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										
											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",
 | 
			
		||||
  "name": "tutu",
 | 
			
		||||
  "version": "1.1.0",
 | 
			
		||||
  "version": "2.0.0",
 | 
			
		||||
  "description": "",
 | 
			
		||||
  "private": true,
 | 
			
		||||
  "type": "module",
 | 
			
		||||
| 
						 | 
				
			
			@ -17,33 +17,33 @@
 | 
			
		|||
  "author": "Rubicon",
 | 
			
		||||
  "license": "Apache-2.0",
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@solid-devtools/overlay": "^0.30.1",
 | 
			
		||||
    "@solid-devtools/overlay": "^0.33.0",
 | 
			
		||||
    "@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.4.5",
 | 
			
		||||
    "@wdio/lighthouse-service": "^9.4.5",
 | 
			
		||||
    "@wdio/local-runner": "^9.4.5",
 | 
			
		||||
    "@wdio/mocha-framework": "^9.4.4",
 | 
			
		||||
    "@wdio/spec-reporter": "^9.4.4",
 | 
			
		||||
    "@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.3.3",
 | 
			
		||||
    "prettier": "^3.4.2",
 | 
			
		||||
    "tsx": "^4.19.2",
 | 
			
		||||
    "typescript": "^5.6.3",
 | 
			
		||||
    "vite": "^5.4.11",
 | 
			
		||||
    "typescript": "^5.7.2",
 | 
			
		||||
    "vite": "^6.0.7",
 | 
			
		||||
    "vite-plugin-package-version": "^1.1.0",
 | 
			
		||||
    "vite-plugin-pwa": "^0.20.5",
 | 
			
		||||
    "vite-plugin-solid": "^2.10.2",
 | 
			
		||||
    "vite-plugin-pwa": "^0.21.1",
 | 
			
		||||
    "vite-plugin-solid": "^2.11.0",
 | 
			
		||||
    "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.86.1"
 | 
			
		||||
    "wrangler": "^3.99.0"
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@formatjs/intl-localematcher": "^0.5.7",
 | 
			
		||||
    "@formatjs/intl-localematcher": "^0.5.10",
 | 
			
		||||
    "@nanostores/persistent": "^0.10.2",
 | 
			
		||||
    "@nanostores/solid": "^0.5.0",
 | 
			
		||||
    "@solid-primitives/event-listener": "^2.3.3",
 | 
			
		||||
| 
						 | 
				
			
			@ -52,7 +52,7 @@
 | 
			
		|||
    "@solid-primitives/map": "^0.4.13",
 | 
			
		||||
    "@solid-primitives/page-visibility": "^2.0.17",
 | 
			
		||||
    "@solid-primitives/resize-observer": "^2.0.26",
 | 
			
		||||
    "@solidjs/router": "^0.15.1",
 | 
			
		||||
    "@solidjs/router": "^0.15.2",
 | 
			
		||||
    "@suid/icons-material": "^0.8.1",
 | 
			
		||||
    "@suid/material": "^0.18.0",
 | 
			
		||||
    "blurhash": "^2.0.5",
 | 
			
		||||
| 
						 | 
				
			
			@ -65,7 +65,7 @@
 | 
			
		|||
    "masto": "^6.10.1",
 | 
			
		||||
    "nanostores": "^0.11.3",
 | 
			
		||||
    "normalize.css": "^8.0.1",
 | 
			
		||||
    "solid-devtools": "^0.30.1",
 | 
			
		||||
    "solid-devtools": "^0.33.0",
 | 
			
		||||
    "solid-js": "^1.9.3",
 | 
			
		||||
    "solid-styled": "^0.11.1",
 | 
			
		||||
    "solid-transition-group": "^0.2.3",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,7 +51,7 @@ function animateSlideInFromBottom(element: HTMLElement, reverse?: boolean) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
const BottomSheet: ParentComponent<BottomSheetProps> = (props) => {
 | 
			
		||||
  let element: HTMLDialogElement;
 | 
			
		||||
  let element!: HTMLDialogElement;
 | 
			
		||||
  let animation: Animation | undefined;
 | 
			
		||||
  const child = children(() => props.children);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -108,7 +108,7 @@ function animateGrowFromTopLeft(
 | 
			
		|||
 * - Use {@link MenuItem} from SUID as children.
 | 
			
		||||
 */
 | 
			
		||||
const Menu: Component<MenuProps> = (oprops) => {
 | 
			
		||||
  let root: HTMLDialogElement;
 | 
			
		||||
  let root!: HTMLDialogElement;
 | 
			
		||||
  const windowSize = useWindowSize();
 | 
			
		||||
  const [props, rest] = splitProps(oprops, [
 | 
			
		||||
    "open",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,38 +1,27 @@
 | 
			
		|||
//! This module has side effect.
 | 
			
		||||
//! 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") {
 | 
			
		||||
  // Chrome/Edge 119, Firefox 121, Safari/iOS 17.4
 | 
			
		||||
 | 
			
		||||
  // Promise.withResolvers is generic and works with subclasses - the typescript built-in decl
 | 
			
		||||
  // could not handle the subclassing case.
 | 
			
		||||
  (Promise.prototype as any).withResolvers = function <T>(this: AnyPromiseConstructor<T>) {
 | 
			
		||||
    let resolve!: PromiseWithResolvers<T>["resolve"], reject!: PromiseWithResolvers<T>["reject"];
 | 
			
		||||
  (Promise.prototype as any).withResolvers = function <T>(
 | 
			
		||||
    this: AnyPromiseConstructor<T>,
 | 
			
		||||
  ) {
 | 
			
		||||
    let resolve!: PromiseWithResolvers<T>["resolve"],
 | 
			
		||||
      reject!: PromiseWithResolvers<T>["reject"];
 | 
			
		||||
    // These variables are expected to be set after `new this()`
 | 
			
		||||
 | 
			
		||||
    const promise = new this((resolve0, reject0) => {
 | 
			
		||||
      resolve = resolve0;
 | 
			
		||||
      reject = reject0;
 | 
			
		||||
    })
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      promise, resolve, reject
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
      promise,
 | 
			
		||||
      resolve,
 | 
			
		||||
      reject,
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,7 +38,7 @@ function clamp(input: number, min: number, max: number) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
const MediaViewer: ParentComponent<MediaViewerProps> = (props) => {
 | 
			
		||||
  let rootRef: HTMLDialogElement;
 | 
			
		||||
  let rootRef!: HTMLDialogElement;
 | 
			
		||||
 | 
			
		||||
  type State = {
 | 
			
		||||
    ref?: HTMLElement;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,7 +17,7 @@ const PullDownToRefresh: Component<{
 | 
			
		|||
  linkedElement?: HTMLElement;
 | 
			
		||||
  onRefresh?: () => void;
 | 
			
		||||
}> = (props) => {
 | 
			
		||||
  let rootElement: HTMLDivElement;
 | 
			
		||||
  let rootElement!: HTMLDivElement;
 | 
			
		||||
  const [pullDown, setPullDown] = createSignal(0);
 | 
			
		||||
 | 
			
		||||
  const stopPos = () => 160;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,7 +23,7 @@ type ChooseTootLangProps = {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
const ChooseTootLang: Component<ChooseTootLangProps> = (props) => {
 | 
			
		||||
  let listRef: HTMLUListElement;
 | 
			
		||||
  let listRef!: HTMLUListElement;
 | 
			
		||||
  const [t] = createTranslator(
 | 
			
		||||
    (code) =>
 | 
			
		||||
      import(`./i18n/${code}.json`) as Promise<{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,7 +17,7 @@ export function PreviewCard(props: {
 | 
			
		|||
  src: mastodon.v1.PreviewCard;
 | 
			
		||||
  alwaysCompact?: boolean;
 | 
			
		||||
}) {
 | 
			
		||||
  let root: HTMLAnchorElement;
 | 
			
		||||
  let root!: HTMLAnchorElement;
 | 
			
		||||
 | 
			
		||||
  createEffect(() => {
 | 
			
		||||
    if (props.alwaysCompact) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,7 +33,7 @@ type TootPollProps = {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
const TootPoll: Component<TootPollProps> = (props) => {
 | 
			
		||||
  let list: HTMLUListElement;
 | 
			
		||||
  let list!: HTMLUListElement;
 | 
			
		||||
  const { vote } = useTootEnv();
 | 
			
		||||
 | 
			
		||||
  const now = useTimeSource();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,8 +2,8 @@
 | 
			
		|||
  "compilerOptions": {
 | 
			
		||||
    "strict": true,
 | 
			
		||||
    "target": "ESNext",
 | 
			
		||||
    "module": "esnext",
 | 
			
		||||
    "moduleResolution": "node",
 | 
			
		||||
    "module": "ESNext",
 | 
			
		||||
    "moduleResolution": "bundler",
 | 
			
		||||
    "allowSyntheticDefaultImports": true,
 | 
			
		||||
    "esModuleInterop": true,
 | 
			
		||||
    "noEmit": true,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,7 @@ import solidStyled from "vite-plugin-solid-styled";
 | 
			
		|||
import suid from "@suid/vite-plugin";
 | 
			
		||||
import { VitePWA } from "vite-plugin-pwa";
 | 
			
		||||
import version from "vite-plugin-package-version";
 | 
			
		||||
import manifest from "./manifest.config";
 | 
			
		||||
import manifest from "./manifest.config.js";
 | 
			
		||||
import { GetManualChunk } from "rollup";
 | 
			
		||||
import devtools from "solid-devtools/vite";
 | 
			
		||||
import { resolve } from "node:path";
 | 
			
		||||
| 
						 | 
				
			
			@ -70,17 +70,17 @@ export default defineConfig(({ mode }) => {
 | 
			
		|||
    plugins: [
 | 
			
		||||
      devtools({
 | 
			
		||||
        autoname: true,
 | 
			
		||||
        locator: {
 | 
			
		||||
          targetIDE:
 | 
			
		||||
            (devConf["DEV_LOCATOR_EDITOR"] as
 | 
			
		||||
              | "vscode"
 | 
			
		||||
              | "atom"
 | 
			
		||||
              | "webstorm"
 | 
			
		||||
              | "vscode-insiders"
 | 
			
		||||
              | "") || undefined,
 | 
			
		||||
          componentLocation: true,
 | 
			
		||||
          jsxLocation: true,
 | 
			
		||||
        },
 | 
			
		||||
        locator: devConf["DEV_LOCATOR_EDITOR"]
 | 
			
		||||
          ? {
 | 
			
		||||
              targetIDE: devConf["DEV_LOCATOR_EDITOR"] as
 | 
			
		||||
                | "vscode"
 | 
			
		||||
                | "atom"
 | 
			
		||||
                | "webstorm"
 | 
			
		||||
                | "vscode-insiders",
 | 
			
		||||
              componentLocation: true,
 | 
			
		||||
              jsxLocation: true,
 | 
			
		||||
            }
 | 
			
		||||
          : undefined,
 | 
			
		||||
      }),
 | 
			
		||||
      suid(),
 | 
			
		||||
      solid(),
 | 
			
		||||
| 
						 | 
				
			
			@ -147,7 +147,7 @@ export default defineConfig(({ mode }) => {
 | 
			
		|||
      devSourcemap: true,
 | 
			
		||||
    },
 | 
			
		||||
    build: {
 | 
			
		||||
      target: ["firefox98", "safari15.4", "ios15.4", "chrome84", "edge87"],
 | 
			
		||||
      target: ["firefox115", "safari15.6", "ios15.6", "chrome108", "edge108"],
 | 
			
		||||
      sourcemap: true,
 | 
			
		||||
      rollupOptions: {
 | 
			
		||||
        output: {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue