aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTulir Asokan <tulir@maunium.net>2020-09-05 14:34:43 +0300
committerTulir Asokan <tulir@maunium.net>2020-09-05 14:34:43 +0300
commitd698f058b51597a419910cb70b72495f8328c817 (patch)
treef52835e77410599fbfa36a50473341563fa1a6a5
parent9a06d63ee9459402ec8a19bd9c22f81d692cf2e5 (diff)
Make scrolling less hacky
-rw-r--r--web/index.css50
-rw-r--r--web/index.js97
-rw-r--r--web/index.sass67
3 files changed, 130 insertions, 84 deletions
diff --git a/web/index.css b/web/index.css
index 1a5b589..df7d367 100644
--- a/web/index.css
+++ b/web/index.css
@@ -1,48 +1,58 @@
* {
font-family: sans-serif; }
-html {
- scrollbar-width: none; }
- html::-webkit-scrollbar {
- display: none; }
-
body {
margin: 0; }
h1 {
font-size: 1rem; }
-main.spinner, main.error, main.empty {
+main.spinner {
+ margin-top: 5rem; }
+
+main.error, main.empty {
margin: 2rem; }
main.empty {
text-align: center; }
-nav {
- display: flex;
- overflow-x: auto;
- scrollbar-width: none;
+main.has-content {
position: fixed;
top: 0;
left: 0;
right: 0;
- height: 12vw;
- background-color: white;
- z-index: 10; }
- nav::-webkit-scrollbar {
+ bottom: 0;
+ display: grid;
+ grid-template-rows: calc(12vw + 2px) auto; }
+
+nav {
+ display: flex;
+ overflow-x: auto;
+ height: calc(12vw + 2px);
+ background-color: white; }
+ nav > a {
+ border-bottom: 2px solid transparent; }
+ nav > a.visible {
+ border-bottom-color: green; }
+ nav > a > div.sticker {
+ width: 12vw;
+ height: 12vw; }
+
+div.pack-list, nav {
+ scrollbar-width: none; }
+ div.pack-list::-webkit-scrollbar, nav::-webkit-scrollbar {
display: none; }
- nav div.sticker {
- width: 12vw;
- height: 12vw; }
+
+div.pack-list {
+ overflow-y: auto; }
section.stickerpack {
- padding-top: 12vw;
- margin-top: -12vw; }
+ margin-top: .75rem; }
section.stickerpack > div.sticker-list {
display: flex;
flex-wrap: wrap; }
section.stickerpack > h1 {
- margin: .75rem; }
+ margin: 0 0 0 .75rem; }
div.sticker {
display: flex;
diff --git a/web/index.js b/web/index.js
index bc478af..dbd5e5c 100644
--- a/web/index.js
+++ b/web/index.js
@@ -23,23 +23,10 @@ class App extends Component {
loading: true,
error: null,
}
- this.observer = null
+ this.imageObserver = null
this.packListRef = null
}
- observeIntersection = intersections => {
- for (const entry of intersections) {
- const img = entry.target.children.item(0)
- if (entry.isIntersecting) {
- img.setAttribute("src", img.getAttribute("data-src"))
- img.classList.add("visible")
- } else {
- img.removeAttribute("src")
- img.classList.remove("visible")
- }
- }
- }
-
componentDidMount() {
fetch(`${PACKS_BASE_URL}/index.json`).then(async indexRes => {
if (indexRes.status >= 400) {
@@ -61,20 +48,50 @@ class App extends Component {
})
}
}, error => this.setState({ loading: false, error }))
- this.observer = new IntersectionObserver(this.observeIntersection, {
+
+ this.imageObserver = new IntersectionObserver(this.observeImageIntersection, {
rootMargin: "100px",
- threshold: 0,
})
+ this.sectionObserver = new IntersectionObserver(this.observeSectionIntersection, {})
+ }
+
+ observeImageIntersection = intersections => {
+ for (const entry of intersections) {
+ const img = entry.target.children.item(0)
+ if (entry.isIntersecting) {
+ img.setAttribute("src", img.getAttribute("data-src"))
+ img.classList.add("visible")
+ } else {
+ img.removeAttribute("src")
+ img.classList.remove("visible")
+ }
+ }
+ }
+
+ observeSectionIntersection = intersections => {
+ for (const entry of intersections) {
+ const packID = entry.target.getAttribute("data-pack-id")
+ const navElement = document.getElementById(`nav-${packID}`)
+ if (entry.isIntersecting) {
+ navElement.classList.add("visible")
+ } else {
+ navElement.classList.remove("visible")
+ }
+ }
}
componentDidUpdate() {
for (const elem of this.packListRef.getElementsByClassName("sticker")) {
- this.observer.observe(elem)
+ this.imageObserver.observe(elem)
+ }
+ for (const elem of this.packListRef.children) {
+ this.sectionObserver.observe(elem)
}
}
componentWillUnmount() {
- this.observer.disconnect()
+ this.imageObserver.disconnect()
+ this.sectionObserver.disconnect()
}
render() {
@@ -86,9 +103,9 @@ class App extends Component {
<p>${this.state.error}</p>
</main>`
} else if (this.state.packs.length === 0) {
- return html`<main class="empty"><h1>No packs found :(</h1></main>`
+ return html`<main class="empty"><h1>No packs found 😿</h1></main>`
}
- return html`<main>
+ return html`<main class="has-content">
<nav>
${this.state.packs.map(pack => html`<${NavBarItem} id=${pack.id} pack=${pack}/>`)}
</nav>
@@ -99,24 +116,30 @@ class App extends Component {
}
}
-const NavBarItem = ({ pack }) => html`<a href="#pack-${pack.id}" title=${pack.title}>
- <div class="sticker">
- <img src=${makeThumbnailURL(pack.stickers[0].url)}
- alt=${pack.stickers[0].body} class="visible" />
- </div>
-</a>`
+const NavBarItem = ({ pack }) => html`
+ <a href="#pack-${pack.id}" id="nav-${pack.id}" data-pack-id=${pack.id} title=${pack.title}>
+ <div class="sticker">
+ <img src=${makeThumbnailURL(pack.stickers[0].url)}
+ alt=${pack.stickers[0].body} class="visible" />
+ </div>
+ </a>
+`
-const Pack = ({ pack }) => html`<section class="stickerpack" id=${`pack-${pack.id}`}>
- <h1>${pack.title}</h1>
- <div class="sticker-list">
- ${pack.stickers.map(sticker => html`
- <${Sticker} key=${sticker["net.maunium.telegram.sticker"].id} content=${sticker}/>
- `)}
- </div>
-</section>`
+const Pack = ({ pack }) => html`
+ <section class="stickerpack" id="pack-${pack.id}" data-pack-id=${pack.id}>
+ <h1>${pack.title}</h1>
+ <div class="sticker-list">
+ ${pack.stickers.map(sticker => html`
+ <${Sticker} key=${sticker["net.maunium.telegram.sticker"].id} content=${sticker}/>
+ `)}
+ </div>
+ </section>
+`
-const Sticker = ({ content }) => html`<div class="sticker" onClick=${() => sendSticker(content)}>
- <img data-src=${makeThumbnailURL(content.url)} alt=${content.body} />
-</div>`
+const Sticker = ({ content }) => html`
+ <div class="sticker" onClick=${() => sendSticker(content)}>
+ <img data-src=${makeThumbnailURL(content.url)} alt=${content.body} />
+ </div>
+`
render(html`<${App} />`, document.body)
diff --git a/web/index.sass b/web/index.sass
index fe73eb8..300c0c0 100644
--- a/web/index.sass
+++ b/web/index.sass
@@ -7,67 +7,80 @@
*
font-family: sans-serif
-html
- scrollbar-width: none
-
- &::-webkit-scrollbar
- display: none
-
body
margin: 0
h1
font-size: 1rem
+$sticker-size: 25vw
+$nav-sticker-size: 12vw
+$nav-bottom-highlight: 2px
+$nav-height: calc(#{$nav-sticker-size} + #{$nav-bottom-highlight})
+$nav-height-inverse: calc(-#{$nav-sticker-size} - #{$nav-bottom-highlight})
+
main
- &.spinner, &.error, &.empty
+ &.spinner
+ margin-top: 5rem
+
+ &.error, &.empty
margin: 2rem
&.empty
text-align: center
+ &.has-content
+ position: fixed
+ top: 0
+ left: 0
+ right: 0
+ bottom: 0
+
+ display: grid
+ grid-template-rows: $nav-height auto
+
nav
display: flex
overflow-x: auto
+
+ height: $nav-height
+
+ background-color: white
+
+ > a
+ border-bottom: $nav-bottom-highlight solid transparent
+ &.visible
+ border-bottom-color: green
+ > div.sticker
+ width: $nav-sticker-size
+ height: $nav-sticker-size
+
+div.pack-list, nav
scrollbar-width: none
&::-webkit-scrollbar
display: none
- position: fixed
- top: 0
- left: 0
- right: 0
- height: 12vw
-
- background-color: white
- z-index: 10
-
- div.sticker
- width: 12vw
- height: 12vw
+div.pack-list
+ overflow-y: auto
section.stickerpack
- // This is a slightly hacky hack so that we can simultaneously have:
- // * Anchor URLs scroll so the header is visible
- // * The scroll area is the whole document
- padding-top: 12vw
- margin-top: -12vw
+ margin-top: .75rem
> div.sticker-list
display: flex
flex-wrap: wrap
> h1
- margin: .75rem
+ margin: 0 0 0 .75rem
div.sticker
display: flex
padding: 4px
cursor: pointer
position: relative
- width: 25vw
- height: 25vw
+ width: $sticker-size
+ height: $sticker-size
box-sizing: border-box
&:hover
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage