mirror of
https://gitee.com/zhangsken/opencode.git
synced 2026-10-16 02:24:10 +08:00
fix(app): fade home project list edges on scroll
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import { createMemo, For, type JSX, onCleanup, Show, splitProps } from "solid-js"
|
import { createMemo, For, type JSX, onCleanup, Show, splitProps } from "solid-js"
|
||||||
import { createStore } from "solid-js/store"
|
import { createStore } from "solid-js/store"
|
||||||
|
import { createResizeObserver } from "@solid-primitives/resize-observer"
|
||||||
import { Popover } from "@kobalte/core/popover"
|
import { Popover } from "@kobalte/core/popover"
|
||||||
import { DragDropProvider, PointerSensor } from "@dnd-kit/solid"
|
import { DragDropProvider, PointerSensor } from "@dnd-kit/solid"
|
||||||
import { isSortable, useSortable } from "@dnd-kit/solid/sortable"
|
import { isSortable, useSortable } from "@dnd-kit/solid/sortable"
|
||||||
@@ -151,10 +152,20 @@ export function HomeProjectsView(props: HomeProjectsViewProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function HomeProjectsPanel(props: HomeProjectsViewProps) {
|
function HomeProjectsPanel(props: HomeProjectsViewProps) {
|
||||||
const [contextMenu, setContextMenu] = createStore({ open: undefined as string | undefined })
|
let observer: MutationObserver | undefined
|
||||||
|
let frame = 0
|
||||||
|
const [state, setState] = createStore({ contextMenu: undefined as string | undefined })
|
||||||
|
const updateFades = (element: HTMLDivElement) => {
|
||||||
|
element.toggleAttribute("data-fade-top", element.scrollTop > 0)
|
||||||
|
element.toggleAttribute("data-fade-bottom", element.scrollTop + element.clientHeight < element.scrollHeight - 1)
|
||||||
|
}
|
||||||
|
onCleanup(() => {
|
||||||
|
observer?.disconnect()
|
||||||
|
cancelAnimationFrame(frame)
|
||||||
|
})
|
||||||
const contextMenuProps = {
|
const contextMenuProps = {
|
||||||
contextMenuOpen: (id: string) => contextMenu.open === id,
|
contextMenuOpen: (id: string) => state.contextMenu === id,
|
||||||
onSetContextMenuOpen: (id: string, open: boolean) => setContextMenu("open", open ? id : undefined),
|
onSetContextMenuOpen: (id: string, open: boolean) => setState("contextMenu", open ? id : undefined),
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<aside
|
<aside
|
||||||
@@ -191,7 +202,17 @@ function HomeProjectsPanel(props: HomeProjectsViewProps) {
|
|||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
<ScrollView data-slot="home-projects-scroll" class="min-h-0 min-w-0 shrink">
|
<ScrollView
|
||||||
|
data-slot="home-projects-scroll"
|
||||||
|
class="min-h-0 min-w-0 shrink"
|
||||||
|
viewportRef={(element) => {
|
||||||
|
createResizeObserver(element, () => updateFades(element))
|
||||||
|
observer = new MutationObserver(() => updateFades(element))
|
||||||
|
observer.observe(element, { childList: true, subtree: true })
|
||||||
|
frame = requestAnimationFrame(() => updateFades(element))
|
||||||
|
}}
|
||||||
|
onScroll={(event) => updateFades(event.currentTarget)}
|
||||||
|
>
|
||||||
<Show when={props.dropdown && props.servers.length === 1}>
|
<Show when={props.dropdown && props.servers.length === 1}>
|
||||||
<HomeProjectNavButton
|
<HomeProjectNavButton
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
+19
-32
@@ -445,8 +445,25 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-slot="home-projects-scroll"] {
|
[data-slot="home-projects-scroll"] > .scroll-view__viewport[data-fade-top] {
|
||||||
timeline-scope: --home-projects-scroll;
|
-webkit-mask-image: linear-gradient(to bottom, transparent, black 16px);
|
||||||
|
mask-image: linear-gradient(to bottom, transparent, black 16px);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-slot="home-projects-scroll"] > .scroll-view__viewport[data-fade-bottom] {
|
||||||
|
-webkit-mask-image: linear-gradient(to bottom, black calc(100% - 16px), transparent);
|
||||||
|
mask-image: linear-gradient(to bottom, black calc(100% - 16px), transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-slot="home-projects-scroll"] > .scroll-view__viewport[data-fade-top][data-fade-bottom] {
|
||||||
|
-webkit-mask-image: linear-gradient(
|
||||||
|
to bottom,
|
||||||
|
transparent,
|
||||||
|
black 16px,
|
||||||
|
black calc(100% - 16px),
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
mask-image: linear-gradient(to bottom, transparent, black 16px, black calc(100% - 16px), transparent);
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-slot="model-selector-scroll"] {
|
[data-slot="model-selector-scroll"] {
|
||||||
@@ -457,8 +474,6 @@
|
|||||||
timeline-scope: --manage-models-scroll;
|
timeline-scope: --manage-models-scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-slot="home-projects-scroll"]::before,
|
|
||||||
[data-slot="home-projects-scroll"]::after,
|
|
||||||
[data-slot="model-selector-scroll"]::before,
|
[data-slot="model-selector-scroll"]::before,
|
||||||
[data-slot="model-selector-scroll"]::after,
|
[data-slot="model-selector-scroll"]::after,
|
||||||
[data-slot="manage-models-scroll"]::before {
|
[data-slot="manage-models-scroll"]::before {
|
||||||
@@ -472,11 +487,6 @@
|
|||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-slot="home-projects-scroll"]::before {
|
|
||||||
top: 0;
|
|
||||||
background: linear-gradient(to bottom, var(--v2-background-bg-base), transparent);
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-slot="model-selector-scroll"]::before {
|
[data-slot="model-selector-scroll"]::before {
|
||||||
top: 0;
|
top: 0;
|
||||||
height: 12px;
|
height: 12px;
|
||||||
@@ -506,11 +516,6 @@
|
|||||||
background: linear-gradient(to bottom, var(--v2-background-bg-base), transparent);
|
background: linear-gradient(to bottom, var(--v2-background-bg-base), transparent);
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-slot="home-projects-scroll"]::after {
|
|
||||||
bottom: 0;
|
|
||||||
background: linear-gradient(to top, var(--v2-background-bg-base), transparent);
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-slot="model-selector-scroll"]::after {
|
[data-slot="model-selector-scroll"]::after {
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
height: 12px;
|
height: 12px;
|
||||||
@@ -535,24 +540,6 @@
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@supports (animation-timeline: --home-projects-scroll) and (timeline-scope: --home-projects-scroll) {
|
|
||||||
[data-slot="home-projects-scroll"] .scroll-view__viewport {
|
|
||||||
scroll-timeline: --home-projects-scroll y;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-slot="home-projects-scroll"]::before {
|
|
||||||
animation: home-projects-fade-top linear both;
|
|
||||||
animation-timeline: --home-projects-scroll;
|
|
||||||
animation-range: 0 0.1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-slot="home-projects-scroll"]::after {
|
|
||||||
animation: home-projects-fade-bottom linear both;
|
|
||||||
animation-timeline: --home-projects-scroll;
|
|
||||||
animation-range: calc(100% - 1.1px) calc(100% - 1px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@supports (animation-timeline: --model-selector-scroll) and (timeline-scope: --model-selector-scroll) {
|
@supports (animation-timeline: --model-selector-scroll) and (timeline-scope: --model-selector-scroll) {
|
||||||
[data-slot="model-selector-scroll"] .scroll-view__viewport {
|
[data-slot="model-selector-scroll"] .scroll-view__viewport {
|
||||||
scroll-timeline: --model-selector-scroll y;
|
scroll-timeline: --model-selector-scroll y;
|
||||||
|
|||||||
Reference in New Issue
Block a user