mirror of
https://github.com/sst/opencode.git
synced 2025-08-04 05:28:16 +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,
|
IconMagnifyingGlass,
|
||||||
IconWrenchScrewdriver,
|
IconWrenchScrewdriver,
|
||||||
IconDocumentMagnifyingGlass,
|
IconDocumentMagnifyingGlass,
|
||||||
|
IconArrowDown,
|
||||||
} from "./icons"
|
} from "./icons"
|
||||||
import DiffView from "./DiffView"
|
import DiffView from "./DiffView"
|
||||||
import CodeBlock from "./CodeBlock"
|
import CodeBlock from "./CodeBlock"
|
||||||
|
@ -594,12 +595,17 @@ export default function Share(props: {
|
||||||
info: Session.Info
|
info: Session.Info
|
||||||
messages: Record<string, Message.Info>
|
messages: Record<string, Message.Info>
|
||||||
}) {
|
}) {
|
||||||
|
let lastScrollY = 0
|
||||||
let hasScrolled = false
|
let hasScrolled = false
|
||||||
|
let scrollTimeout: number | undefined
|
||||||
|
|
||||||
const id = props.id
|
const id = props.id
|
||||||
const params = new URLSearchParams(window.location.search)
|
const params = new URLSearchParams(window.location.search)
|
||||||
const debug = params.get("debug") === "true"
|
const debug = params.get("debug") === "true"
|
||||||
|
|
||||||
|
const [showScrollButton, setShowScrollButton] = createSignal(false)
|
||||||
|
const [isButtonHovered, setIsButtonHovered] = createSignal(false)
|
||||||
|
|
||||||
const anchorId = createMemo<string | null>(() => {
|
const anchorId = createMemo<string | null>(() => {
|
||||||
const raw = window.location.hash.slice(1)
|
const raw = window.location.hash.slice(1)
|
||||||
const [id] = raw.split("-")
|
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 data = createMemo(() => {
|
||||||
const result = {
|
const result = {
|
||||||
rootDir: undefined as string | undefined,
|
rootDir: undefined as string | undefined,
|
||||||
|
@ -825,6 +879,7 @@ export default function Share(props: {
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1902,6 +1957,36 @@ export default function Share(props: {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</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>
|
</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