add alias ~platform and ~material
All checks were successful
/ depoly (push) Successful in 1m19s

This commit is contained in:
thislight 2024-11-22 17:16:56 +08:00
parent ade7df2234
commit 246771e8a0
No known key found for this signature in database
GPG key ID: FCFE5192241CCD4E
30 changed files with 143 additions and 86 deletions

View file

@ -49,3 +49,38 @@ Use physical directions to avoid trouble, like "margin-top, margin-bottom".
For isolating control of the UI effect, we already setup css variables `--safe-area-inset-*`. In components, you should use the variables unless you have reasons to use `env()`.
Using `--safe-area-inset-*`, you can control the global value in settings (under dev mode).
## Module Isolation
> Write the code that can be easily removed.
To limit the code impact, we organize the code based on **"topic modules"** (modules in short). Each module focus on a specific topic described by the name. Like the "accounts" contains the code about the accounts, "masto" contains the code about the masto (a library used to access mastodon) helpers.
> Sidenote: This also helps easing "the landing problem". If you need something about accounts, no longer "common/accounts" and "hooks/accounts" and "helpers/accounts" and "components/accounts". Someone says this is clean - is it even if you need to jump between 6 directories for how one simple feature works?
> And you no longer needs to think about "where to place this file (between six directories, usually)". People often optimize their code structure too early - just like how they treat the runtime performance.
> The worse is, it's very hard to solve this problem later, because you had sent your code to different places.
There are **two special modules** in this project:
One is the *platform*. This module provides foundation of this app: deals with the host platform (like SizedTextarea - auto resized textarea), provides custom platform feature (like StackedRouter - provides mobile-native navigation experience).
The another is the *material*. This module provides Material styling toolkit, the stylesheets, MUI Theme, constants and components.
They (and only them) can be accessed by special aliases: `~{module name}`, like the `~platform`.
We discourage cross referencings between two topics. Reuse is not better than duplication. Cross referencing is still possible if required.
When a tool, a file or a component is required every-elsewhere, **promoting** is required to reduce the cross referencing. Thanksfully, it's usually automated process for moving files.
But, sometimes you need a redesigned (sometimes better) tool for the generic usage. Follow the idea:
- Move slowly or crash. Only make the change if it's required.
- Try to make the original part depends on your new tool, and keep the original for awhile.
- Mark deprecated only if you think the original won't worth an existence. Reasons:
- Migrate to the new code only needs minor change.
- The original code has critical problems, like performance or compatibility.
- Make notes. Communication is important, even with the future you.
- *Why* this move is decided?
- *What* this new tool does?
- *How* this tool works?
- Clean up code regularly. Don't keep the unused code forever.

View file

@ -9,12 +9,12 @@ import {
import { acceptAccountViaAuthCode } from "./stores";
import { $settings } from "../settings/stores";
import { useDocumentTitle } from "../utils";
import cards from "../material/cards.module.css";
import cards from "~material/cards.module.css";
import { LinearProgress } from "@suid/material";
import Img from "../material/Img";
import Img from "~material/Img";
import { createRestAPIClient } from "masto";
import { Title } from "../material/typography";
import { useNavigator } from "../platform/StackedRouter";
import { Title } from "~material/typography";
import { useNavigator } from "~platform/StackedRouter";
type OAuth2CallbackParams = {
code?: string;

View file

@ -7,11 +7,11 @@ import {
createUniqueId,
onMount,
} from "solid-js";
import cards from "../material/cards.module.css";
import TextField from "../material/TextField.js";
import Button from "../material/Button.js";
import cards from "~material/cards.module.css";
import TextField from "~material/TextField.js";
import Button from "~material/Button.js";
import { useDocumentTitle } from "../utils";
import { Title } from "../material/typography";
import { Title } from "~material/typography";
import { css } from "solid-styled";
import { LinearProgress } from "@suid/material";
import { createRestAPIClient } from "masto";

View file

@ -9,7 +9,7 @@ import {
import { Account } from "../accounts/stores";
import { createRestAPIClient, mastodon } from "masto";
import { useLocation } from "@solidjs/router";
import { useNavigator } from "../platform/StackedRouter";
import { useNavigator } from "~platform/StackedRouter";
const restfulCache: Record<string, mastodon.rest.Client> = {};

View file

@ -17,7 +17,7 @@ import {
import {
animateSlideInFromRight,
animateSlideOutToRight,
} from "../platform/anim";
} from "~platform/anim";
export type BottomSheetProps = {
open?: boolean;

View file

@ -14,7 +14,7 @@ import "./Menu.css";
import {
animateGrowFromTopRight,
animateShrinkToTopRight,
} from "../platform/anim";
} from "~platform/anim";
import type { MenuListProps } from "@suid/material/MenuList";
export type Anchor = Pick<DOMRect, "top" | "left" | "right"> & { e?: number };

View file

@ -15,7 +15,7 @@ import {
import { createStore, unwrap } from "solid-js/store";
import "./StackedRouter.css";
import { animateSlideInFromRight, animateSlideOutToRight } from "./anim";
import { ANIM_CURVE_DECELERATION, ANIM_CURVE_STD } from "../material/theme";
import { ANIM_CURVE_DECELERATION, ANIM_CURVE_STD } from "~material/theme";
import { makeEventListener } from "@solid-primitives/event-listener";
import { useWindowSize } from "@solid-primitives/resize-observer";

View file

@ -179,7 +179,7 @@ type MergedImportedModule<T> = T extends []
export function createStringResource<
T extends ImportFn<Record<string, string | Template<any> | undefined>>[],
>(...importFns: T) {
const language = useLanguage();
const language = useLanguage(); // TODO: this function costs to much, provide a global cache
const cache: Record<string, MergedImportedModule<T>> = {};
return createResource(

View file

@ -4,8 +4,8 @@ import {
onCleanup,
type Component,
} from "solid-js";
import Scaffold from "../material/Scaffold";
import BottomSheet from "../material/BottomSheet";
import Scaffold from "~material/Scaffold";
import BottomSheet from "~material/BottomSheet";
import {
Button,
IconButton,
@ -14,9 +14,9 @@ import {
Toolbar,
} from "@suid/material";
import { Close as CloseIcon, ContentCopy } from "@suid/icons-material";
import { Title } from "../material/typography";
import { Title } from "~material/typography";
import { render } from "solid-js/web";
import { useRootTheme } from "../material/theme";
import { useRootTheme } from "~material/theme";
const ShareBottomSheet: Component<{
data?: ShareData;

View file

@ -12,7 +12,7 @@ import {
type Component,
createMemo,
} from "solid-js";
import Scaffold from "../material/Scaffold";
import Scaffold from "~material/Scaffold";
import {
AppBar,
Avatar,
@ -44,7 +44,7 @@ import {
Subject,
Verified,
} from "@suid/icons-material";
import { Body2, Title } from "../material/typography";
import { Body2, Title } from "~material/typography";
import { useParams } from "@solidjs/router";
import { useSessionForAcctStr } from "../masto/clients";
import { resolveCustomEmoji } from "../masto/toot";
@ -52,12 +52,12 @@ import { FastAverageColor } from "fast-average-color";
import { useWindowSize } from "@solid-primitives/resize-observer";
import { createTimeline, createTimelineSnapshot } from "../masto/timelines";
import TootList from "../timelines/TootList";
import { createTimeSource, TimeSourceProvider } from "../platform/timesrc";
import { createTimeSource, TimeSourceProvider } from "~platform/timesrc";
import TootFilterButton from "./TootFilterButton";
import Menu, { createManagedMenuState } from "../material/Menu";
import { share } from "../platform/share";
import Menu, { createManagedMenuState } from "~material/Menu";
import { share } from "~platform/share";
import "./Profile.css";
import { useNavigator } from "../platform/StackedRouter";
import { useNavigator } from "~platform/StackedRouter";
const Profile: Component = () => {
const { pop } = useNavigator();
@ -175,12 +175,12 @@ const Profile: Component = () => {
createRenderEffect(() => (e.innerHTML = sessionDisplayName()));
};
const toggleSubscribeHome = async () => {
const toggleSubscribeHome = async (event: Event) => {
const client = session().client;
if (!session().account) return;
const isSubscribed = relationship()?.following ?? false;
mutateRelationship((x) => Object.assign({ following: !isSubscribed }, x));
subscribeMenuState.onClose();
subscribeMenuState.onClose(event);
if (isSubscribed) {
const nrel = await client.v1.accounts.$select(params.id).unfollow();

View file

@ -1,6 +1,6 @@
import { Button, MenuItem, Checkbox, ListItemText } from "@suid/material";
import { createMemo, createSignal, createUniqueId, For } from "solid-js";
import Menu from "../material/Menu";
import Menu from "~material/Menu";
import { FilterList, FilterListOff } from "@suid/icons-material";
type Props<Filters extends Record<string, string>> = {

View file

@ -1,5 +1,5 @@
import { createMemo, For, type Component, type JSX } from "solid-js";
import Scaffold from "../material/Scaffold";
import Scaffold from "~material/Scaffold";
import {
AppBar,
IconButton,
@ -19,12 +19,12 @@ import {
autoMatchLangTag,
createTranslator,
SUPPORTED_LANGS,
} from "../platform/i18n";
import { Title } from "../material/typography";
} from "~platform/i18n";
import { Title } from "~material/typography";
import type { Template } from "@solid-primitives/i18n";
import { useStore } from "@nanostores/solid";
import { $settings } from "./stores";
import { useNavigator } from "../platform/StackedRouter";
import { useNavigator } from "~platform/StackedRouter";
const ChooseLang: Component = () => {
const { pop } = useNavigator();

View file

@ -1,5 +1,5 @@
import type { Component } from "solid-js";
import Scaffold from "../material/Scaffold";
import Scaffold from "~material/Scaffold";
import {
AppBar,
Divider,
@ -12,12 +12,12 @@ import {
Switch,
Toolbar,
} from "@suid/material";
import { Title } from "../material/typography";
import { Title } from "~material/typography";
import { ArrowBack } from "@suid/icons-material";
import { createTranslator } from "../platform/i18n";
import { createTranslator } from "~platform/i18n";
import { useStore } from "@nanostores/solid";
import { $settings } from "./stores";
import { useNavigator } from "../platform/StackedRouter";
import { useNavigator } from "~platform/StackedRouter";
const Motions: Component = () => {
const {pop} = useNavigator();

View file

@ -1,5 +1,5 @@
import { createMemo, For, type Component, type JSX } from "solid-js";
import Scaffold from "../material/Scaffold";
import Scaffold from "~material/Scaffold";
import {
AppBar,
IconButton,
@ -17,12 +17,12 @@ import {
autoMatchRegion,
createTranslator,
SUPPORTED_REGIONS,
} from "../platform/i18n";
import { Title } from "../material/typography";
} from "~platform/i18n";
import { Title } from "~material/typography";
import type { Template } from "@solid-primitives/i18n";
import { $settings } from "./stores";
import { useStore } from "@nanostores/solid";
import { useNavigator } from "../platform/StackedRouter";
import { useNavigator } from "~platform/StackedRouter";
const ChooseRegion: Component = () => {
const {pop} = useNavigator();

View file

@ -1,5 +1,5 @@
import { For, Show, type Component } from "solid-js";
import Scaffold from "../material/Scaffold.js";
import Scaffold from "~material/Scaffold.js";
import {
AppBar,
Divider,
@ -23,8 +23,8 @@ import {
Refresh as RefreshIcon,
Translate as TranslateIcon,
} from "@suid/icons-material";
import A from "../platform/A.js";
import { Title } from "../material/typography.jsx";
import A from "~platform/A.js";
import { Title } from "~material/typography.js";
import { css } from "solid-styled";
import { signOut, type Account } from "../accounts/stores.js";
import { format } from "date-fns";
@ -35,11 +35,11 @@ import {
autoMatchRegion,
createTranslator,
useDateFnLocale,
} from "../platform/i18n.jsx";
} from "~platform/i18n.jsx";
import { type Template } from "@solid-primitives/i18n";
import { useServiceWorker } from "../platform/host.js";
import { useServiceWorker } from "~platform/host.js";
import { useSessions } from "../masto/clients.js";
import { useNavigator } from "../platform/StackedRouter.jsx";
import { useNavigator } from "~platform/StackedRouter.jsx";
type Inset = {
top?: number;

View file

@ -4,7 +4,7 @@ import {
type Component,
type JSX,
} from "solid-js";
import Scaffold from "../material/Scaffold";
import Scaffold from "~material/Scaffold";
import {
AppBar,
IconButton,
@ -17,8 +17,8 @@ import {
} from "@suid/material";
import { Close as CloseIcon } from "@suid/icons-material";
import iso639_1 from "iso-639-1";
import { createTranslator } from "../platform/i18n";
import { Title } from "../material/typography";
import { createTranslator } from "~platform/i18n";
import { Title } from "~material/typography";
type ChooseTootLangProps = {
code: string;

View file

@ -2,8 +2,8 @@ import type { mastodon } from "masto";
import { Show, type Component } from "solid-js";
import tootStyle from "./toot.module.css";
import { formatRelative } from "date-fns";
import Img from "../material/Img";
import { Body2 } from "../material/typography";
import Img from "~material/Img";
import { Body2 } from "~material/typography";
import { appliedCustomEmoji } from "../masto/toot";
import { TootPreviewCard } from "./RegularToot";

View file

@ -6,7 +6,7 @@ import {
createRenderEffect,
} from "solid-js";
import { useDocumentTitle } from "../utils";
import Scaffold from "../material/Scaffold";
import Scaffold from "~material/Scaffold";
import {
AppBar,
ListItemSecondaryAction,
@ -16,10 +16,10 @@ import {
Toolbar,
} from "@suid/material";
import { css } from "solid-styled";
import { TimeSourceProvider, createTimeSource } from "../platform/timesrc";
import { TimeSourceProvider, createTimeSource } from "~platform/timesrc";
import ProfileMenuButton from "./ProfileMenuButton";
import Tabs from "../material/Tabs";
import Tab from "../material/Tab";
import Tabs from "~material/Tabs";
import Tab from "~material/Tab";
import { makeEventListener } from "@solid-primitives/event-listener";
import { $settings } from "../settings/stores";
import { useStore } from "@nanostores/solid";

View file

@ -14,8 +14,8 @@ import {
Star as LikeIcon,
FeaturedPlayList as ListIcon,
} from "@suid/icons-material";
import A from "../platform/A";
import Menu, { createManagedMenuState } from "../material/Menu";
import A from "~platform/A";
import Menu, { createManagedMenuState } from "~material/Menu";
const ProfileMenuButton: ParentComponent<{
profile?: {

View file

@ -10,7 +10,7 @@ import { Refresh as RefreshIcon } from "@suid/icons-material";
import { CircularProgress } from "@suid/material";
import { makeEventListener } from "@solid-primitives/event-listener";
import { createVisibilityObserver } from "@solid-primitives/intersection-observer";
import { useIsFrameSuspended } from "../platform/StackedRouter";
import { useIsFrameSuspended } from "~platform/StackedRouter";
const PullDownToRefresh: Component<{
loading?: boolean;

View file

@ -10,8 +10,8 @@ import {
} from "solid-js";
import tootStyle from "./toot.module.css";
import { formatRelative } from "date-fns";
import Img from "../material/Img.js";
import { Body2 } from "../material/typography.js";
import Img from "~material/Img.js";
import { Body2 } from "~material/typography.js";
import { css } from "solid-styled";
import {
BookmarkAddOutlined,
@ -24,14 +24,14 @@ import {
SmartToySharp,
Lock,
} from "@suid/icons-material";
import { useTimeSource } from "../platform/timesrc.js";
import { useTimeSource } from "~platform/timesrc.js";
import { resolveCustomEmoji } from "../masto/toot.js";
import { Divider } from "@suid/material";
import cardStyle from "../material/cards.module.css";
import Button from "../material/Button.js";
import cardStyle from "~material/cards.module.css";
import Button from "~material/Button.js";
import MediaAttachmentGrid from "./toots/MediaAttachmentGrid.jsx";
import { useDateFnLocale } from "../platform/i18n";
import { canShare, share } from "../platform/share";
import { useDateFnLocale } from "~platform/i18n";
import { canShare, share } from "~platform/share";
import { makeAcctText, useDefaultSession } from "../masto/clients";
import TootContent from "./toots/TootContent";
import BoostIcon from "./toots/BoostIcon";

View file

@ -7,25 +7,25 @@ import {
Show,
type Component,
} from "solid-js";
import Scaffold from "../material/Scaffold";
import Scaffold from "~material/Scaffold";
import { AppBar, CircularProgress, IconButton, Toolbar } from "@suid/material";
import { Title } from "../material/typography";
import { Title } from "~material/typography";
import { Close as CloseIcon } from "@suid/icons-material";
import { useSessionForAcctStr } from "../masto/clients";
import { resolveCustomEmoji } from "../masto/toot";
import RegularToot, { findElementActionable } from "./RegularToot";
import type { mastodon } from "masto";
import cards from "../material/cards.module.css";
import cards from "~material/cards.module.css";
import { css } from "solid-styled";
import { vibrate } from "../platform/hardware";
import { createTimeSource, TimeSourceProvider } from "../platform/timesrc";
import { vibrate } from "~platform/hardware";
import { createTimeSource, TimeSourceProvider } from "~platform/timesrc";
import TootComposer from "./TootComposer";
import { useDocumentTitle } from "../utils";
import { createTimelineControlsForArray } from "../masto/timelines";
import TootList from "./TootList";
import "./TootBottomSheet.css";
import { useNavigator } from "../platform/StackedRouter";
import BackButton from "../platform/BackButton";
import { useNavigator } from "~platform/StackedRouter";
import BackButton from "~platform/BackButton";
let cachedEntry: [string, mastodon.v1.Status] | undefined;

View file

@ -9,7 +9,7 @@ import {
type JSX,
type Ref,
} from "solid-js";
import Scaffold from "../material/Scaffold";
import Scaffold from "~material/Scaffold";
import {
Avatar,
Button,
@ -41,16 +41,16 @@ import {
} from "@suid/icons-material";
import type { Account } from "../accounts/stores";
import "./TootComposer.css";
import BottomSheet from "../material/BottomSheet";
import { useLanguage } from "../platform/i18n";
import BottomSheet from "~material/BottomSheet";
import { useLanguage } from "~platform/i18n";
import iso639_1 from "iso-639-1";
import ChooseTootLang from "./ChooseTootLang";
import type { mastodon } from "masto";
import cardStyles from "../material/cards.module.css";
import Menu, { createManagedMenuState } from "../material/Menu";
import cardStyles from "~material/cards.module.css";
import Menu, { createManagedMenuState } from "~material/Menu";
import { useDefaultSession } from "../masto/clients";
import { resolveCustomEmoji } from "../masto/toot";
import SizedTextarea from "../platform/SizedTextarea";
import SizedTextarea from "~platform/SizedTextarea";
type TootVisibility = "public" | "unlisted" | "private" | "direct";

View file

@ -8,17 +8,17 @@ import {
createMemo,
} from "solid-js";
import { type mastodon } from "masto";
import { vibrate } from "../platform/hardware";
import { vibrate } from "~platform/hardware";
import { useDefaultSession } from "../masto/clients";
import { setCache as setTootBottomSheetCache } from "./TootBottomSheet";
import RegularToot, {
findElementActionable,
findRootToot,
} from "./RegularToot";
import cardStyle from "../material/cards.module.css";
import cardStyle from "~material/cards.module.css";
import type { ThreadNode } from "../masto/timelines";
import { useNavigator } from "../platform/StackedRouter";
import { ANIM_CURVE_STD } from "../material/theme";
import { useNavigator } from "~platform/StackedRouter";
import { ANIM_CURVE_STD } from "~material/theme";
function durationOf(rect0: DOMRect, rect1: DOMRect) {
const distancelt = Math.sqrt(

View file

@ -136,7 +136,7 @@
}
.tootBottomActionGrp {
composes: cardGutSkip from "../material/cards.module.css";
composes: cardGutSkip from "~material/cards.module.css";
padding-block: calc((var(--card-gut) - 10px) / 2);
animation: 225ms var(--tutu-anim-curve-std) tootBottomExpanding;

View file

@ -18,9 +18,9 @@ import {
} from "@solid-primitives/resize-observer";
import { useStore } from "@nanostores/solid";
import { $settings } from "../../settings/stores";
import { averageColorHex } from "../../platform/blurhash";
import { averageColorHex } from "~platform/blurhash";
import "./MediaAttachmentGrid.css";
import cardStyle from "../../material/cards.module.css";
import cardStyle from "~material/cards.module.css";
import { Preview } from "@suid/icons-material";
import { IconButton } from "@suid/material";

View file

@ -1,8 +1,8 @@
import Color from "colorjs.io";
import type { mastodon } from "masto";
import { createEffect, createMemo, Show } from "solid-js";
import { Title, Body1 } from "../../material/typography";
import { averageColorHex } from "../../platform/blurhash";
import { Title, Body1 } from "~material/typography";
import { averageColorHex } from "~platform/blurhash";
import "./PreviewCard.css";
function onResetImg(event: Event & { currentTarget: HTMLImageElement }) {

View file

@ -11,7 +11,7 @@ import { resolveCustomEmoji } from "../../masto/toot.js";
import { makeAcctText, useDefaultSession } from "../../masto/clients.js";
import "./TootContent.css";
import { Button } from "@suid/material";
import { createTranslator } from "../../platform/i18n.jsx";
import { createTranslator } from "~platform/i18n.js";
function preventDefault(event: Event) {
event.preventDefault();

View file

@ -12,5 +12,9 @@
"noEmit": true,
"isolatedModules": true,
"resolveJsonModule": true,
"paths": {
"~platform/*": ["./src/platform/*"],
"~material/*": ["./src/material/*"]
}
}
}

View file

@ -7,6 +7,7 @@ import version from "vite-plugin-package-version";
import manifest from "./manifest.config";
import { GetManualChunk } from "rollup";
import devtools from "solid-devtools/vite";
import { resolve } from "node:path";
/**
* Put all strings (/i18n/{key}.<json|js|ts>) into separated chunks based on the key.
@ -107,6 +108,23 @@ export default defineConfig(({ mode }) => {
}),
version(),
],
resolve: {
alias: {
/* We don't allow directly acessing the source root,
because this encourage cross referencing between different
module and loose the isolation. (Cross referencing is still
possible, we don't stop it in any technical way.)
If the module is so important and is being referencing
everywhere in the app. Consider promoting it to the top
dir.
see docs/devnotes.md#module-isolation for details.
*/
"~platform": resolve(__dirname, "src/platform"),
"~material": resolve(__dirname, "src/material"),
},
},
server: {
https: serverHttpCertBase
? {