Compare commits
5 commits
8a435be4c8
...
4a46a0fbc9
Author | SHA1 | Date | |
---|---|---|---|
|
4a46a0fbc9 | ||
|
376f97c5cd | ||
|
898575637e | ||
|
92af897590 | ||
|
65fa4c4fa5 |
8 changed files with 312 additions and 155 deletions
|
@ -7,6 +7,22 @@
|
||||||
width: max-content;
|
width: max-content;
|
||||||
box-shadow: var(--tutu-shadow-e8);
|
box-shadow: var(--tutu-shadow-e8);
|
||||||
contain: content;
|
contain: content;
|
||||||
|
|
||||||
|
&.e1 {
|
||||||
|
box-shadow: var(--tutu-shadow-e9);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.e2 {
|
||||||
|
box-shadow: var(--tutu-shadow-e10);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.e3 {
|
||||||
|
box-shadow: var(--tutu-shadow-e11);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.e4 {
|
||||||
|
box-shadow: var(--tutu-shadow-e12);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dialog.Menu::backdrop {
|
dialog.Menu::backdrop {
|
||||||
|
|
|
@ -3,8 +3,9 @@ import { MenuList } from "@suid/material";
|
||||||
import {
|
import {
|
||||||
createEffect,
|
createEffect,
|
||||||
createSignal,
|
createSignal,
|
||||||
|
type Component,
|
||||||
type JSX,
|
type JSX,
|
||||||
type ParentComponent,
|
type ParentProps,
|
||||||
} from "solid-js";
|
} from "solid-js";
|
||||||
import { ANIM_CURVE_STD } from "./theme";
|
import { ANIM_CURVE_STD } from "./theme";
|
||||||
import "./Menu.css";
|
import "./Menu.css";
|
||||||
|
@ -13,13 +14,13 @@ import {
|
||||||
animateShrinkToTopRight,
|
animateShrinkToTopRight,
|
||||||
} from "../platform/anim";
|
} from "../platform/anim";
|
||||||
|
|
||||||
type Anchor = Pick<DOMRect, "top" | "left" | "right">
|
export type Anchor = Pick<DOMRect, "top" | "left" | "right"> & { e?: number };
|
||||||
|
|
||||||
type Props = {
|
export type MenuProps = ParentProps<{
|
||||||
open?: boolean;
|
open?: boolean;
|
||||||
onClose?: JSX.EventHandlerUnion<HTMLDialogElement, Event>;
|
onClose?: JSX.EventHandlerUnion<HTMLDialogElement, Event>;
|
||||||
anchor: () => Anchor;
|
anchor: () => Anchor;
|
||||||
};
|
}>;
|
||||||
|
|
||||||
function px(n?: number) {
|
function px(n?: number) {
|
||||||
if (n) {
|
if (n) {
|
||||||
|
@ -29,15 +30,71 @@ function px(n?: number) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const Menu: ParentComponent<Props> = (props) => {
|
/**
|
||||||
|
* Create managed state for {@link Menu}. This function
|
||||||
|
* expose an "open" closure for you to open the menu. The
|
||||||
|
* opening and closing is automatically managed internally.
|
||||||
|
*
|
||||||
|
* @returns The first element is the "open" closure, calls
|
||||||
|
* with anchor infomation to open the menu.
|
||||||
|
* The second element is the state props for {@link Menu}, use
|
||||||
|
* spread syntax to set the props.
|
||||||
|
* @example
|
||||||
|
* ````tsx
|
||||||
|
* const [openMenu, menuState] = createManagedMenuState();
|
||||||
|
*
|
||||||
|
* <Menu {...menuState}></Menu>
|
||||||
|
*
|
||||||
|
* <Button onClick={event => openMenu(event.currectTarget.getBoundingClientRect())} />
|
||||||
|
* ````
|
||||||
|
*/
|
||||||
|
export function createManagedMenuState() {
|
||||||
|
const [anchor, setAnchor] = createSignal<Anchor>();
|
||||||
|
|
||||||
|
return [
|
||||||
|
setAnchor,
|
||||||
|
{
|
||||||
|
get open() {
|
||||||
|
return !!anchor();
|
||||||
|
},
|
||||||
|
anchor: anchor as () => Anchor,
|
||||||
|
onClose: () => setAnchor(),
|
||||||
|
},
|
||||||
|
] as const;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Material Menu Component. This component is
|
||||||
|
* implemented with dialog and {@link MenuList} from SUID.
|
||||||
|
*
|
||||||
|
* Notes:
|
||||||
|
* - Use {@link createManagedMenuState} and you don't need to manage the open and close.
|
||||||
|
* - Use {@link MenuItem} from SUID as children.
|
||||||
|
*/
|
||||||
|
const Menu: Component<MenuProps> = (props) => {
|
||||||
let root: HTMLDialogElement;
|
let root: HTMLDialogElement;
|
||||||
const windowSize = useWindowSize();
|
const windowSize = useWindowSize();
|
||||||
|
|
||||||
const [anchorPos, setAnchorPos] = createSignal<{
|
const [anchorPos, setAnchorPos] = createSignal<{
|
||||||
left?: number;
|
left?: number;
|
||||||
top?: number;
|
top?: number;
|
||||||
|
e?: number;
|
||||||
}>({});
|
}>({});
|
||||||
|
|
||||||
|
if (import.meta.env.DEV) {
|
||||||
|
createEffect(() => {
|
||||||
|
switch (anchorPos().e) {
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
case 3:
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
console.warn('value %s is invalid for param "e"', anchorPos().e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let openAnimationOrigin: "lt" | "rt" = "lt";
|
let openAnimationOrigin: "lt" | "rt" = "lt";
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
|
@ -49,18 +106,19 @@ const Menu: ParentComponent<Props> = (props) => {
|
||||||
const rend = root.getBoundingClientRect();
|
const rend = root.getBoundingClientRect();
|
||||||
|
|
||||||
const { width } = windowSize;
|
const { width } = windowSize;
|
||||||
const { left, top, right } = a;
|
const { left, top, right, e } = a;
|
||||||
if (left > width / 2) {
|
if (left > width / 2) {
|
||||||
openAnimationOrigin = "rt";
|
openAnimationOrigin = "rt";
|
||||||
setAnchorPos({
|
setAnchorPos({
|
||||||
left: right - rend.width,
|
left: right - rend.width,
|
||||||
top,
|
top,
|
||||||
|
e,
|
||||||
});
|
});
|
||||||
|
|
||||||
animateGrowFromTopRight(root, { easing: ANIM_CURVE_STD });
|
animateGrowFromTopRight(root, { easing: ANIM_CURVE_STD });
|
||||||
} else {
|
} else {
|
||||||
openAnimationOrigin = "lt";
|
openAnimationOrigin = "lt";
|
||||||
setAnchorPos({ left, top });
|
setAnchorPos({ left, top, e });
|
||||||
|
|
||||||
const overflow = root.style.overflow;
|
const overflow = root.style.overflow;
|
||||||
root.style.overflow = "hidden";
|
root.style.overflow = "hidden";
|
||||||
|
@ -138,7 +196,7 @@ const Menu: ParentComponent<Props> = (props) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
class="Menu"
|
class={`Menu e${anchorPos().e || 0}`}
|
||||||
style={{
|
style={{
|
||||||
left: px(anchorPos().left),
|
left: px(anchorPos().left),
|
||||||
top: px(anchorPos().top),
|
top: px(anchorPos().top),
|
||||||
|
@ -148,6 +206,7 @@ const Menu: ParentComponent<Props> = (props) => {
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
background: "var(--tutu-color-surface)",
|
background: "var(--tutu-color-surface)",
|
||||||
|
display: "contents"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<MenuList>{props.children}</MenuList>
|
<MenuList>{props.children}</MenuList>
|
||||||
|
|
22
src/material/Scaffold.css
Normal file
22
src/material/Scaffold.css
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
|
||||||
|
.Scaffold__topbar {
|
||||||
|
position: sticky;
|
||||||
|
top: 0px;
|
||||||
|
z-index: var(--tutu-zidx-nav, auto);
|
||||||
|
}
|
||||||
|
|
||||||
|
.Scaffold__fab-dock {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 40px;
|
||||||
|
right: 40px;
|
||||||
|
z-index: var(--tutu-zidx-nav, auto);
|
||||||
|
}
|
||||||
|
|
||||||
|
.Scaffold__bottom-dock {
|
||||||
|
position: sticky;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: var(--tutu-zidx-nav, auto);
|
||||||
|
padding-bottom: var(--safe-area-inset-bottom, 0);
|
||||||
|
}
|
|
@ -1,66 +1,67 @@
|
||||||
import { createElementSize } from "@solid-primitives/resize-observer";
|
import { createElementSize } from "@solid-primitives/resize-observer";
|
||||||
import {
|
import {
|
||||||
|
JSX,
|
||||||
Show,
|
Show,
|
||||||
createRenderEffect,
|
createRenderEffect,
|
||||||
createSignal,
|
createSignal,
|
||||||
onCleanup,
|
splitProps,
|
||||||
type JSX,
|
type Component,
|
||||||
type ParentComponent,
|
type ParentProps,
|
||||||
} from "solid-js";
|
} from "solid-js";
|
||||||
import { css } from "solid-styled";
|
import "./Scaffold.css";
|
||||||
|
|
||||||
interface ScaffoldProps {
|
type ScaffoldProps = ParentProps<
|
||||||
topbar?: JSX.Element;
|
{
|
||||||
fab?: JSX.Element;
|
topbar?: JSX.Element;
|
||||||
bottom?: JSX.Element;
|
fab?: JSX.Element;
|
||||||
}
|
bottom?: JSX.Element;
|
||||||
|
} & JSX.HTMLElementTags["div"]
|
||||||
|
>;
|
||||||
|
|
||||||
const Scaffold: ParentComponent<ScaffoldProps> = (props) => {
|
/**
|
||||||
|
* The passthrough props are passed to the content container.
|
||||||
|
*/
|
||||||
|
const Scaffold: Component<ScaffoldProps> = (props) => {
|
||||||
|
const [managed, rest] = splitProps(props, [
|
||||||
|
"topbar",
|
||||||
|
"fab",
|
||||||
|
"bottom",
|
||||||
|
"children",
|
||||||
|
"ref",
|
||||||
|
]);
|
||||||
const [topbarElement, setTopbarElement] = createSignal<HTMLElement>();
|
const [topbarElement, setTopbarElement] = createSignal<HTMLElement>();
|
||||||
|
|
||||||
const topbarSize = createElementSize(topbarElement);
|
const topbarSize = createElementSize(topbarElement);
|
||||||
|
|
||||||
css`
|
|
||||||
.scaffold-content {
|
|
||||||
--scaffold-topbar-height: ${(topbarSize.height?.toString() ?? 0) + "px"};
|
|
||||||
}
|
|
||||||
|
|
||||||
.topbar {
|
|
||||||
position: sticky;
|
|
||||||
top: 0px;
|
|
||||||
z-index: var(--tutu-zidx-nav, auto);
|
|
||||||
}
|
|
||||||
|
|
||||||
.fab-dock {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 40px;
|
|
||||||
right: 40px;
|
|
||||||
z-index: var(--tutu-zidx-nav, auto);
|
|
||||||
}
|
|
||||||
|
|
||||||
.bottom-dock {
|
|
||||||
position: sticky;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
z-index: var(--tutu-zidx-nav, auto);
|
|
||||||
padding-bottom: var(--safe-area-inset-bottom, 0);
|
|
||||||
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Show when={props.topbar}>
|
<Show when={props.topbar}>
|
||||||
<div class="topbar" ref={setTopbarElement}>
|
<div class="Scaffold__topbar" ref={setTopbarElement}>
|
||||||
{props.topbar}
|
{props.topbar}
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={props.fab}>
|
<Show when={props.fab}>
|
||||||
<div class="fab-dock">{props.fab}</div>
|
<div class="Scaffold__fab-dock">{props.fab}</div>
|
||||||
</Show>
|
</Show>
|
||||||
<div class="scaffold-content">{props.children}</div>
|
<div
|
||||||
|
ref={(e) => {
|
||||||
|
createRenderEffect(() => {
|
||||||
|
e.style.setProperty(
|
||||||
|
"--scaffold-topbar-height",
|
||||||
|
(topbarSize.height?.toString() ?? 0) + "px",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (managed.ref) {
|
||||||
|
(managed.ref as (val: typeof e) => void)(e);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
|
{managed.children}
|
||||||
|
</div>
|
||||||
<Show when={props.bottom}>
|
<Show when={props.bottom}>
|
||||||
<div class="bottom-dock">{props.bottom}</div>
|
<div class="Scaffold__bottom-dock">{props.bottom}</div>
|
||||||
</Show>
|
</Show>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
@ -106,6 +106,8 @@
|
||||||
|
|
||||||
/* Submenu (+1dp for each submenu) */
|
/* Submenu (+1dp for each submenu) */
|
||||||
--tutu-shadow-e9: 0px 9px 18px 0px var(--tutu-color-shadow);
|
--tutu-shadow-e9: 0px 9px 18px 0px var(--tutu-color-shadow);
|
||||||
|
--tutu-shadow-e10: 0px 10px 18px 0px var(--tutu-color-shadow);
|
||||||
|
--tutu-shadow-e11: 0px 11px 18px 0px var(--tutu-color-shadow-l1);
|
||||||
|
|
||||||
/* (pressed) FAB */
|
/* (pressed) FAB */
|
||||||
--tutu-shadow-e12: 0px 12px 24px 0px var(--tutu-color-shadow-l1);
|
--tutu-shadow-e12: 0px 12px 24px 0px var(--tutu-color-shadow-l1);
|
||||||
|
|
82
src/profiles/Profile.css
Normal file
82
src/profiles/Profile.css
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
.Profile {
|
||||||
|
.intro {
|
||||||
|
background-color: var(--tutu-color-surface-d);
|
||||||
|
color: var(--tutu-color-on-surface);
|
||||||
|
padding: 16px 12px;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column nowrap;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
& a {
|
||||||
|
color: inherit;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.acct-grp {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row wrap;
|
||||||
|
gap: 16px;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
& > :nth-child(2) {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > :last-child {
|
||||||
|
flex-grow: 1;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.name-grp {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.acct-fields {
|
||||||
|
word-break: break-all;
|
||||||
|
|
||||||
|
& td > a {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
color: inherit;
|
||||||
|
min-height: 44px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& a > .invisible {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
& svg {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.toot-list-toolbar {
|
||||||
|
position: sticky;
|
||||||
|
top: var(--scaffold-topbar-height);
|
||||||
|
z-index: calc(var(--tutu-zidx-nav, 1) - 1);
|
||||||
|
background: var(--tutu-color-surface);
|
||||||
|
border-bottom: 1px solid var(--tutu-color-surface-d);
|
||||||
|
contain: content;
|
||||||
|
/* TODO: box-shadow is needed here (same as app bar, e6).
|
||||||
|
There is no good way to detect if the sticky is "sticked" -
|
||||||
|
so let's leave it for future.
|
||||||
|
|
||||||
|
For now we use a trick to make it looks better.
|
||||||
|
*/
|
||||||
|
box-shadow: 0px -2px 4px 0px var(--tutu-color-shadow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.Profile__page-title {
|
||||||
|
flex-grow: 1;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
|
@ -5,6 +5,8 @@ import {
|
||||||
createSignal,
|
createSignal,
|
||||||
createUniqueId,
|
createUniqueId,
|
||||||
For,
|
For,
|
||||||
|
Switch,
|
||||||
|
Match,
|
||||||
onCleanup,
|
onCleanup,
|
||||||
Show,
|
Show,
|
||||||
type Component,
|
type Component,
|
||||||
|
@ -17,6 +19,7 @@ import {
|
||||||
CircularProgress,
|
CircularProgress,
|
||||||
Divider,
|
Divider,
|
||||||
IconButton,
|
IconButton,
|
||||||
|
ListItemAvatar,
|
||||||
ListItemIcon,
|
ListItemIcon,
|
||||||
ListItemText,
|
ListItemText,
|
||||||
MenuItem,
|
MenuItem,
|
||||||
|
@ -42,13 +45,13 @@ import { useSessionForAcctStr } from "../masto/clients";
|
||||||
import { resolveCustomEmoji } from "../masto/toot";
|
import { resolveCustomEmoji } from "../masto/toot";
|
||||||
import { FastAverageColor } from "fast-average-color";
|
import { FastAverageColor } from "fast-average-color";
|
||||||
import { useWindowSize } from "@solid-primitives/resize-observer";
|
import { useWindowSize } from "@solid-primitives/resize-observer";
|
||||||
import { css } from "solid-styled";
|
|
||||||
import { createTimeline, createTimelineSnapshot } from "../masto/timelines";
|
import { createTimeline, createTimelineSnapshot } from "../masto/timelines";
|
||||||
import TootList from "../timelines/TootList";
|
import TootList from "../timelines/TootList";
|
||||||
import { createTimeSource, TimeSourceProvider } from "../platform/timesrc";
|
import { createTimeSource, TimeSourceProvider } from "../platform/timesrc";
|
||||||
import TootFilterButton from "./TootFilterButton";
|
import TootFilterButton from "./TootFilterButton";
|
||||||
import Menu from "../material/Menu";
|
import Menu, { createManagedMenuState } from "../material/Menu";
|
||||||
import { share } from "../platform/share";
|
import { share } from "../platform/share";
|
||||||
|
import "./Profile.css";
|
||||||
|
|
||||||
const Profile: Component = () => {
|
const Profile: Component = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
@ -66,6 +69,8 @@ const Profile: Component = () => {
|
||||||
|
|
||||||
const [menuOpen, setMenuOpen] = createSignal(false);
|
const [menuOpen, setMenuOpen] = createSignal(false);
|
||||||
|
|
||||||
|
const [openSubscribeMenu, subscribeMenuState] = createManagedMenuState();
|
||||||
|
|
||||||
const [scrolledPastBanner, setScrolledPastBanner] = createSignal(false);
|
const [scrolledPastBanner, setScrolledPastBanner] = createSignal(false);
|
||||||
const obx = new IntersectionObserver(
|
const obx = new IntersectionObserver(
|
||||||
(entries) => {
|
(entries) => {
|
||||||
|
@ -132,89 +137,6 @@ const Profile: Component = () => {
|
||||||
recentTootChunk.loading ||
|
recentTootChunk.loading ||
|
||||||
(recentTootFilter().pinned && pinnedTootChunk.loading);
|
(recentTootFilter().pinned && pinnedTootChunk.loading);
|
||||||
|
|
||||||
css`
|
|
||||||
.intro {
|
|
||||||
background-color: var(--tutu-color-surface-d);
|
|
||||||
color: var(--tutu-color-on-surface);
|
|
||||||
padding: 16px 12px;
|
|
||||||
display: flex;
|
|
||||||
flex-flow: column nowrap;
|
|
||||||
gap: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.description {
|
|
||||||
& :global(a) {
|
|
||||||
color: inherit;
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
word-break: break-all;
|
|
||||||
}
|
|
||||||
|
|
||||||
.acct-grp {
|
|
||||||
display: flex;
|
|
||||||
flex-flow: row wrap;
|
|
||||||
gap: 16px;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
& > :nth-child(2) {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > :last-child {
|
|
||||||
flex-grow: 1;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.name-grp {
|
|
||||||
display: flex;
|
|
||||||
flex-flow: column nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.acct-fields {
|
|
||||||
word-break: break-all;
|
|
||||||
|
|
||||||
& td > :global(a) {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
color: inherit;
|
|
||||||
min-height: 44px;
|
|
||||||
}
|
|
||||||
|
|
||||||
& :global(a > .invisible) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
& :global(svg) {
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.page-title {
|
|
||||||
flex-grow: 1;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toot-list-toolbar {
|
|
||||||
position: sticky;
|
|
||||||
top: var(--scaffold-topbar-height);
|
|
||||||
z-index: calc(var(--tutu-zidx-nav, 1) - 1);
|
|
||||||
background: var(--tutu-color-surface);
|
|
||||||
border-bottom: 1px solid var(--tutu-color-surface-d);
|
|
||||||
contain: content;
|
|
||||||
/* TODO: box-shadow is needed here (same as app bar, e6).
|
|
||||||
There is no good way to detect if the sticky is "sticked" -
|
|
||||||
so let's leave it for future.
|
|
||||||
|
|
||||||
For now we use a trick to make it looks better.
|
|
||||||
*/
|
|
||||||
box-shadow: 0px -2px 4px 0px var(--tutu-color-shadow);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Scaffold
|
<Scaffold
|
||||||
topbar={
|
topbar={
|
||||||
|
@ -241,8 +163,7 @@ const Profile: Component = () => {
|
||||||
<Close />
|
<Close />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<Title
|
<Title
|
||||||
use:solid-styled
|
class="Profile__page-title"
|
||||||
class="page-title"
|
|
||||||
style={{
|
style={{
|
||||||
visibility: scrolledPastBanner() ? undefined : "hidden",
|
visibility: scrolledPastBanner() ? undefined : "hidden",
|
||||||
}}
|
}}
|
||||||
|
@ -261,6 +182,7 @@ const Profile: Component = () => {
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
</AppBar>
|
</AppBar>
|
||||||
}
|
}
|
||||||
|
class="Profile"
|
||||||
>
|
>
|
||||||
<Menu
|
<Menu
|
||||||
open={menuOpen()}
|
open={menuOpen()}
|
||||||
|
@ -269,25 +191,38 @@ const Profile: Component = () => {
|
||||||
document.getElementById(menuButId)!.getBoundingClientRect()
|
document.getElementById(menuButId)!.getBoundingClientRect()
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Show
|
<Show when={session().account && profile()}>
|
||||||
when={isCurrentSessionProfile()}
|
<Show
|
||||||
fallback={
|
when={isCurrentSessionProfile()}
|
||||||
|
fallback={
|
||||||
|
<MenuItem
|
||||||
|
onClick={(event) => {
|
||||||
|
const { left, right, top } =
|
||||||
|
event.currentTarget.getBoundingClientRect();
|
||||||
|
openSubscribeMenu({
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
top,
|
||||||
|
e: 1,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ListItemIcon>
|
||||||
|
<PlaylistAdd />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText>Subscribe...</ListItemText>
|
||||||
|
</MenuItem>
|
||||||
|
}
|
||||||
|
>
|
||||||
<MenuItem disabled>
|
<MenuItem disabled>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<PlaylistAdd />
|
<Edit />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText>Subscribe...</ListItemText>
|
<ListItemText>Edit...</ListItemText>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
}
|
</Show>
|
||||||
>
|
<Divider />
|
||||||
<MenuItem disabled>
|
|
||||||
<ListItemIcon>
|
|
||||||
<Edit />
|
|
||||||
</ListItemIcon>
|
|
||||||
<ListItemText>Edit...</ListItemText>
|
|
||||||
</MenuItem>
|
|
||||||
</Show>
|
</Show>
|
||||||
<Divider />
|
|
||||||
<MenuItem disabled>
|
<MenuItem disabled>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<Group />
|
<Group />
|
||||||
|
@ -360,6 +295,27 @@ const Profile: Component = () => {
|
||||||
></img>
|
></img>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<Menu {...subscribeMenuState}>
|
||||||
|
<MenuItem disabled>
|
||||||
|
<ListItemAvatar>
|
||||||
|
<Avatar src={session().account?.inf?.avatar}></Avatar>
|
||||||
|
</ListItemAvatar>
|
||||||
|
<ListItemText>
|
||||||
|
<span
|
||||||
|
ref={(e) =>
|
||||||
|
createRenderEffect(() => {
|
||||||
|
e.innerHTML = resolveCustomEmoji(
|
||||||
|
session().account?.inf?.displayName || "",
|
||||||
|
session().account?.inf?.emojis ?? [],
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
></span>
|
||||||
|
<span>'s Home</span>
|
||||||
|
</ListItemText>
|
||||||
|
</MenuItem>
|
||||||
|
</Menu>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="intro"
|
class="intro"
|
||||||
style={{
|
style={{
|
||||||
|
@ -385,9 +341,29 @@ const Profile: Component = () => {
|
||||||
<span>{fullUsername()}</span>
|
<span>{fullUsername()}</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Button variant="contained" color="secondary">
|
<Switch>
|
||||||
Subscribe
|
<Match when={!session().account || profileErrorUncaught.loading}>
|
||||||
</Button>
|
{<></>}
|
||||||
|
</Match>
|
||||||
|
<Match when={isCurrentSessionProfile()}>
|
||||||
|
<IconButton color="inherit">
|
||||||
|
<Edit />
|
||||||
|
</IconButton>
|
||||||
|
</Match>
|
||||||
|
<Match when={true}>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="secondary"
|
||||||
|
onClick={(event) => {
|
||||||
|
openSubscribeMenu(
|
||||||
|
event.currentTarget.getBoundingClientRect(),
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Subscribe
|
||||||
|
</Button>
|
||||||
|
</Match>
|
||||||
|
</Switch>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -123,7 +123,6 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
position: relative;
|
position: relative;
|
||||||
contain: content;
|
|
||||||
|
|
||||||
>img {
|
>img {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
|
|
Loading…
Reference in a new issue