mirror of
https://github.com/sst/opencode.git
synced 2025-07-08 00:25:00 +00:00
Merge branch 'jeremyosih-feat/scroll-to-bottom-button' into dev
This commit is contained in:
commit
688f3fd12f
2 changed files with 113 additions and 0 deletions
|
@ -39,6 +39,7 @@ import {
|
|||
IconMagnifyingGlass,
|
||||
IconWrenchScrewdriver,
|
||||
IconDocumentMagnifyingGlass,
|
||||
IconArrowDown,
|
||||
} from "./icons"
|
||||
import DiffView from "./DiffView"
|
||||
import CodeBlock from "./CodeBlock"
|
||||
|
@ -594,12 +595,17 @@ export default function Share(props: {
|
|||
info: Session.Info
|
||||
messages: Record<string, Message.Info>
|
||||
}) {
|
||||
let lastScrollY = 0
|
||||
let hasScrolled = false
|
||||
let scrollTimeout: number | undefined
|
||||
|
||||
const id = props.id
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
const debug = params.get("debug") === "true"
|
||||
|
||||
const [showScrollButton, setShowScrollButton] = createSignal(false)
|
||||
const [isButtonHovered, setIsButtonHovered] = createSignal(false)
|
||||
|
||||
const anchorId = createMemo<string | null>(() => {
|
||||
const raw = window.location.hash.slice(1)
|
||||
const [id] = raw.split("-")
|
||||
|
@ -715,6 +721,54 @@ export default function Share(props: {
|
|||
})
|
||||
})
|
||||
|
||||
function checkScrollNeed() {
|
||||
const currentScrollY = window.scrollY
|
||||
const isScrollingDown = currentScrollY > lastScrollY
|
||||
const scrolled = currentScrollY > 200 // Show after scrolling 200px
|
||||
const isNearBottom = window.innerHeight + currentScrollY >= document.body.scrollHeight - 100
|
||||
|
||||
// Only show when scrolling down, scrolled enough, and not near bottom
|
||||
const shouldShow = isScrollingDown && scrolled && !isNearBottom
|
||||
|
||||
// Update last scroll position
|
||||
lastScrollY = currentScrollY
|
||||
|
||||
if (shouldShow) {
|
||||
setShowScrollButton(true)
|
||||
// Clear existing timeout
|
||||
if (scrollTimeout) {
|
||||
clearTimeout(scrollTimeout)
|
||||
}
|
||||
// Hide button after 3 seconds of no scrolling (unless hovered)
|
||||
scrollTimeout = window.setTimeout(() => {
|
||||
if (!isButtonHovered()) {
|
||||
setShowScrollButton(false)
|
||||
}
|
||||
}, 3000)
|
||||
} else if (!isButtonHovered()) {
|
||||
// Only hide if not hovered (to prevent disappearing while user is about to click)
|
||||
setShowScrollButton(false)
|
||||
if (scrollTimeout) {
|
||||
clearTimeout(scrollTimeout)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
lastScrollY = window.scrollY // Initialize scroll position
|
||||
checkScrollNeed()
|
||||
window.addEventListener("scroll", checkScrollNeed)
|
||||
window.addEventListener("resize", checkScrollNeed)
|
||||
})
|
||||
|
||||
onCleanup(() => {
|
||||
window.removeEventListener("scroll", checkScrollNeed)
|
||||
window.removeEventListener("resize", checkScrollNeed)
|
||||
if (scrollTimeout) {
|
||||
clearTimeout(scrollTimeout)
|
||||
}
|
||||
})
|
||||
|
||||
const data = createMemo(() => {
|
||||
const result = {
|
||||
rootDir: undefined as string | undefined,
|
||||
|
@ -825,6 +879,7 @@ export default function Share(props: {
|
|||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -1902,6 +1957,36 @@ export default function Share(props: {
|
|||
</div>
|
||||
</div>
|
||||
</Show>
|
||||
|
||||
<Show when={showScrollButton()}>
|
||||
<button
|
||||
type="button"
|
||||
class={styles["scroll-button"]}
|
||||
onClick={() =>
|
||||
document.body.scrollIntoView({ behavior: "smooth", block: "end" })
|
||||
}
|
||||
onMouseEnter={() => {
|
||||
setIsButtonHovered(true)
|
||||
if (scrollTimeout) {
|
||||
clearTimeout(scrollTimeout)
|
||||
}
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
setIsButtonHovered(false)
|
||||
if (showScrollButton()) {
|
||||
scrollTimeout = window.setTimeout(() => {
|
||||
if (!isButtonHovered()) {
|
||||
setShowScrollButton(false)
|
||||
}
|
||||
}, 3000)
|
||||
}
|
||||
}}
|
||||
title="Scroll to bottom"
|
||||
aria-label="Scroll to bottom"
|
||||
>
|
||||
<IconArrowDown width={20} height={20} />
|
||||
</button>
|
||||
</Show>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -784,3 +784,31 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.scroll-button {
|
||||
position: fixed;
|
||||
bottom: 2rem;
|
||||
right: 2rem;
|
||||
width: 2.5rem;
|
||||
height: 2.5rem;
|
||||
border-radius: 0.25rem;
|
||||
border: 1px solid var(--sl-color-divider);
|
||||
background-color: var(--sl-color-bg-surface);
|
||||
color: var(--sl-color-text-secondary);
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.15s ease, opacity 0.5s ease;
|
||||
z-index: 100;
|
||||
appearance: none;
|
||||
opacity: 1;
|
||||
|
||||
&:active {
|
||||
transform: translateY(1px);
|
||||
}
|
||||
|
||||
svg {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue