Compare commits
	
		
			2 commits
		
	
	
		
			b6fbe71a51
			...
			4718239723
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 4718239723 | ||
|  | 8854a3b86a | 
					 23 changed files with 234 additions and 163 deletions
				
			
		|  | @ -84,3 +84,64 @@ 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 <div class="root"></div> | ||||
| }; | ||||
| ``` | ||||
| 
 | ||||
| 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. | ||||
|  |  | |||
							
								
								
									
										67
									
								
								src/App.css
									
										
									
									
									
								
							
							
						
						
									
										67
									
								
								src/App.css
									
										
									
									
									
								
							|  | @ -1,41 +1,46 @@ | |||
| @import "normalize.css/normalize.css"; | ||||
| @import "./material/theme.css"; | ||||
| @layer compat, theme, 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); | ||||
| } | ||||
| @import "normalize.css/normalize.css" layer(compat); | ||||
| @import "./material/theme.css" layer(theme); | ||||
| @import "./material/material.css" layer(material); | ||||
| 
 | ||||
| /* | ||||
| 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; | ||||
| @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); | ||||
|   } | ||||
| 
 | ||||
|   #root { | ||||
|     position: fixed; | ||||
|     top: 0; | ||||
|     left: 0; | ||||
|     height: 100vh; | ||||
|     width: 100vw; | ||||
|   /* | ||||
|   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; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| .custom-emoji { | ||||
|   width: 1em; | ||||
| } | ||||
| 
 | ||||
| h1 { | ||||
|   margin: 0; | ||||
| } | ||||
| 
 | ||||
| * { | ||||
|   user-select: none; | ||||
| } | ||||
|  |  | |||
							
								
								
									
										22
									
								
								src/accounts/MastodonOAuth2Callback.css
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/accounts/MastodonOAuth2Callback.css
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,22 @@ | |||
| .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; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | @ -8,7 +8,7 @@ import { | |||
| } from "solid-js"; | ||||
| import { acceptAccountViaAuthCode } from "./stores"; | ||||
| import { $settings } from "../settings/stores"; | ||||
| import cards from "~material/cards.module.css"; | ||||
| import "~material/cards.css"; | ||||
| import { LinearProgress } from "@suid/material"; | ||||
| import Img from "~material/Img"; | ||||
| import { createRestAPIClient } from "masto"; | ||||
|  | @ -92,11 +92,11 @@ const MastodonOAuth2Callback: Component = () => { | |||
|   }); | ||||
|   return ( | ||||
|     <> | ||||
|     <DocumentTitle>Back from {siteTitle()}</DocumentTitle> | ||||
|       <div class={cards.layoutCentered}> | ||||
|         <div class={cards.card} aria-busy="true" aria-describedby={progressId}> | ||||
|       <DocumentTitle>Back from {siteTitle()}</DocumentTitle> | ||||
|       <main class="MastodonOAuth2Callback"> | ||||
|         <div class="card card-auto-margin" aria-busy="true" aria-describedby={progressId}> | ||||
|           <LinearProgress | ||||
|             class={[cards.cardNoPad, cards.cardGutSkip].join(" ")} | ||||
|             class="card-no-pad card-gut-skip" | ||||
|             id={progressId} | ||||
|             aria-labelledby={titleId} | ||||
|           /> | ||||
|  | @ -114,7 +114,7 @@ const MastodonOAuth2Callback: Component = () => { | |||
|               src={siteImg()?.src} | ||||
|               srcset={siteImg()?.srcset} | ||||
|               blurhash={siteImg()?.blurhash} | ||||
|               class={[cards.cardNoPad, cards.cardGutSkip].join(" ")} | ||||
|               class="card-no-pad card-gut-skip" | ||||
|               alt={`Banner image for ${siteTitle()}`} | ||||
|               style={{ height: "235px", display: "block" }} | ||||
|             /> | ||||
|  | @ -128,7 +128,7 @@ const MastodonOAuth2Callback: Component = () => { | |||
|             again. | ||||
|           </p> | ||||
|         </div> | ||||
|       </div> | ||||
|       </main> | ||||
|     </> | ||||
|   ); | ||||
| }; | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ import { | |||
|   createUniqueId, | ||||
|   onMount, | ||||
| } from "solid-js"; | ||||
| import cards from "~material/cards.module.css"; | ||||
| import "~material/cards.css"; | ||||
| import TextField from "~material/TextField.js"; | ||||
| import Button from "~material/Button.js"; | ||||
| import { Title } from "~material/typography"; | ||||
|  | @ -115,7 +115,7 @@ const SignIn: Component = () => { | |||
|       <DocumentTitle>Sign In</DocumentTitle> | ||||
|       <main class="SignIn"> | ||||
|         <Show when={params.error || params.errorDescription}> | ||||
|           <div class={cards.card} style={{ "margin-bottom": "20px" }}> | ||||
|           <div class="card card-auto-margin" style={{ "margin-bottom": "20px" }}> | ||||
|             <p>Authorization is failed.</p> | ||||
|             <p>{params.errorDescription}</p> | ||||
|             <p> | ||||
|  | @ -125,7 +125,7 @@ const SignIn: Component = () => { | |||
|           </div> | ||||
|         </Show> | ||||
|         <div | ||||
|           class={`${cards.card} key-content`} | ||||
|           class="card card-auto-margin key-content" | ||||
|           aria-busy={currentState() !== "inactive" ? "true" : "false"} | ||||
|           aria-describedby={ | ||||
|             currentState() !== "inactive" ? progressId : undefined | ||||
|  | @ -135,7 +135,7 @@ const SignIn: Component = () => { | |||
|           }} | ||||
|         > | ||||
|           <LinearProgress | ||||
|             class={[cards.cardNoPad, cards.cardGutSkip].join(" ")} | ||||
|             class={"card-no-pad card-gut-skip"} | ||||
|             id={progressId} | ||||
|             sx={currentState() === "inactive" ? { display: "none" } : undefined} | ||||
|           /> | ||||
|  |  | |||
|  | @ -7,7 +7,6 @@ import { | |||
|   type ParentComponent, | ||||
| } from "solid-js"; | ||||
| import "./BottomSheet.css"; | ||||
| import material from "./material.module.css"; | ||||
| import { ANIM_CURVE_ACELERATION, ANIM_CURVE_DECELERATION } from "./theme"; | ||||
| import { | ||||
|   animateSlideInFromRight, | ||||
|  | @ -134,7 +133,7 @@ const BottomSheet: ParentComponent<BottomSheetProps> = (props) => { | |||
| 
 | ||||
|   return ( | ||||
|     <dialog | ||||
|       class={`BottomSheet ${material.surface} ${props.class || ""}`} | ||||
|       class={`BottomSheet surface ${props.class || ""}`} | ||||
|       classList={{ | ||||
|         ["bottom"]: props.bottomUp, | ||||
|       }} | ||||
|  |  | |||
|  | @ -1,5 +1,4 @@ | |||
| import { Component, JSX, splitProps } from "solid-js"; | ||||
| import materialStyles from "./material.module.css"; | ||||
| import "./typography.css"; | ||||
| 
 | ||||
| /** | ||||
|  | @ -10,13 +9,12 @@ import "./typography.css"; | |||
| const Button: Component<JSX.ButtonHTMLAttributes<HTMLButtonElement>> = ( | ||||
|   props, | ||||
| ) => { | ||||
|   const [managed, passthough] = splitProps(props, ["class", "type"]); | ||||
|   const [managed, passthough] = splitProps(props, [ "type"]); | ||||
|   const type = () => managed.type ?? "button"; | ||||
| 
 | ||||
|   return ( | ||||
|     <button | ||||
|       type={type()} | ||||
|       class={`${materialStyles.button} buttonText ${managed.class || ""}`} | ||||
|       {...passthough} | ||||
|     ></button> | ||||
|   ); | ||||
|  |  | |||
|  | @ -1,5 +1,7 @@ | |||
| .textfield { | ||||
|   composes: touchTarget from "material.module.css"; | ||||
| .TextField { | ||||
|   min-width: 44px; | ||||
|   min-height: 44px; | ||||
|   cursor: pointer; | ||||
| 
 | ||||
|   --border-color: var(--tutu-color-inactive-on-surface); | ||||
|   --active-border-color: var(--tutu-color-primary); | ||||
|  | @ -6,7 +6,7 @@ import { | |||
|   onMount, | ||||
|   Show, | ||||
| } from "solid-js"; | ||||
| import formStyles from "./form.module.css"; | ||||
| import "./TextField.css"; | ||||
| 
 | ||||
| export type TextFieldProps = { | ||||
|   label?: string; | ||||
|  | @ -47,12 +47,12 @@ const TextField: Component<TextFieldProps> = (props) => { | |||
|   const inputId = () => props.inputId ?? altInputId; | ||||
| 
 | ||||
|   const fieldClass = () => { | ||||
|     const cls = [formStyles.textfield]; | ||||
|     const cls = ["TextField"]; | ||||
|     if (typeof props.helperText !== "undefined") { | ||||
|       cls.push(formStyles.withHelperText); | ||||
|       cls.push("withHelperText"); | ||||
|     } | ||||
|     if (props.error) { | ||||
|       cls.push(formStyles.error); | ||||
|       cls.push("error"); | ||||
|     } | ||||
|     return cls.join(" "); | ||||
|   }; | ||||
|  | @ -71,7 +71,7 @@ const TextField: Component<TextFieldProps> = (props) => { | |||
|         name={props.name} | ||||
|       /> | ||||
|       <Show when={typeof props.helperText !== "undefined"}> | ||||
|         <span class={formStyles.helperText}>{props.helperText}</span> | ||||
|         <span class="helperText">{props.helperText}</span> | ||||
|       </Show> | ||||
|     </div> | ||||
|   ); | ||||
|  |  | |||
							
								
								
									
										56
									
								
								src/material/cards.css
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								src/material/cards.css
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,56 @@ | |||
| @layer material { | ||||
|   .card { | ||||
|     --card-pad: 20px; | ||||
|     --card-gut: 20px; | ||||
| 
 | ||||
|     background-color: var(--tutu-color-surface); | ||||
|     color: var(--tutu-color-on-surface); | ||||
| 
 | ||||
|     border-radius: 2px; | ||||
|     box-shadow: var(--tutu-shadow-e2); | ||||
|     transition: var(--tutu-transition-shadow); | ||||
|     overflow: hidden; | ||||
|     background-color: var(--tutu-color-surface-l); | ||||
| 
 | ||||
|     &:focus-within, | ||||
|     &:focus-visible { | ||||
|       box-shadow: var(--tutu-shadow-e8); | ||||
|     } | ||||
| 
 | ||||
|     &>.card-pad { | ||||
|       margin-inline: var(--card-pad); | ||||
|     } | ||||
| 
 | ||||
|     &>.card-gut { | ||||
|       &:first-child { | ||||
|         margin-top: var(--card-gut); | ||||
|       } | ||||
| 
 | ||||
|       &+.card-gut { | ||||
|         margin-top: var(--card-gut); | ||||
|       } | ||||
| 
 | ||||
|       &:last-child { | ||||
|         margin-bottom: var(--card-gut); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     &.card-auto-margin { | ||||
|       &> :not(.card-no-pad) { | ||||
|         margin-inline: var(--card-pad, 20px); | ||||
|       } | ||||
| 
 | ||||
|       > :not(.card-gut-skip):first-child { | ||||
|         margin-top: var(--card-gut, 20px); | ||||
|       } | ||||
| 
 | ||||
|       >.card-gut-skip+*:not(.card-gut-skip) { | ||||
|         margin-top: var(--card-gut, 20px); | ||||
|       } | ||||
| 
 | ||||
|       > :not(.card-gut-skip):last-child { | ||||
|         margin-bottom: var(--card-gut, 20px); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | @ -1,54 +0,0 @@ | |||
| .card { | ||||
|   composes: surface from "material.module.css"; | ||||
|   border-radius: 2px; | ||||
|   box-shadow: var(--tutu-shadow-e2); | ||||
|   transition: var(--tutu-transition-shadow); | ||||
|   overflow: hidden; | ||||
|   background-color: var(--tutu-color-surface-l); | ||||
| 
 | ||||
|   &:focus-within, | ||||
|   &:focus-visible { | ||||
|     box-shadow: var(--tutu-shadow-e8); | ||||
|   } | ||||
| 
 | ||||
|   &:not(.manualMargin) { | ||||
|     &> :not(.cardNoPad) { | ||||
|       margin-inline: var(--card-pad, 20px); | ||||
|     } | ||||
| 
 | ||||
|     > :not(.cardGutSkip):first-child { | ||||
|       margin-top: var(--card-gut, 20px); | ||||
|     } | ||||
| 
 | ||||
|     >.cardGutSkip+*:not(.cardGutSkip) { | ||||
|       margin-top: var(--card-gut, 20px); | ||||
|     } | ||||
| 
 | ||||
|     > :not(.cardGutSkip):last-child { | ||||
|       margin-bottom: var(--card-gut, 20px); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| .layoutCentered { | ||||
|   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; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | @ -1,16 +1,14 @@ | |||
| @import "./typography.css"; | ||||
| 
 | ||||
| .surface { | ||||
|   background-color: var(--tutu-color-surface); | ||||
|   color: var(--tutu-color-on-surface); | ||||
| } | ||||
| 
 | ||||
| .touchTarget { | ||||
| button { | ||||
|   min-width: 44px; | ||||
|   min-height: 44px; | ||||
|   cursor: pointer; | ||||
| } | ||||
| 
 | ||||
| .button { | ||||
|   composes: touchTarget; | ||||
| 
 | ||||
|   border: none; | ||||
|   background-color: transparent; | ||||
|  | @ -1,3 +1,6 @@ | |||
| /* Don't import this file directly. This file is already included in material.css */ | ||||
| 
 | ||||
| 
 | ||||
| .display4 { | ||||
|   font-size: 7rem; | ||||
|   font-weight: 300; | ||||
|  |  | |||
|  | @ -1,21 +1,11 @@ | |||
| import { JSX, ParentComponent, splitProps, type Ref } from "solid-js"; | ||||
| import { splitProps, type Ref, ComponentProps, ValidComponent } from "solid-js"; | ||||
| import { Dynamic } from "solid-js/web"; | ||||
| import "./typography.css"; | ||||
| 
 | ||||
| type AnyElement = keyof JSX.IntrinsicElements | ParentComponent<any>; | ||||
| 
 | ||||
| type PropsOf<E extends AnyElement> = | ||||
|   E extends ParentComponent<infer Props> | ||||
|     ? Props | ||||
|     : E extends keyof JSX.IntrinsicElements | ||||
|       ? JSX.IntrinsicElements[E] | ||||
|       : JSX.HTMLAttributes<HTMLElement>; | ||||
| 
 | ||||
| export type TypographyProps<E extends AnyElement> = { | ||||
| export type TypographyProps<E extends ValidComponent> = { | ||||
|   ref?: Ref<E>; | ||||
|   component?: E; | ||||
|   class?: string; | ||||
| } & PropsOf<E>; | ||||
| } & ComponentProps<E>; | ||||
| 
 | ||||
| type TypographyKind = | ||||
|   | "display4" | ||||
|  | @ -30,7 +20,7 @@ type TypographyKind = | |||
|   | "caption" | ||||
|   | "buttonText"; | ||||
| 
 | ||||
| export function Typography<T extends AnyElement>( | ||||
| export function Typography<T extends ValidComponent>( | ||||
|   props: { typography: TypographyKind } & TypographyProps<T>, | ||||
| ) { | ||||
|   const [managed, passthough] = splitProps(props, [ | ||||
|  | @ -49,36 +39,36 @@ export function Typography<T extends AnyElement>( | |||
|   ); | ||||
| } | ||||
| 
 | ||||
| export function Display4<E extends AnyElement>(props: TypographyProps<E>) { | ||||
| export function Display4<E extends ValidComponent>(props: TypographyProps<E>) { | ||||
|   return <Typography typography={"display4"} {...props}></Typography>; | ||||
| } | ||||
| export function Display3<E extends AnyElement>(props: TypographyProps<E>) { | ||||
| export function Display3<E extends ValidComponent>(props: TypographyProps<E>) { | ||||
|   return <Typography typography={"display3"} {...props}></Typography>; | ||||
| } | ||||
| export function Display2<E extends AnyElement>(props: TypographyProps<E>) { | ||||
| export function Display2<E extends ValidComponent>(props: TypographyProps<E>) { | ||||
|   return <Typography typography={"display2"} {...props}></Typography>; | ||||
| } | ||||
| export function Display1<E extends AnyElement>(props: TypographyProps<E>) { | ||||
| export function Display1<E extends ValidComponent>(props: TypographyProps<E>) { | ||||
|   return <Typography typography={"display1"} {...props}></Typography>; | ||||
| } | ||||
| export function Headline<E extends AnyElement>(props: TypographyProps<E>) { | ||||
| export function Headline<E extends ValidComponent>(props: TypographyProps<E>) { | ||||
|   return <Typography typography={"headline"} {...props}></Typography>; | ||||
| } | ||||
| export function Title<E extends AnyElement>(props: TypographyProps<E>) { | ||||
| export function Title<E extends ValidComponent>(props: TypographyProps<E>) { | ||||
|   return <Typography typography={"title"} {...props}></Typography>; | ||||
| } | ||||
| export function Subheading<E extends AnyElement>(props: TypographyProps<E>) { | ||||
| export function Subheading<E extends ValidComponent>(props: TypographyProps<E>) { | ||||
|   return <Typography typography={"subheading"} {...props}></Typography>; | ||||
| } | ||||
| export function Body1<E extends AnyElement>(props: TypographyProps<E>) { | ||||
| export function Body1<E extends ValidComponent>(props: TypographyProps<E>) { | ||||
|   return <Typography typography={"body1"} {...props}></Typography>; | ||||
| } | ||||
| export function Body2<E extends AnyElement>(props: TypographyProps<E>) { | ||||
| export function Body2<E extends ValidComponent>(props: TypographyProps<E>) { | ||||
|   return <Typography typography={"body2"} {...props}></Typography>; | ||||
| } | ||||
| export function Caption<E extends AnyElement>(props: TypographyProps<E>) { | ||||
| export function Caption<E extends ValidComponent>(props: TypographyProps<E>) { | ||||
|   return <Typography typography={"caption"} {...props}></Typography>; | ||||
| } | ||||
| export function ButtonText<E extends AnyElement>(props: TypographyProps<E>) { | ||||
| export function ButtonText<E extends ValidComponent>(props: TypographyProps<E>) { | ||||
|   return <Typography typography={"buttonText"} {...props}></Typography>; | ||||
| } | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ import { Body2 } from "~material/typography.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 MediaAttachmentGrid from "./toots/MediaAttachmentGrid.jsx"; | ||||
| import { makeAcctText, useDefaultSession } from "../masto/clients"; | ||||
| import TootContent from "./toots/TootContent"; | ||||
|  | @ -25,6 +24,7 @@ import TootAuthorGroup from "./toots/TootAuthorGroup.js"; | |||
| import "./RegularToot.css"; | ||||
| import { vibrate } from "~platform/hardware.js"; | ||||
| import { Transition } from "solid-transition-group"; | ||||
| import "~material/cards.css"; | ||||
| 
 | ||||
| export type TootEnv = { | ||||
|   boost: (value: mastodon.v1.Status) => void; | ||||
|  | @ -251,6 +251,7 @@ const RegularToot: Component<RegularTootProps> = (oprops) => { | |||
|       <article | ||||
|         classList={{ | ||||
|           RegularToot: true, | ||||
|           "card": true, | ||||
|           expanded: props.evaluated, | ||||
|           "thread-top": props.thread === "top", | ||||
|           "thread-mid": props.thread === "middle", | ||||
|  | @ -262,7 +263,7 @@ const RegularToot: Component<RegularTootProps> = (oprops) => { | |||
|         {...rest} | ||||
|       > | ||||
|         <Show when={!!status().reblog}> | ||||
|           <div class="retoot-grp"> | ||||
|           <div class="retoot-grp card-gut card-pad"> | ||||
|             <BoostIcon /> | ||||
|             <Body2 | ||||
|               innerHTML={resolveCustomEmoji( | ||||
|  | @ -284,7 +285,6 @@ const RegularToot: Component<RegularTootProps> = (oprops) => { | |||
|           source={toot().content} | ||||
|           emojis={toot().emojis} | ||||
|           mentions={toot().mentions} | ||||
|           class={cardStyle.cardNoPad} | ||||
|           sensitive={toot().sensitive} | ||||
|           spoilerText={toot().spoilerText} | ||||
|           reveal={reveal()} | ||||
|  | @ -308,7 +308,6 @@ const RegularToot: Component<RegularTootProps> = (oprops) => { | |||
|         </Show> | ||||
|         {props.actionable && ( | ||||
|           <Divider | ||||
|             class={cardStyle.cardNoPad} | ||||
|             style={{ "margin-top": "8px" }} | ||||
|           /> | ||||
|         )} | ||||
|  | @ -319,7 +318,7 @@ const RegularToot: Component<RegularTootProps> = (oprops) => { | |||
|           }} | ||||
|         > | ||||
|           <Show when={props.actionable}> | ||||
|             <TootActionGroup value={status()} class={cardStyle.cardGutSkip} /> | ||||
|             <TootActionGroup value={status()} /> | ||||
|           </Show> | ||||
|         </Transition> | ||||
|       </article> | ||||
|  |  | |||
|  | @ -10,7 +10,6 @@ import RegularToot, { | |||
|   findElementActionable, | ||||
|   TootEnvProvider, | ||||
| } from "./RegularToot"; | ||||
| import cards from "~material/cards.module.css"; | ||||
| import { css } from "solid-styled"; | ||||
| import { createTimeSource, TimeSourceProvider } from "~platform/timesrc"; | ||||
| import TootComposer from "./TootComposer"; | ||||
|  | @ -177,7 +176,6 @@ const TootBottomSheet: Component = (props) => { | |||
|               <TootEnvProvider value={mainTootEnv}> | ||||
|                 <RegularToot | ||||
|                   id={`toot-${toot()!.id}`} | ||||
|                   class={cards.card} | ||||
|                   style={{ | ||||
|                     "scroll-margin-top": | ||||
|                       "calc(var(--scaffold-topbar-height) + 20px)", | ||||
|  |  | |||
|  | @ -1,7 +1,6 @@ | |||
| import { | ||||
|   createEffect, | ||||
|   createMemo, | ||||
|   createRenderEffect, | ||||
|   createSignal, | ||||
|   Show, | ||||
|   type Accessor, | ||||
|  | @ -39,14 +38,13 @@ import { | |||
|   Close, | ||||
|   MoreVert, | ||||
| } from "@suid/icons-material"; | ||||
| import type { Account } from "../accounts/stores"; | ||||
| import "./TootComposer.css"; | ||||
| import BottomSheet from "~material/BottomSheet"; | ||||
| import { useAppLocale } from "~platform/i18n"; | ||||
| import iso639_1 from "iso-639-1"; | ||||
| import ChooseTootLang from "./TootLangPicker"; | ||||
| import type { mastodon } from "masto"; | ||||
| import cardStyles from "~material/cards.module.css"; | ||||
| import "~material/cards.css"; | ||||
| import Menu, { createManagedMenuState } from "~material/Menu"; | ||||
| import { useDefaultSession } from "../masto/clients"; | ||||
| import { resolveCustomEmoji } from "../masto/toot"; | ||||
|  | @ -318,7 +316,7 @@ const TootComposer: Component<{ | |||
|   return ( | ||||
|     <div | ||||
|       ref={props.ref} | ||||
|       class={/* @once */ `TootComposer ${cardStyles.card}`} | ||||
|       class={/* @once */ `TootComposer card`} | ||||
|       style={containerStyle()} | ||||
|       on:touchend={ | ||||
|         cancelEvent | ||||
|  | @ -328,7 +326,7 @@ const TootComposer: Component<{ | |||
|       on:wheel={cancelEvent} | ||||
|     > | ||||
|       <Show when={active()}> | ||||
|         <Toolbar class={cardStyles.cardNoPad}> | ||||
|         <Toolbar class="card-gut"> | ||||
|           <IconButton | ||||
|             onClick={[setActive, false]} | ||||
|             aria-label="Close the composer" | ||||
|  | @ -341,7 +339,7 @@ const TootComposer: Component<{ | |||
|             <MoreVert /> | ||||
|           </IconButton> | ||||
|         </Toolbar> | ||||
|         <div class={cardStyles.cardNoPad}> | ||||
|         <div class="card-gut"> | ||||
|           <Menu {...menuState}> | ||||
|             <MenuItem> | ||||
|               <ListItemAvatar> | ||||
|  | @ -360,7 +358,7 @@ const TootComposer: Component<{ | |||
|         </div> | ||||
|       </Show> | ||||
| 
 | ||||
|       <div class="reply-input"> | ||||
|       <div class="reply-input card-gut card-pad"> | ||||
|         <Show when={props.profile}> | ||||
|           <Avatar | ||||
|             src={props.profile!.avatar} | ||||
|  | @ -406,7 +404,7 @@ const TootComposer: Component<{ | |||
|       </div> | ||||
| 
 | ||||
|       <Show when={active()}> | ||||
|         <div class="options"> | ||||
|         <div class="options card-pad card-gut"> | ||||
|           <Button | ||||
|             startIcon={<Translate />} | ||||
|             endIcon={<ArrowDropDown />} | ||||
|  | @ -430,7 +428,6 @@ const TootComposer: Component<{ | |||
|         </div> | ||||
| 
 | ||||
|         <TootVisibilityPickerDialog | ||||
|           class={cardStyles.cardNoPad} | ||||
|           open={permPicker()} | ||||
|           onClose={() => setPermPicker(false)} | ||||
|           visibility={visibility()} | ||||
|  | @ -438,7 +435,6 @@ const TootComposer: Component<{ | |||
|         /> | ||||
| 
 | ||||
|         <TootLanguagePickerDialog | ||||
|           class={cardStyles.cardNoPad} | ||||
|           open={langPickerOpen()} | ||||
|           onClose={() => setLangPickerOpen(false)} | ||||
|           code={language()} | ||||
|  |  | |||
|  | @ -15,7 +15,6 @@ import RegularToot, { | |||
|   findRootToot, | ||||
|   TootEnvProvider, | ||||
| } from "./RegularToot"; | ||||
| 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"; | ||||
|  | @ -221,7 +220,6 @@ const TootList: Component<{ | |||
|                             ? positionTootInThread(index, threadLength()) | ||||
|                             : undefined | ||||
|                         } | ||||
|                         class={cardStyle.card} | ||||
|                         evaluated={isExpanded(id)} | ||||
|                         actionable={isExpanded(id)} | ||||
|                         onClick={[onItemClick, status()]} | ||||
|  |  | |||
|  | @ -20,7 +20,7 @@ import { useStore } from "@nanostores/solid"; | |||
| import { $settings } from "../../settings/stores"; | ||||
| import { averageColorHex } from "~platform/blurhash"; | ||||
| import "./MediaAttachmentGrid.css"; | ||||
| import cardStyle from "~material/cards.module.css"; | ||||
| import "~material/cards.css"; | ||||
| import { Preview } from "@suid/icons-material"; | ||||
| import { IconButton } from "@suid/material"; | ||||
| import Masonry from "~platform/Masonry"; | ||||
|  | @ -153,7 +153,7 @@ const MediaAttachmentGrid: Component<{ | |||
|     <Masonry | ||||
|       component="section" | ||||
|       ref={setRootRef} | ||||
|       class={`MediaAttachmentGrid ${cardStyle.cardNoPad}`} | ||||
|       class={`MediaAttachmentGrid card-gut`} | ||||
|       classList={{ | ||||
|         sensitive: props.sensitive, | ||||
|       }} | ||||
|  |  | |||
|  | @ -75,7 +75,7 @@ export function PreviewCard(props: { | |||
|   return ( | ||||
|     <a | ||||
|       ref={root!} | ||||
|       class={"PreviewCard"} | ||||
|       class={"PreviewCard card-pad card-gut"} | ||||
|       href={props.src.url} | ||||
|       target="_blank" | ||||
|       referrerPolicy="unsafe-url" | ||||
|  |  | |||
|  | @ -19,7 +19,7 @@ function TootAuthorGroup( | |||
|   const { dateFn: dateFnLocale } = useAppLocale(); | ||||
| 
 | ||||
|   return ( | ||||
|     <div class="TootAuthorGroup" {...rest}> | ||||
|     <div class="TootAuthorGroup card-gut card-pad" {...rest}> | ||||
|       <Img src={toot().account.avatar} class="avatar" /> | ||||
|       <div class="name-grp"> | ||||
|         <div class="name-primary"> | ||||
|  |  | |||
|  | @ -75,7 +75,7 @@ const TootContent: Component<TootContentProps> = (oprops) => { | |||
|           } | ||||
|         }); | ||||
|       }} | ||||
|       class={`TootContent ${props.class || ""}`} | ||||
|       class={`TootContent card-gut card-pad ${props.class || ""}`} | ||||
|       {...rest} | ||||
|     > | ||||
|       <Show when={props.sensitive}> | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue