├── .gitignore ├── README.md ├── astro.config.mjs ├── package-lock.json ├── package.json ├── postcss.config.js ├── public ├── favicon.svg ├── snapChanged-twitter.mov └── snapChanging-pogo.mov └── src ├── pages └── index.astro ├── scripts ├── chat.js ├── in-view.js ├── index.js ├── infinite-scroll.js ├── pull-to-refresh.js ├── snapped.smart.js ├── snapto.js ├── stories.js └── tabs.js ├── slyds ├── advanced │ ├── DevTools.astro │ ├── HorizontalNested.astro │ ├── HorizontalSingle.astro │ ├── IntersectionObserver.astro │ ├── IntersectionObserverInView.astro │ ├── OverscrollBehavior.astro │ ├── RecapScrollItem.astro │ ├── RecapScrollport.astro │ ├── ScrollIntoView.astro │ ├── ScrollMargin.astro │ ├── ScrollPadding.astro │ ├── SnapAfterLayout.astro │ ├── SnapGallery.astro │ └── Title.astro ├── basics │ ├── Horizontal.astro │ ├── Matrix.astro │ ├── MatrixStop.astro │ ├── Syntax.astro │ ├── Title.astro │ ├── Vertical.astro │ └── VerticalStop.astro ├── explainers │ ├── ScrollStart.astro │ ├── SnapChanged.astro │ ├── SnapChanging.astro │ ├── SnapDraft.astro │ ├── SnapExplainers.astro │ ├── SnapTarget.astro │ ├── SnapTo.astro │ └── Title.astro ├── review │ ├── Clipping.astro │ ├── Glossary.astro │ ├── Horizontal.astro │ ├── Logical.astro │ ├── Title.astro │ ├── Vertical.astro │ └── XandY.astro └── tricks │ ├── 3DPerspective.astro │ ├── AutoForward.astro │ ├── Chat.astro │ ├── DateTimePicker.astro │ ├── InfiniteScroll.astro │ ├── OverscrollEffect.astro │ ├── PullToRefresh.astro │ ├── QuantityResponsive.astro │ ├── SMART.astro │ ├── ScrollLinked.astro │ ├── ScrollStart.astro │ ├── SlydStarter.astro │ ├── StarterKit.astro │ ├── StarterKitSticky.astro │ ├── Stories.astro │ ├── SwipeUI.astro │ ├── Tabs.astro │ ├── TapToSnap.astro │ └── Title.astro ├── styles ├── components │ ├── code-gallery.css │ ├── demo-stage.css │ └── slyd-scrollport.css ├── custom.prism.css ├── index.css ├── slyd.overrides.css ├── tricks │ ├── auto-forward.css │ ├── chat.css │ ├── date-time-picker.css │ ├── in-view.css │ ├── infinite-scroll.css │ ├── nested-slyds-demo.css │ ├── overscroll.css │ ├── perspective-starter-kit.css │ ├── pull-to-refresh.css │ ├── scroll-linked-tabs.css │ ├── scroll-start.css │ ├── slides-starter-kit.css │ ├── smart.css │ ├── sticky-slide-starter-kit.css │ ├── stories.css │ ├── swipe-ui.css │ └── tap-to-snap.css └── utilities.css └── utils └── Prism.astro /.gitignore: -------------------------------------------------------------------------------- 1 | # build output 2 | dist/ 3 | .output/ 4 | 5 | # dependencies 6 | node_modules/ 7 | 8 | # logs 9 | npm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | pnpm-debug.log* 13 | 14 | 15 | # environment variables 16 | .env 17 | .env.production 18 | 19 | # macOS-specific files 20 | .DS_Store 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Welcome to [Astro](https://astro.build) 2 | 3 | [![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/astro/tree/latest/examples/starter) 4 | 5 | > 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun! 6 | 7 | ## 🚀 Project Structure 8 | 9 | Inside of your Astro project, you'll see the following folders and files: 10 | 11 | ``` 12 | / 13 | ├── public/ 14 | │ └── favicon.ico 15 | ├── src/ 16 | │ ├── components/ 17 | │ │ └── Layout.astro 18 | │ └── pages/ 19 | │ └── index.astro 20 | └── package.json 21 | ``` 22 | 23 | Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name. 24 | 25 | There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components or layouts. 26 | 27 | Any static assets, like images, can be placed in the `public/` directory. 28 | 29 | ## 🧞 Commands 30 | 31 | All commands are run from the root of the project, from a terminal: 32 | 33 | | Command | Action | 34 | | :---------------- | :------------------------------------------- | 35 | | `npm install` | Installs dependencies | 36 | | `npm run dev` | Starts local dev server at `localhost:3000` | 37 | | `npm run build` | Build your production site to `./dist/` | 38 | | `npm run preview` | Preview your build locally, before deploying | 39 | 40 | ## 👀 Want to learn more? 41 | 42 | Feel free to check [our documentation](https://github.com/withastro/astro) or jump into our [Discord server](https://astro.build/chat). 43 | -------------------------------------------------------------------------------- /astro.config.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'astro/config'; 2 | 3 | // https://astro.build/config 4 | export default defineConfig({}); 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "CSS Day - 2022", 3 | "version": "1.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "astro dev", 7 | "start": "astro dev", 8 | "build": "astro build", 9 | "preview": "astro preview" 10 | }, 11 | "devDependencies": { 12 | "astro": "^1.0.0-beta.20", 13 | "postcss-jit-props": "^1.0.6", 14 | "postcss-preset-env": "^7.5.0", 15 | "prismjs": "^1.28.0" 16 | }, 17 | "dependencies": { 18 | "open-props": "^1.3.16", 19 | "slyd": "^0.1.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | const postcssPresetEnv = require('postcss-preset-env') 2 | const postcssJitProps = require('postcss-jit-props') 3 | const OpenProps = require('open-props') 4 | 5 | module.exports = { 6 | plugins: [ 7 | postcssJitProps(OpenProps), 8 | postcssPresetEnv({ 9 | stage: 0, 10 | autoprefixer: false, 11 | features: { 12 | 'logical-properties-and-values': false, 13 | 'prefers-color-scheme-query': false, 14 | 'gap-properties': false, 15 | 'custom-properties': false, 16 | 'place-properties': false, 17 | 'not-pseudo-class': false, 18 | 'focus-visible-pseudo-class': false, 19 | 'focus-within-pseudo-class': false, 20 | 'color-functional-notation': false 21 | } 22 | }), 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /public/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /public/snapChanged-twitter.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/argyleink/2022-css-day_oh-snap/2afc1e0d54ac4e578e519cefa5257b857ad16060/public/snapChanged-twitter.mov -------------------------------------------------------------------------------- /public/snapChanging-pogo.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/argyleink/2022-css-day_oh-snap/2afc1e0d54ac4e578e519cefa5257b857ad16060/public/snapChanging-pogo.mov -------------------------------------------------------------------------------- /src/pages/index.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import OverflowTitle from '../slyds/review/Title.astro' 3 | import ClippingOverflow from '../slyds/review/Clipping.astro' 4 | import HorizontalOverflow from '../slyds/review/Horizontal.astro' 5 | import VerticalOverflow from '../slyds/review/Vertical.astro' 6 | import LogicalOverflow from '../slyds/review/Logical.astro' 7 | import XandY from '../slyds/review/XandY.astro' 8 | import Glossary from '../slyds/review/Glossary.astro' 9 | 10 | import BasicsTitle from '../slyds/basics/Title.astro' 11 | import Syntax from '../slyds/basics/Syntax.astro' 12 | import BasicHorizontal from '../slyds/basics/Horizontal.astro' 13 | import BasicVertical from '../slyds/basics/Vertical.astro' 14 | import StopVertical from '../slyds/basics/VerticalStop.astro' 15 | import Matrix from '../slyds/basics/Matrix.astro' 16 | import StopMatrix from '../slyds/basics/MatrixStop.astro' 17 | 18 | import AdvancedSnap from '../slyds/advanced/Title.astro' 19 | import DevTools from '../slyds/advanced/DevTools.astro' 20 | import SingleHorizontal from '../slyds/advanced/HorizontalSingle.astro' 21 | import NestedHorizontal from '../slyds/advanced/HorizontalNested.astro' 22 | import OverscrollBehavior from '../slyds/advanced/OverscrollBehavior.astro' 23 | import ScrollPadding from '../slyds/advanced/ScrollPadding.astro' 24 | import ScrollMargin from '../slyds/advanced/ScrollMargin.astro' 25 | import ScrollIntoView from '../slyds/advanced/ScrollIntoView.astro' 26 | import SnapAfterLayout from '../slyds/advanced/SnapAfterLayout.astro' 27 | import IntersectionObserver from '../slyds/advanced/IntersectionObserver.astro' 28 | import IntersectionObserverInView from '../slyds/advanced/IntersectionObserverInView.astro' 29 | import DevTools from '../slyds/advanced/DevTools.astro' 30 | import SnapGallery from '../slyds/advanced/SnapGallery.astro' 31 | import RecapScrollport from '../slyds/advanced/RecapScrollport.astro' 32 | import RecapScrollItem from '../slyds/advanced/RecapScrollItem.astro' 33 | 34 | import SnapTricks from '../slyds/tricks/Title.astro' 35 | import Perspective from '../slyds/tricks/3DPerspective.astro' 36 | import AutoForward from '../slyds/tricks/AutoForward.astro' 37 | import Chat from '../slyds/tricks/Chat.astro' 38 | import DateTimePicker from '../slyds/tricks/DateTimePicker.astro' 39 | import InfiniteScroll from '../slyds/tricks/InfiniteScroll.astro' 40 | import OverscrollEffect from '../slyds/tricks/OverscrollEffect.astro' 41 | import PullToRefresh from '../slyds/tricks/PullToRefresh.astro' 42 | import QuantityResponsive from '../slyds/tricks/QuantityResponsive.astro' 43 | import ScrollLinked from '../slyds/tricks/ScrollLinked.astro' 44 | import ScrollStartTrick from '../slyds/tricks/ScrollStart.astro' 45 | import SlydStarter from '../slyds/tricks/SlydStarter.astro' 46 | import Smart from '../slyds/tricks/SMART.astro' 47 | import StarterKit from '../slyds/tricks/StarterKit.astro' 48 | import StarterKitSticky from '../slyds/tricks/StarterKitSticky.astro' 49 | import Stories from '../slyds/tricks/Stories.astro' 50 | import SwipeUI from '../slyds/tricks/SwipeUI.astro' 51 | import Tabs from '../slyds/tricks/Tabs.astro' 52 | import TapToSnap from '../slyds/tricks/TapToSnap.astro' 53 | 54 | import SnapNext from '../slyds/explainers/Title.astro' 55 | import SnapExplainers from '../slyds/explainers/SnapExplainers.astro' 56 | import SnapDraft from '../slyds/explainers/SnapDraft.astro' 57 | import SnapTarget from '../slyds/explainers/SnapTarget.astro' 58 | import ScrollStart from '../slyds/explainers/ScrollStart.astro' 59 | import SnapChanging from '../slyds/explainers/SnapChanging.astro' 60 | import SnapChanged from '../slyds/explainers/SnapChanged.astro' 61 | import SnapTo from '../slyds/explainers/SnapTo.astro' 62 | --- 63 | 64 | 68 | 69 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | CSS Day 2022 85 | 86 | 87 | 88 | 89 | 90 |

oh snap!

91 |

That Scroll Control

92 |
93 |
94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 |

Holy Snap

168 |

🤯 scroll 🤯

169 |
170 | 171 | 172 |

Review The Slides

173 | oh-snap.netlify.app 174 |
175 | 176 | 177 |

Thank You

178 |
179 |
180 | 181 |
182 | 183 | 184 | -------------------------------------------------------------------------------- /src/scripts/chat.js: -------------------------------------------------------------------------------- 1 | const bot = document.querySelector('#bot-text') 2 | const author = document.querySelector('.chat-authoring') 3 | const scrollview = document.querySelector('.chat-scrollview') 4 | const messagelist = document.querySelector('.chat-messagelist') 5 | const bot_template = message => ` 6 |
7 |
8 | 9 |
10 |
11 |

Snap Bot

12 |
${message}
13 |
14 |
15 | ` 16 | 17 | const user_template = message => ` 18 |
19 |
20 |
${message}
21 |
22 |
23 | ` 24 | 25 | scrollview.scrollTop = scrollview.scrollHeight 26 | 27 | bot.addEventListener('keypress', e => { 28 | const {keyCode} = e 29 | 30 | if (keyCode === 13) { 31 | e.preventDefault() 32 | 33 | if (!messagelist.querySelector('.chat-cluster:last-child').hasAttribute('mine')) { 34 | messagelist.querySelector('.chat-cluster:last-child > section').innerHTML += `
${bot.value}
` 35 | } 36 | else { 37 | messagelist.innerHTML += bot_template(bot.value) 38 | } 39 | 40 | bot.value = '' 41 | } 42 | }) 43 | 44 | author.addEventListener('keypress', e => { 45 | const {keyCode} = e 46 | 47 | if (keyCode === 13) { 48 | e.preventDefault() 49 | 50 | if (messagelist.querySelector('.chat-cluster:last-child').hasAttribute('mine')) { 51 | messagelist.querySelector('.chat-cluster:last-child > section').innerHTML += `
${author.innerHTML}
` 52 | } 53 | else { 54 | messagelist.innerHTML += user_template(author.innerHTML) 55 | } 56 | 57 | author.innerHTML = '' 58 | } 59 | }) -------------------------------------------------------------------------------- /src/scripts/in-view.js: -------------------------------------------------------------------------------- 1 | let ioCallback = nodes => { 2 | for (let node of nodes) 3 | node.target.classList 4 | .toggle('in-view', node.isIntersecting) 5 | } 6 | 7 | const observeInView = scrollport => { 8 | const scrollitems = scrollport.querySelectorAll(':scope > div') 9 | 10 | const io = new IntersectionObserver(ioCallback, { 11 | root: scrollport, 12 | }) 13 | 14 | for (let item of scrollitems) 15 | io.observe(item) 16 | } 17 | 18 | Array.from(document.querySelectorAll('.observe-in-view')) 19 | .forEach(scrollport => { 20 | observeInView(scrollport) 21 | }) -------------------------------------------------------------------------------- /src/scripts/index.js: -------------------------------------------------------------------------------- 1 | import 'https://argyleink.github.io/scroll-timeline/dist/scroll-timeline.js' 2 | 3 | import "./infinite-scroll.js" 4 | import "./in-view.js" 5 | import "./snapped.smart.js" 6 | import "./pull-to-refresh.js" 7 | import "./tabs.js" 8 | import "./chat.js" 9 | import "./stories.js" 10 | import "./snapto.js" -------------------------------------------------------------------------------- /src/scripts/infinite-scroll.js: -------------------------------------------------------------------------------- 1 | const scrollport = document.querySelector('.infinite-scroll') 2 | const scrollitems = document.querySelectorAll('.infinite-scroll > div') 3 | 4 | const io = new IntersectionObserver(nodes => { 5 | const [active] = nodes.filter(node => node.isIntersecting) 6 | 7 | if (active && active.target === active.target.parentElement.lastElementChild) { 8 | active.target.parentElement.firstElementChild.scrollIntoView() 9 | } 10 | }, { 11 | root: scrollport, 12 | rootMargin: '1px', 13 | threshold: 1, 14 | }) 15 | 16 | Array.from(scrollitems) 17 | .forEach(node => 18 | io.observe(node)) -------------------------------------------------------------------------------- /src/scripts/pull-to-refresh.js: -------------------------------------------------------------------------------- 1 | const ptr_scrollport = document.querySelector('.pull-to-refresh') 2 | const ptr = document.querySelector('#refresh') 3 | const main = document.querySelector('#refresh-main') 4 | 5 | const determinePTR = event => { 6 | if (event.target.scrollTop === 0) { 7 | // fetch() 8 | ptr.querySelector('span').textContent = 'refreshing...' 9 | ptr.setAttribute('loading-state', 'loading') 10 | 11 | // sim response 12 | setTimeout(() => { 13 | ptr.querySelector('span').textContent = 'Pull to refresh' 14 | ptr.removeAttribute('loading-state') 15 | main.scrollIntoView({ behavior: 'smooth', block: "nearest" }) 16 | // todo: on scroll complete, set text 17 | }, 2000) 18 | } 19 | } 20 | 21 | ptr_scrollport.addEventListener('scroll', e => { 22 | clearTimeout(ptr_scrollport.scrollEndTimer) 23 | ptr_scrollport.scrollEndTimer = setTimeout(() => { 24 | determinePTR(e) 25 | }, 100) 26 | }) 27 | 28 | const ptr_timeline = new ScrollTimeline({ 29 | scrollSource: ptr_scrollport, 30 | orientation: 'block', 31 | fill: 'both', 32 | startScrollOffset: { 33 | target: ptr, 34 | edge: 'start', 35 | threshold: 1 36 | }, 37 | endScrollOffset: { 38 | target: ptr, 39 | edge: 'start', 40 | threshold: .8 41 | }, 42 | }) 43 | 44 | document.querySelector('#refresh > svg').animate( 45 | { 46 | transform: ['rotateZ(0)', 'rotateZ(.5turn)'], 47 | }, 48 | { 49 | duration: 1000, 50 | fill: 'both', 51 | timeline: ptr_timeline 52 | } 53 | ) 54 | 55 | document.querySelector('#refresh > span').animate( 56 | { 57 | opacity: ['1', '0'], 58 | }, 59 | { 60 | duration: 1000, 61 | fill: 'both', 62 | timeline: ptr_timeline 63 | } 64 | ) -------------------------------------------------------------------------------- /src/scripts/snapped.smart.js: -------------------------------------------------------------------------------- 1 | const snapcontainer = document.querySelector('#smart-container') 2 | 3 | let last_scroll = 0 4 | 5 | function determineSnapped(e) { 6 | if (!e || e?.target.scrollLeft === last_scroll) return 7 | last_scroll = e.target.scrollLeft 8 | 9 | let viewportwidth = window.innerWidth 10 | snapcontainer.style.gap = '100vw' 11 | snapcontainer.getBoundingClientRect() 12 | 13 | Array.from(snapcontainer.children).forEach(child => { 14 | let {left} = child.getBoundingClientRect() 15 | child.classList.toggle('snapped', left > 0 && left < viewportwidth) 16 | }) 17 | 18 | snapcontainer.style.gap = null 19 | } 20 | 21 | snapcontainer.addEventListener('scroll', e => { 22 | clearTimeout(snapcontainer.scrollEndTimer) 23 | snapcontainer.scrollEndTimer = setTimeout(() => { 24 | determineSnapped(e) 25 | }, 100) 26 | }) -------------------------------------------------------------------------------- /src/scripts/snapto.js: -------------------------------------------------------------------------------- 1 | let i = 1 2 | 3 | document.querySelector('#snap-to-next').addEventListener('click', e => { 4 | e.target.parentElement.parentElement 5 | .querySelector(`slyd-scrollport > div:nth-child(${++i})`) 6 | .scrollIntoView({behavior: 'smooth', inline: 'center'}) 7 | }) 8 | 9 | document.querySelector('#snap-to-prev').addEventListener('click', e => { 10 | e.target.parentElement.parentElement 11 | .querySelector(`slyd-scrollport > div:nth-child(${--i})`) 12 | .scrollIntoView({behavior: 'smooth', inline: 'center'}) 13 | }) -------------------------------------------------------------------------------- /src/scripts/stories.js: -------------------------------------------------------------------------------- 1 | const stories = document.querySelector('.stories') 2 | const median = stories.offsetLeft + (stories.clientWidth / 2) 3 | 4 | const state = { 5 | current_story: stories.firstElementChild.lastElementChild 6 | } 7 | 8 | const navigateStories = direction => { 9 | const story = state.current_story 10 | const lastItemInUserStory = story.parentNode.firstElementChild 11 | const firstItemInUserStory = story.parentNode.lastElementChild 12 | const hasNextUserStory = story.parentElement.nextElementSibling 13 | const hasPrevUserStory = story.parentElement.previousElementSibling 14 | 15 | if (direction === 'next') { 16 | if (lastItemInUserStory === story && !hasNextUserStory) 17 | return 18 | else if (lastItemInUserStory === story && hasNextUserStory) { 19 | state.current_story = story.parentElement.nextElementSibling.lastElementChild 20 | story.parentElement.nextElementSibling.scrollIntoView({ 21 | behavior: 'smooth' 22 | }) 23 | } 24 | else { 25 | story.classList.add('seen') 26 | state.current_story = story.previousElementSibling 27 | } 28 | } 29 | else if(direction === 'prev') { 30 | if (firstItemInUserStory === story && !hasPrevUserStory) 31 | return 32 | else if (firstItemInUserStory === story && hasPrevUserStory) { 33 | state.current_story = story.parentElement.previousElementSibling.firstElementChild 34 | story.parentElement.previousElementSibling.scrollIntoView({ 35 | behavior: 'smooth' 36 | }) 37 | } 38 | else { 39 | story.nextElementSibling.classList.remove('seen') 40 | state.current_story = story.nextElementSibling 41 | } 42 | } 43 | } 44 | 45 | stories.addEventListener('click', e => { 46 | if (e.target.nodeName !== 'ARTICLE') 47 | return 48 | 49 | navigateStories( 50 | e.clientX > median 51 | ? 'next' 52 | : 'prev') 53 | }) 54 | 55 | // left & right are free with snap points 👍 56 | document.addEventListener('keydown', ({key}) => { 57 | if (key !== 'ArrowDown' || key !== 'ArrowUp') 58 | navigateStories( 59 | key === 'ArrowDown' 60 | ? 'next' 61 | : 'prev') 62 | }) -------------------------------------------------------------------------------- /src/scripts/tabs.js: -------------------------------------------------------------------------------- 1 | const tabgroup = document.querySelector('.tabs') 2 | const tabsection = document.querySelector('.tabs > section') 3 | const tabnav = document.querySelector('.tabs > nav') 4 | const tabnavitems = document.querySelectorAll('.tabs > nav a') 5 | const tabindicator = document.querySelector('.tabs .indicator') 6 | 7 | tabindicator.animate( 8 | { 9 | transform: [...tabnavitems].map(item => 10 | `translateX(${item.offsetLeft}px)`), 11 | width: [...tabnavitems].map(item => 12 | `${item.offsetWidth}px`), 13 | }, 14 | { 15 | duration: 1000, 16 | fill: 'both', 17 | timeline: new ScrollTimeline({ 18 | scrollSource: tabsection, 19 | orientation: 'inline', 20 | fill: 'both', 21 | }) 22 | } 23 | ) 24 | 25 | const setActiveTab = tabbtn => { 26 | document 27 | .querySelector('.tabs a[active]') 28 | .removeAttribute('active') 29 | 30 | tabbtn.setAttribute('active', '') 31 | tabbtn.scrollIntoView() 32 | } 33 | 34 | const determineActiveTabSection = () => { 35 | const i = tabsection.scrollLeft / tabsection.clientWidth 36 | const matchingNavItem = tabnavitems[i] 37 | matchingNavItem && setActiveTab(matchingNavItem) 38 | } 39 | 40 | tabnav.addEventListener('click', e => { 41 | if (e.target.nodeName !== "A") return 42 | setActiveTab(e.target) 43 | }) 44 | 45 | tabsection.addEventListener('scroll', () => { 46 | clearTimeout(tabsection.scrollEndTimer) 47 | tabsection.scrollEndTimer = setTimeout(determineActiveTabSection, 100) 48 | }) -------------------------------------------------------------------------------- /src/slyds/advanced/DevTools.astro: -------------------------------------------------------------------------------- 1 | 2 |

Chrome DevTools

3 |

Elements > "scroll-snap" badge

4 |
-------------------------------------------------------------------------------- /src/slyds/advanced/HorizontalNested.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

Indirect Snap

7 | 8 | .some > .nested > .child { 13 | scroll-snap-align: center; 14 | } 15 | } 16 | `}/> 17 | 18 | {[...Array(10)].map(() => ( 19 |
20 | 🤘💀 21 |
22 | ))} 23 |
24 |
25 |
-------------------------------------------------------------------------------- /src/slyds/advanced/HorizontalSingle.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

Single Snap

7 | 8 | :nth-child(5) { 13 | scroll-snap-align: center; 14 | } 15 | } 16 | `}/> 17 | 18 | {[...Array(10)].map(() => ( 19 |
20 | ))} 21 |
22 |
23 |
-------------------------------------------------------------------------------- /src/slyds/advanced/IntersectionObserver.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

Intersection Observer

7 | { 9 | // filter based on intersection/bounds/etc 10 | } 11 | 12 | let io = new IntersectionObserver(ioCallback, { 13 | root: scrollport, 14 | }) 15 | 16 | for (let item of scrollitems) 17 | io.observe(item) 18 | `}/> 19 |
-------------------------------------------------------------------------------- /src/slyds/advanced/IntersectionObserverInView.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

In View‽

7 | 8 | { 10 | for (let node of nodes) 11 | node.target.classList 12 | .toggle('in-view', 13 | node.isIntersecting) 14 | } 15 | `}/> 16 | 17 | {[...Array(10)].map(() => ( 18 |
19 | ))} 20 |
21 |
22 |
-------------------------------------------------------------------------------- /src/slyds/advanced/OverscrollBehavior.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

Trapping Scroll

7 | 8 | 9 | 17 |
18 |
19 |
Contained
20 | 21 | {[...Array(5)].map(() => ( 22 |
23 | ))} 24 |
25 |
26 |
27 |
Default
28 | 29 | {[...Array(5)].map(() => ( 30 |
31 | ))} 32 |
33 |
34 |
35 |
36 |
-------------------------------------------------------------------------------- /src/slyds/advanced/RecapScrollItem.astro: -------------------------------------------------------------------------------- 1 | 2 |

A Scroll Item

3 | 8 |
-------------------------------------------------------------------------------- /src/slyds/advanced/RecapScrollport.astro: -------------------------------------------------------------------------------- 1 | 2 |

The Scrollport

3 | 9 |
-------------------------------------------------------------------------------- /src/slyds/advanced/ScrollIntoView.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

Scroll Into View

7 | 8 | 9 | 15 |
16 | 17 | {[...Array(10)].map(() => ( 18 |
19 | ))} 20 |
21 | 22 |
23 |
24 |
-------------------------------------------------------------------------------- /src/slyds/advanced/ScrollMargin.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

Scroll Margin

7 | 8 | 9 | 14 |
15 |
16 |
No margins
17 | 18 | {[...Array(10)].map(() => ( 19 |
20 | ))} 21 |
22 |
23 |
24 |
Margins
25 | 26 | {[...Array(10)].map(() => ( 27 |
28 | ))} 29 |
30 |
31 |
32 |
33 |
-------------------------------------------------------------------------------- /src/slyds/advanced/ScrollPadding.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

Scroll Padding

7 | 8 | 9 | 17 |
18 |
19 |
No padding
20 | 21 | {[...Array(10)].map(() => ( 22 |
23 | ))} 24 |
25 |
26 |
27 |
Padding
28 | 29 | {[...Array(10)].map(() => ( 30 |
31 | ))} 32 |
33 |
34 |
35 |
36 |
-------------------------------------------------------------------------------- /src/slyds/advanced/SnapAfterLayout.astro: -------------------------------------------------------------------------------- 1 | 2 |

Snap After Layout

3 | 4 |
5 | 6 | {[...Array(10)].map(() => ( 7 |
8 | ))} 9 |
10 |
11 |
-------------------------------------------------------------------------------- /src/slyds/advanced/SnapGallery.astro: -------------------------------------------------------------------------------- 1 | 2 |

Snap Gallery

3 |

https://codepen.io/collection/KpqBGW

4 |

A Codepen Collection

5 |
-------------------------------------------------------------------------------- /src/slyds/advanced/Title.astro: -------------------------------------------------------------------------------- 1 | 2 |

Scroll Snap

3 |

Advanced

4 |
-------------------------------------------------------------------------------- /src/slyds/basics/Horizontal.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

Horizontal

7 | 8 | * { 13 | scroll-snap-align: center; 14 | } 15 | } 16 | `}/> 17 | 18 | {[...Array(10)].map(() => ( 19 |
20 | ))} 21 |
22 |
23 |
24 | -------------------------------------------------------------------------------- /src/slyds/basics/Matrix.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

Matrix

7 | 8 | * { 14 | scroll-snap-align: center; 15 | } 16 | `}/> 17 | 18 | {[...Array(24)].map(() => ( 19 |
20 | ))} 21 |
22 |
23 |
-------------------------------------------------------------------------------- /src/slyds/basics/MatrixStop.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

Matrix Stops

7 | 8 | * { 14 | scroll-snap-stop: always; 15 | } 16 | `}/> 17 | 18 | {[...Array(36)].map(() => ( 19 |
20 | ))} 21 |
22 |
23 |
-------------------------------------------------------------------------------- /src/slyds/basics/Syntax.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

Syntax

7 | 17 |
18 | -------------------------------------------------------------------------------- /src/slyds/basics/Title.astro: -------------------------------------------------------------------------------- 1 | 2 |

Scroll Snap

3 |

The Basics

4 |
-------------------------------------------------------------------------------- /src/slyds/basics/Vertical.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

Vertical

7 | 8 | * { 13 | scroll-snap-align: center; 14 | } 15 | } 16 | `}/> 17 | 18 | {[...Array(10)].map(() => ( 19 |
20 | ))} 21 |
22 |
23 |
-------------------------------------------------------------------------------- /src/slyds/basics/VerticalStop.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

Snap Stop

7 | 8 | * { 10 | scroll-snap-stop: always; 11 | } 12 | `}/> 13 | 14 | {[...Array(10)].map(() => ( 15 |
16 | ))} 17 |
18 |
19 |
-------------------------------------------------------------------------------- /src/slyds/explainers/ScrollStart.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

Scroll Start

7 | 8 | 18 | 19 |
20 |
scroll-start-target
21 |
22 |
23 |
24 | Scroll Snap 2 25 |
26 | -------------------------------------------------------------------------------- /src/slyds/explainers/SnapChanged.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

snapChanged()

7 | 8 | { 10 | console.info(event) 11 | }) 12 | `}/> 13 | 14 | 15 | Scroll Snap 2 16 |
-------------------------------------------------------------------------------- /src/slyds/explainers/SnapChanging.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

snapChanging()

7 | 8 | { 10 | console.info(event) 11 | }) 12 | `}/> 13 | 14 | 15 | Scroll Snap 2 16 |
-------------------------------------------------------------------------------- /src/slyds/explainers/SnapDraft.astro: -------------------------------------------------------------------------------- 1 | 2 |

Scroll Snap 2

3 |

Draft Module

4 | https://drafts.csswg.org/css-scroll-snap-2/ 5 |
-------------------------------------------------------------------------------- /src/slyds/explainers/SnapExplainers.astro: -------------------------------------------------------------------------------- 1 | 2 |

Snap Explainers

3 | https://github.com/argyleink/ScrollSnapExplainers/ 4 |
-------------------------------------------------------------------------------- /src/slyds/explainers/SnapTarget.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

:snapped

7 | 8 | 17 | 18 |
:snapped
19 | {[...Array(10)].map(() => ( 20 |
21 | ))} 22 |
23 |
24 | Scroll Snap 2 25 |
-------------------------------------------------------------------------------- /src/slyds/explainers/SnapTo.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

snapTo()

7 | 8 | 14 |
15 | 16 | {[...Array(10)].map(() => ( 17 |
18 | ))} 19 |
20 |
21 | 22 | 23 |
24 |
25 |
26 |
-------------------------------------------------------------------------------- /src/slyds/explainers/Title.astro: -------------------------------------------------------------------------------- 1 | 2 |

Snap "next"

3 |

5 Features

4 |
-------------------------------------------------------------------------------- /src/slyds/review/Clipping.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

Clipping

7 | 8 | 13 | 14 |
15 |
16 |
17 | 18 | 19 | 24 | 25 |
26 |
27 |
28 |
-------------------------------------------------------------------------------- /src/slyds/review/Glossary.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

Glossary

7 | 8 |
9 |

Root Scroller

10 |

Top most scroller. Typically the HTML tag. Scroller promotion possible.

11 |
12 |
13 |

Implicit Scroller

14 |

A nested scroller or any scroller that's not the root scroller lol

15 |
16 |
17 |

ScrollPort

18 |

The viewport frame of a scroller

19 |
20 |
21 |

Scroll Axis

22 |

A 2D coordinate system to translate along

23 |
24 |
25 |

Scroll Behavior

26 |

From CSS or JS, control if browser scroll should be instant or animated

27 |
28 |
29 |

Overscroll Behavior

30 |

Should a nested scroller trap it's inertia or not

31 |
32 |
33 |

Overscroll Effect

34 |

UI feedback informing users they're at the beginning or end of a scroller

35 |
36 |
37 |

Scroll Hint

38 |

UI to help users see there's room to scroll

39 |
40 |
41 |
42 | -------------------------------------------------------------------------------- /src/slyds/review/Horizontal.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

Horizontal

7 | 8 | 13 | 14 | {[...Array(10)].map(() => ( 15 |
16 | ))} 17 |
18 |
19 | 20 | 21 | 27 | 28 | {[...Array(10)].map(() => ( 29 |
30 | ))} 31 |
32 |
33 |
-------------------------------------------------------------------------------- /src/slyds/review/Logical.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

Logical Axis

7 | 8 | 13 | 14 |
15 |
16 |
17 | 18 | 19 | 24 | 25 |
26 |
27 |
28 |
-------------------------------------------------------------------------------- /src/slyds/review/Title.astro: -------------------------------------------------------------------------------- 1 | 2 |

Overflow

3 |

A Review

4 |
-------------------------------------------------------------------------------- /src/slyds/review/Vertical.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

Vertical

7 | 8 | 13 | 14 | {[...Array(10)].map(() => ( 15 |
16 | ))} 17 |
18 |
19 | 20 | 21 | 27 | 28 | {[...Array(10)].map(() => ( 29 |
30 | ))} 31 |
32 |
33 |
-------------------------------------------------------------------------------- /src/slyds/review/XandY.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

Both

7 | 8 | 13 | 14 | {[...Array(12)].map(() => ( 15 |
16 | ))} 17 |
18 |
19 | 20 | 21 | 27 | 28 | {[...Array(12)].map(() => ( 29 |
30 | ))} 31 |
32 |
33 |
-------------------------------------------------------------------------------- /src/slyds/tricks/3DPerspective.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

3D Perspective

7 | 8 | p { 19 | transform: translateZ(-5px); 20 | } 21 | `}/> 22 |
23 | {[...Array(3)].map((x, i) => ( 24 |
25 |

depth {i}

26 |
27 | ))} 28 |
29 |

depth 1

30 |

depth 2

31 |

depth 3

32 |
33 |
34 |

rad 🤘💀

35 |
36 |
37 |
38 |
-------------------------------------------------------------------------------- /src/slyds/tricks/AutoForward.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |
7 |

Auto Forward

8 |

By Christian Schaefer

9 |
10 | 11 | 22 |
23 | {[...Array(3)].map((x, i) => ( 24 |
25 |
26 | slide {i} 27 |
28 | ))} 29 |
30 |
31 | Chrome Only 32 |
-------------------------------------------------------------------------------- /src/slyds/tricks/Chat.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 | 7 |
8 |

Chat

9 | 14 | 15 |
16 |
17 |
18 |
Chat UI
19 |
20 | 21 |
22 |
23 | 24 |
25 |
26 | 27 |
28 |
29 | 30 |
31 |
32 |

Snap Bot

33 |
Hi!
34 |
I'm a bot
35 |
36 |
37 | 38 |
39 |
40 |
Hi!
41 |
I'm not a bot
42 |
But I am static text that was put here by a human. The only dynamic stuff you'll find here is whatever someone types in the "say something" text area hehe.
43 |
44 |
45 | 46 |
47 |
48 | 49 |
50 |
51 |

Snap Bot

52 |
Makes sense.
53 |
I see this chat implementation is using scroll snap points?
54 |
Can you tell me more about that?
55 |
56 |
57 | 58 |
59 |
60 |
sure!
61 |
scroll-snapping got an update and this is a demo to show the feature.
62 |
On Chrome 81, all these chats automatically snap to the scroll bottom. In Chrome 80, we'd need to write custom javascript to maintain the position at the bottom.
63 |
Now CSS can do it!
64 |
65 |
66 | 67 |
68 |
69 | 70 |
71 |
72 |
73 |
-------------------------------------------------------------------------------- /src/slyds/tricks/DateTimePicker.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

Date / Time

7 | 8 | 16 |
17 | 18 | Fri 24 Jul 19 | Sat 25 Jul 20 | Sun 26 Jul 21 | Mon 27 Jul 22 | Tue 28 Jul 23 | Wed 29 Jul 24 | Thu 30 Jul 25 | Fri 1 Aug 26 | Sat 2 Aug 27 | Sun 3 Aug 28 | Mon 4 Aug 29 | Tue 5 Aug 30 | Wed 6 Aug 31 | Thu 7 Aug 32 | Fri 8 Aug 33 | Sat 9 Aug 34 | Sun 10 Aug 35 | Mon 11 Aug 36 | Tue 12 Aug 37 | Wed 13 Aug 38 | Thu 14 Aug 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 |
129 |
130 |
-------------------------------------------------------------------------------- /src/slyds/tricks/InfiniteScroll.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

Infinite Scroll

7 | 8 | { 10 | const [active] = nodes.filter(node => 11 | node.isIntersecting) 12 | ... 13 | if (active.target === parent.lastElementChild) 14 | parent.firstElementChild.scrollIntoView() 15 | }, { 16 | root: scrollPort 17 | }) 18 | `}/> 19 |
20 |
this
carousel
never
ends
this
21 |
22 |
23 |
-------------------------------------------------------------------------------- /src/slyds/tricks/OverscrollEffect.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

Overscroll Effect

7 | 8 | :not(.overscroller) { 10 | scroll-snap-align: start; 11 | } 12 | `}/> 13 |
14 |
15 | {[...Array(10)].map(() => ( 16 |
17 | ))} 18 |
19 |
20 |
21 |
-------------------------------------------------------------------------------- /src/slyds/tricks/PullToRefresh.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

Pull To Refresh

7 | 8 | 18 |
19 |
20 | 21 | 22 | 23 | Pull to refresh 24 |
25 |
26 |

Header

27 |

Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempora laborum illo autem asperiores. Numquam voluptate facilis odit impedit non autem magni architecto, placeat voluptatum dolorem nemo doloremque velit, iure id.

28 |

Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempora laborum illo autem asperiores. Numquam voluptate facilis odit impedit non autem magni architecto, placeat voluptatum dolorem nemo doloremque velit, iure id.

29 |

Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempora laborum illo autem asperiores. Numquam voluptate facilis odit impedit non autem magni architecto, placeat voluptatum dolorem nemo doloremque velit, iure id.

30 |
31 |
32 |
33 |
-------------------------------------------------------------------------------- /src/slyds/tricks/QuantityResponsive.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

Quantity Responsive

7 | 8 | 11 | 12 | {[...Array(10)].map(() => ( 13 |
14 | ))} 15 |
16 |
17 |
-------------------------------------------------------------------------------- /src/slyds/tricks/SMART.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

S.M.A.R.T.

7 | 8 | 14 | 15 | {[...Array(10)].map(() => ( 16 |
17 | ))} 18 |
19 |
20 |

Uncover which is snapped

21 |
22 | -------------------------------------------------------------------------------- /src/slyds/tricks/ScrollLinked.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 | 7 |
8 |

Scroll Linked

9 | 16 |

⚠️ syntax changing

17 |
18 |
19 |
20 | 33 |
34 |
35 |

Sit dolor

36 |

Lorem ipsum dolor sit amet consectet adipisicing elit

37 |

Lore s sdf

38 |

Lorem ipsum dolor sit amet consectet adipisicing elit

39 |

Sit molestiae itaque rem optio molestias voluptati obcaecati!

40 |

Ipsum, a? Tenetur aut a nisi, aspernatur earum eligendi id quam nihil sint quas?

41 |

nisi, aspernatur earum eligendi id quam nihil sint quas?

42 |

Sit molestiae itaque rem optio molestias voluptati obcaecati!

43 |

Ipsum, a? Tenetur aut a nisi, aspernatur earum eligendi id quam nihil sint quas?

44 |

nisi, aspernatur earum eligendi id quam nihil sint quas?

45 |
46 |
47 |

Tenetur

48 |

Lorem ipsum dolor sit amet consectet adipisicing elit. Sit molestiae itaque rem optio molestias voluptati obcaecati!

49 |

Tenet urs

50 |

Ipsum, a? Tenetur aut a nisi, aspernatur earum eligendi id quam nihil sint quas?

51 |

nisi, aspernatur earum eligendi id quam nihil sint quas?

52 |

Lore s sdf

53 |

Lorem ipsum dolor sit amet consectet adipisicing elit

54 |

Sit molestiae itaque rem optio molestias voluptati obcaecati!

55 |

Ipsum, a? Tenetur aut a nisi, aspernatur earum eligendi id quam nihil sint quas?

56 |

nisi, aspernatur earum eligendi id quam nihil sint quas?

57 |
58 |
59 |

Lorems dolor

60 |

Lorem ipsum dolor sit amet consectet adipisicing elit

61 |

Sit molestiae itaque rem optio molestias voluptati obcaecati!

62 |

nisi, aspernatur earum eligendi id quam nihil sint quas?

63 |
64 |
65 |

Lore s sdf

66 |

Lorem ipsum dolor sit amet consectet adipisicing elit

67 |
68 |
69 |
70 |
71 |
72 |
-------------------------------------------------------------------------------- /src/slyds/tricks/ScrollStart.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

Scroll Start

7 | 8 | 22 | 23 | {[...Array(10)].map(() => ( 24 |
25 | ))} 26 |
27 |
28 |
29 | -------------------------------------------------------------------------------- /src/slyds/tricks/SlydStarter.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

Slyd Starter

7 | 8 | 10 | @import "https://unpkg.com/slyd/dist/slyd.css"; 11 | 12 | 13 | 16 | `}/> 17 | 18 | 19 | Group A, Slide 1 20 | Group A, Slide 2 21 | Group A, Slide 3 22 | 23 | 24 | Group B, Slide 1 25 | Group B, Slide 2 26 | Group B, Slide 3 27 | 28 | 29 | 30 |
-------------------------------------------------------------------------------- /src/slyds/tricks/StarterKit.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

Slides Starter Kit

7 | 8 | 19 |
20 | {[...Array(10)].map((x, i) => ( 21 |
slide {i}
22 | ))} 23 |
24 |
25 |
-------------------------------------------------------------------------------- /src/slyds/tricks/StarterKitSticky.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

Sticky Starter

7 | 8 | 14 |
15 | {[...Array(10)].map((x, i) => ( 16 |
slide {i}
17 | ))} 18 |
19 |
20 |
-------------------------------------------------------------------------------- /src/slyds/tricks/Stories.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 | 7 |
8 |

Stories

9 | 20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
-------------------------------------------------------------------------------- /src/slyds/tricks/SwipeUI.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

Swipe UI

7 | 8 | 19 |
20 |
21 |
22 |
23 | 24 | 25 | 26 | archive 27 |
28 |
New Message!
29 |
30 | delete 31 | 32 | 33 | 34 |
35 |
36 |
37 |
38 | 39 | 40 | 41 | archive 42 |
43 |
New Message!
44 |
45 | delete 46 | 47 | 48 | 49 |
50 |
51 |
52 |
53 |
54 |
-------------------------------------------------------------------------------- /src/slyds/tricks/Tabs.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

Tabs

7 | 8 | 11 | 12 | {[...Array(10)].map(() => ( 13 |
14 | ))} 15 |
16 |
17 |
-------------------------------------------------------------------------------- /src/slyds/tricks/TapToSnap.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from '/src/utils/Prism.astro' 3 | --- 4 | 5 | 6 |

Tap to Snap

7 | 8 | 18 | 19 | {[...Array(10)].map(() => ( 20 |
21 | ))} 22 |
23 |
24 |
-------------------------------------------------------------------------------- /src/slyds/tricks/Title.astro: -------------------------------------------------------------------------------- 1 | 2 |

Scroll Snap

3 |

Tricks n' Hacks

4 |
-------------------------------------------------------------------------------- /src/styles/components/code-gallery.css: -------------------------------------------------------------------------------- 1 | code-gallery { 2 | --space: 5vmin; 3 | display: flex; 4 | align-items: center; 5 | gap: var(--space); 6 | overflow: scroll hidden; 7 | overscroll-behavior-x: contain; 8 | max-inline-size: 94vw; 9 | padding-inline: var(--space); 10 | padding-block-end: 20px; 11 | scroll-padding-inline: var(--space); 12 | scroll-snap-type: x; 13 | 14 | @media (orientation: portrait) { 15 | transform: translateZ(0); 16 | } 17 | 18 | & > * { 19 | flex-shrink: 0; 20 | scroll-snap-align: center; 21 | } 22 | 23 | & > picture { 24 | transform: translateZ(0); 25 | } 26 | } -------------------------------------------------------------------------------- /src/styles/components/demo-stage.css: -------------------------------------------------------------------------------- 1 | demo-stage { 2 | display: grid; 3 | gap: var(--size-fluid-7); 4 | grid-auto-columns: auto; 5 | grid-auto-flow: column; 6 | place-content: center; 7 | align-items: center; 8 | 9 | max-inline-size: 90vw; 10 | inline-size: 100%; 11 | max-block-size: 20vw; 12 | 13 | @nest slyd > &:first-of-type { 14 | margin-block-end: var(--size-5); 15 | } 16 | } -------------------------------------------------------------------------------- /src/styles/components/slyd-scrollport.css: -------------------------------------------------------------------------------- 1 | slyd-scrollport { 2 | overflow: auto; 3 | overscroll-behavior: contain; 4 | max-inline-size: 100%; 5 | max-block-size: 100%; 6 | box-sizing: border-box; 7 | background: hsl(var(--hue) var(--saturation) 4%); 8 | border: 1px solid var(--brand-color-3); 9 | 10 | display: flex; 11 | gap: var(--size-5); 12 | padding: var(--size-5); 13 | align-items: center; 14 | 15 | & > * { 16 | block-size: 25vmin; 17 | aspect-ratio: 1; 18 | flex-shrink: 0; 19 | box-shadow: var(--shadow-3); 20 | color: white; 21 | text-shadow: 0 1px 0 hsl(0 0% 0% / 25%); 22 | 23 | &:nth-child(12n+1) { background: var(--indigo-4) } 24 | &:nth-child(12n+2) { background: var(--violet-4) } 25 | &:nth-child(12n+3) { background: var(--grape-4) } 26 | &:nth-child(12n+4) { background: var(--pink-4) } 27 | &:nth-child(12n+5) { background: var(--red-4) } 28 | &:nth-child(12n+6) { background: var(--orange-4) } 29 | &:nth-child(12n+7) { background: var(--yellow-4) } 30 | &:nth-child(12n+8) { background: var(--lime-4) } 31 | &:nth-child(12n+9) { background: var(--green-4) } 32 | &:nth-child(12n+10) { background: var(--teal-4) } 33 | &:nth-child(12n+11) { background: var(--cyan-4) } 34 | &:nth-child(12n+12) { background: var(--blue-4) } 35 | } 36 | 37 | &.vertical > * { 38 | block-size: 18vmin; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/styles/custom.prism.css: -------------------------------------------------------------------------------- 1 | code[class*="language-"], pre[class*="language-"] { 2 | text-align: left; 3 | font-size: clamp(.8rem, 1.5rem, 3vmin); 4 | 5 | @media (max-width: 640px) { 6 | font-size: 16px; 7 | transform: translateZ(-15x); 8 | } 9 | 10 | @media (orientation: portrait) { 11 | font-size: 2.5vmin; 12 | } 13 | 14 | @media (width >= 480px) { 15 | font-size: clamp(1rem, 2rem, 4vmin); 16 | } 17 | 18 | @media (width >= 1920px) { 19 | font-size: clamp(1rem, 3rem, 4vmin); 20 | } 21 | 22 | @media (width >= 2000px) { 23 | font-size: max(48px, 4vmin); 24 | } 25 | } 26 | 27 | .token.atrule, 28 | .token.attr-value { 29 | color: hsl(120 61% 70%); 30 | } 31 | 32 | .token.atrule { 33 | color: var(--brand-color-2); 34 | } 35 | 36 | .token.atrule > .token:first-of-type { 37 | color: white; 38 | text-shadow: 0 0 .5em white; 39 | display: inline-block; 40 | 41 | /* &::first-letter { 42 | color: hsl(120 40% 75%); 43 | text-shadow: 0 0 .5em #02c435; 44 | } */ 45 | } 46 | 47 | .token.function { 48 | color: var(--brand-color-3); 49 | text-shadow: 0 0 .5em #4003e6; 50 | } 51 | 52 | .token.property { 53 | text-shadow: 0 0 0.5em hsl(210 100% 30%); 54 | } 55 | 56 | .token.url { 57 | color: var(--text-1); 58 | } -------------------------------------------------------------------------------- /src/styles/index.css: -------------------------------------------------------------------------------- 1 | @layer libraries, overrides, slides, tricks; 2 | 3 | @import "slyd" layer(libraries); 4 | 5 | @import "./custom.prism.css" layer(overrides); 6 | @import "./slyd.overrides.css" layer(overrides); 7 | 8 | @import "./utilities.css" layer(slides); 9 | @import "./components/code-gallery.css" layer(slides); 10 | @import "./components/demo-stage.css" layer(slides); 11 | @import "./components/slyd-scrollport.css" layer(slides); 12 | 13 | @import "./tricks/in-view.css" layer(tricks); 14 | @import "./tricks/slides-starter-kit.css" layer(tricks); 15 | @import "./tricks/sticky-slide-starter-kit.css" layer(tricks); 16 | @import "./tricks/perspective-starter-kit.css" layer(tricks); 17 | @import "./tricks/nested-slyds-demo.css" layer(tricks); 18 | @import "./tricks/tap-to-snap.css" layer(tricks); 19 | @import "./tricks/auto-forward.css" layer(tricks); 20 | @import "./tricks/infinite-scroll.css" layer(tricks); 21 | @import "./tricks/smart.css" layer(tricks); 22 | @import "./tricks/overscroll.css" layer(tricks); 23 | @import "./tricks/pull-to-refresh.css" layer(tricks); 24 | @import "./tricks/scroll-start.css" layer(tricks); 25 | @import "./tricks/scroll-linked-tabs.css" layer(tricks); 26 | @import "./tricks/date-time-picker.css" layer(tricks); 27 | @import "./tricks/chat.css" layer(tricks); 28 | @import "./tricks/stories.css" layer(tricks); 29 | @import "./tricks/swipe-ui.css" layer(tricks); 30 | 31 | @media (prefers-reduced-motion: no-preference) { 32 | :focus-visible { 33 | transition: outline-offset 145ms var(--ease-2); 34 | } 35 | :where(:not(:active)):focus-visible { 36 | transition-duration: .25s; 37 | } 38 | } 39 | 40 | :where(:not(:active)):focus-visible { 41 | outline-offset: 5px; 42 | } 43 | 44 | #glossary { 45 | & > code-gallery > div { 46 | transition: opacity 1s ease 1s; 47 | 48 | &.in-view { 49 | opacity: 1; 50 | } 51 | 52 | &:not(.in-view) { 53 | opacity: .1; 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /src/styles/slyd.overrides.css: -------------------------------------------------------------------------------- 1 | slyds { 2 | --surface-1: black; /* for the projector */ 3 | } 4 | 5 | slyds > slyd-group:not(:last-child) > slyd:last-child::after { 6 | inset-inline: auto 2vw; 7 | } 8 | 9 | slyd.lg-gap { 10 | gap: var(--size-10) 11 | } 12 | 13 | :is(h3, h4, h5, h6):not([color]) { 14 | color: var(--text-color-2); 15 | } 16 | 17 | slyds > slyd:after, slyds > slyd-group:not(:last-child) > slyd:last-child:after { 18 | font-size: max(2vmax, 32px); 19 | } 20 | 21 | @media (orientation: portrait) and (max-width: 720px) { 22 | h1, h2, h3, h4, h5, h6, p { 23 | margin: 0 2vmax; 24 | } 25 | } 26 | 27 | @media (min-width: 1024px) { 28 | h2.lg-codeblock-adjust { 29 | transform: translateZ(6px) translateY(50px); 30 | } 31 | 32 | h2.xl-codeblock-adjust { 33 | transform: translateZ(6px) translateY(75px); 34 | } 35 | } -------------------------------------------------------------------------------- /src/styles/tricks/auto-forward.css: -------------------------------------------------------------------------------- 1 | @keyframes slide { 2 | 75%, 99% { 3 | top: 0 4 | } 5 | 95%, 98% { 6 | top: 100% 7 | } 8 | } 9 | 10 | @keyframes slide-restart { 11 | 75%, 99% { 12 | top: 0 13 | } 14 | 95%, 98% { 15 | top: -200% 16 | } 17 | } 18 | 19 | @keyframes snap-toggle { 20 | 96%, 100% { 21 | scroll-snap-align: start; 22 | } 23 | 97%, 99% { 24 | scroll-snap-align: none; 25 | } 26 | } 27 | 28 | .auto-forward { 29 | --_slide-size: 35vh; 30 | 31 | block-size: var(--_slide-size); 32 | inline-size: 25vw; 33 | overflow-y: auto; 34 | overscroll-behavior-y: contain; 35 | scroll-snap-type: y mandatory; 36 | } 37 | 38 | .auto-forward-slide { 39 | position: relative; 40 | min-block-size: var(--_slide-size); 41 | 42 | display: flex; 43 | align-items: center; 44 | justify-content: center; 45 | 46 | &:nth-of-type(even) { 47 | color: var(--grape-0); 48 | background: var(--grape-7); 49 | } 50 | 51 | &:nth-of-type(odd) { 52 | color: var(--pink-0); 53 | background: var(--pink-5); 54 | } 55 | 56 | &:last-of-type > .auto-forward-sentinel { 57 | animation: 58 | slide-restart 3s ease infinite, 59 | snap-toggle 3s ease infinite 60 | ; 61 | } 62 | } 63 | 64 | .auto-forward-sentinel { 65 | position: absolute; 66 | inset: 0; 67 | scroll-snap-align: start; 68 | /* scroll-snap-stop: always; */ 69 | 70 | animation: 71 | slide 3s ease infinite, 72 | snap-toggle 3s ease infinite 73 | ; 74 | } -------------------------------------------------------------------------------- /src/styles/tricks/chat.css: -------------------------------------------------------------------------------- 1 | #chat textarea { 2 | color-scheme: dark; 3 | font-size: 1.25rem; 4 | } 5 | 6 | .chat-ui { 7 | --chat-ui_theme: hsl(200, 100%, 50%); 8 | --chat-ui_theme_compliment: color(var(--chat-ui_theme) hue(+200)); 9 | --chat-ui_theme_text-color: white; 10 | --chat-ui_bg: hsl(0, 0%, 90%); 11 | --chat-ui_width: 350px; 12 | --chat-ui_height: 480px; 13 | --chat-ui_message_bg: white; 14 | --chat-ui_message_bg2: hsl(0, 0%, 85%); 15 | --chat-ui_message_text-color: hsl(0, 0%, 10%); 16 | --chat-ui_message_font-size: 0.8rem; 17 | --chat-ui_easing-quick: cubic-bezier(0.075, 0.820, 0.165, 1.000); 18 | 19 | width: 320px; 20 | height: 480px; 21 | position: relative; 22 | background: var(--chat-ui_bg); 23 | overflow: hidden; 24 | resize: both; 25 | text-align: start; 26 | 27 | @media (width >= 1920px) { 28 | width: 480px; 29 | height: 720px; 30 | --chat-ui_message_font-size: 1.25rem; 31 | } 32 | } 33 | 34 | .chat-titlebar { 35 | display: flex; 36 | flex-wrap: wrap; 37 | align-items: center; 38 | justify-content: space-between; 39 | contain: layout; 40 | background: var(--chat-ui_theme, blue); 41 | box-shadow: 0 0.1rem 1rem hsla(0, 0%, 0%, .4); 42 | overflow: hidden; 43 | padding: .5rem 1rem; 44 | position: absolute; 45 | text-align: start; 46 | top: 0; 47 | left: 0; 48 | right: 0; 49 | z-index: 11; 50 | will-change: transform; 51 | transition: transform 0.15s var(--chat-ui_easing-quick); 52 | 53 | & > h5 { 54 | color: var(--chat-ui_theme_text-color, ); 55 | font-size: 1rem; 56 | font-weight: normal; 57 | line-height: 1.1; 58 | flex: 2; 59 | margin: 0; 60 | } 61 | } 62 | 63 | .chat-avatar { 64 | width: 2rem; 65 | height: 2rem; 66 | border-radius: 50%; 67 | margin: 0; 68 | overflow: hidden; 69 | display: flex; 70 | 71 | & > img { 72 | width: 100%; 73 | height: 100%; 74 | object-fit: cover; 75 | } 76 | } 77 | 78 | .chat-scrollview { 79 | overflow-y: auto; 80 | overflow-x: hidden; 81 | -webkit-overflow-scrolling: touch; 82 | overscroll-behavior: contain; 83 | scroll-snap-type: y proximity; 84 | position: absolute; 85 | top: 0; 86 | left: 0; 87 | right: 0; 88 | bottom: 0; 89 | } 90 | 91 | .chat-messagelist { 92 | display: flex; 93 | flex-wrap: wrap; 94 | flex-direction: column; 95 | justify-content: flex-end; 96 | align-items: flex-end; 97 | padding-block: 4rem; 98 | min-height: 100%; 99 | 100 | & > .chat-cluster:last-child { 101 | scroll-snap-align: end; 102 | scroll-margin-block-end: 5rem; 103 | } 104 | } 105 | 106 | .chat-cluster { 107 | margin: 0.25rem 3rem 0.75rem 0.5rem; 108 | display: flex; 109 | flex-wrap: wrap; 110 | align-self: flex-start; 111 | align-items: flex-end; 112 | 113 | &[mine] { 114 | margin-left: 3rem; 115 | margin-right: 0.5rem; 116 | align-self: flex-end; 117 | 118 | & > section { 119 | align-items: flex-end; 120 | } 121 | } 122 | 123 | & > .chat-avatar { 124 | margin-right: 0.5rem; 125 | bottom: 1rem; 126 | position: sticky; 127 | } 128 | 129 | & > section { 130 | flex: 2; 131 | display: flex; 132 | flex-wrap: wrap; 133 | align-items: flex-start; 134 | flex-direction: column; 135 | 136 | & > h3 { 137 | margin: 0 0 0 0.7rem; 138 | font-size: 0.7rem; 139 | font-weight: 300; 140 | letter-spacing: initial; 141 | color: hsl(0, 0%, 40%); 142 | } 143 | } 144 | } 145 | 146 | .chat-message { 147 | background-attachment: fixed; 148 | background-image: linear-gradient(var(--chat-ui_theme), 30%, hotpink); 149 | background-size: 100% 120%; 150 | color: white; 151 | font-weight: 300; 152 | font-size: var(--chat-ui_message_font-size); 153 | line-height: 1.4; 154 | padding: 0.5rem 0.75rem; 155 | margin: 0; 156 | border-radius: 0.25rem 1rem 1rem 0.25rem; 157 | 158 | &:first-of-type { 159 | border-radius: 1rem 1rem 1rem 0.25rem; 160 | } 161 | 162 | &:not(:first-child) { 163 | margin-top: 3px; 164 | } 165 | } 166 | 167 | [mine] .chat-message { 168 | background: var(--chat-ui_message_bg2); 169 | color: var(--chat-ui_message_text-color); 170 | border-radius: 1rem 0.25rem 0.25rem 1rem; 171 | } 172 | 173 | .chat-authoring { 174 | color: black; 175 | position: absolute; 176 | z-index: 12; 177 | bottom: 0.5rem; 178 | right: 0; 179 | box-sizing: border-box; 180 | margin: 0.5rem; 181 | padding: 0.5rem 0.75rem; 182 | border-radius: 1rem 1rem 2px; 183 | box-shadow: 0.25rem 0.5rem 1rem hsla(0, 0%, 0%, .2); 184 | background: white; 185 | caret-color: var(--chat-ui_theme, blue); 186 | font-size: 0.9rem; 187 | font-weight: 300; 188 | line-height: 1.4em; 189 | width: calc(100% - 1rem); 190 | transition: width 0.15s var(--chat-ui_easing-quick); 191 | 192 | @media (width >= 1920px) { 193 | font-size: 1.3rem; 194 | } 195 | 196 | &:focus { 197 | width: calc(100% - 1rem); 198 | outline: none; 199 | } 200 | 201 | &:empty:not(:focus) { 202 | width: 50%; 203 | } 204 | 205 | &:empty::after { 206 | content: "Say Something.."; 207 | } 208 | } -------------------------------------------------------------------------------- /src/styles/tricks/date-time-picker.css: -------------------------------------------------------------------------------- 1 | .picker { 2 | display: grid; 3 | grid-auto-flow: column; 4 | gap: 2ch; 5 | position: relative; 6 | box-sizing: border-box; 7 | } 8 | 9 | .picker::before, 10 | .picker::after { 11 | content: " "; 12 | position: absolute; 13 | top: 0; 14 | background: linear-gradient( 15 | var(--surface-1), 16 | 65%, 17 | hsl(200 20% 10% / 0%) 18 | ); 19 | /* backdrop-filter: blur(1px); */ 20 | width: 100%; 21 | height: calc(50% - 3.5ex); 22 | pointer-events: none; 23 | } 24 | 25 | .picker::after { 26 | top: auto; 27 | bottom: 0; 28 | background: linear-gradient( 29 | hsl(200 20% 10% / 0%), 30 | 35%, 31 | var(--surface-1) 32 | ); 33 | } 34 | 35 | .picker > * { 36 | display: grid; 37 | grid-auto-rows: 9vmin; 38 | align-items: center; 39 | max-block-size: calc(9vmin * 5); 40 | overflow-y: auto; 41 | overscroll-behavior-y: contain; 42 | scroll-snap-type: y mandatory; 43 | padding-inline-end: 1ch; 44 | font-size: 5vmin; 45 | font-weight: lighter; 46 | 47 | @media (width >= 1920px) { 48 | font-size: 6vmin; 49 | } 50 | } 51 | 52 | .picker > [title]::before { 53 | content: attr(title); 54 | position: sticky; 55 | top: 0; 56 | align-self: start; 57 | color: hsl(0 0% 65%); 58 | z-index: 1; 59 | font-size: min(.5em, 40%); 60 | font-weight: bold; 61 | text-align: center; 62 | text-shadow: 0 1px 1px hsl(0 0% 0% / 50%); 63 | } 64 | 65 | .picker > [title]:first-child::before { 66 | text-align: end; 67 | } 68 | 69 | .picker > * > * { 70 | scroll-snap-align: center; 71 | } 72 | 73 | .picker date { 74 | text-align: end; 75 | } 76 | 77 | .picker time { 78 | text-align: center; 79 | } -------------------------------------------------------------------------------- /src/styles/tricks/in-view.css: -------------------------------------------------------------------------------- 1 | #in-view-scrollport { 2 | & > * { 3 | transition: 4 | opacity 3s ease, 5 | border-radius 1s ease; 6 | } 7 | 8 | & > :not(.in-view) { 9 | opacity: .1; 10 | } 11 | 12 | & > .in-view { 13 | border-radius: 50%; 14 | } 15 | } -------------------------------------------------------------------------------- /src/styles/tricks/infinite-scroll.css: -------------------------------------------------------------------------------- 1 | .infinite-scroll { 2 | overflow-x: auto; 3 | overscroll-behavior-x: contain; 4 | scroll-snap-type: x mandatory; 5 | border: 1px solid var(--brand-color-3); 6 | 7 | display: grid; 8 | grid-auto-flow: column; 9 | grid-auto-columns: 100%; 10 | grid-template-rows: 35vh; 11 | 12 | & > div { 13 | scroll-snap-align: center; 14 | display: grid; 15 | place-content: center; 16 | } 17 | } -------------------------------------------------------------------------------- /src/styles/tricks/nested-slyds-demo.css: -------------------------------------------------------------------------------- 1 | .nested-slyds-demo { 2 | --_inline-size: 25vw; 3 | --_block-size: 20vw; 4 | 5 | inline-size: var(--_inline-size); 6 | block-size: var(--_block-size); 7 | grid-auto-columns: var(--_inline-size); 8 | grid-template-rows: var(--_block-size); 9 | 10 | border: 1px solid var(--brand-color-3); 11 | 12 | & > slyd-group { 13 | max-inline-size: var(--_inline-size); 14 | max-block-size: var(--_block-size); 15 | grid-auto-rows: var(--_block-size); 16 | grid-template-columns: var(--_inline-size); 17 | 18 | & > slyd { 19 | inline-size: var(--_inline-size); 20 | block-size: var(--_block-size); 21 | 22 | &:first-child:after { 23 | left: calc(13vw - .5em); 24 | } 25 | 26 | &:last-child:after { 27 | bottom: calc(17vh - .5em); 28 | } 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/styles/tricks/overscroll.css: -------------------------------------------------------------------------------- 1 | .overscroll-demo { 2 | overflow: auto; 3 | overscroll-behavior: contain; 4 | scroll-snap-type: x mandatory; 5 | max-inline-size: 100%; 6 | max-block-size: 100%; 7 | box-sizing: border-box; 8 | background: hsl(var(--hue) var(--saturation) 4%); 9 | border: 1px solid var(--brand-color-3); 10 | 11 | display: flex; 12 | gap: var(--size-5); 13 | padding: var(--size-5); 14 | scroll-padding-inline: var(--size-5); 15 | align-items: center; 16 | 17 | & > :not(.overscroller) { 18 | block-size: 25vmin; 19 | aspect-ratio: 1; 20 | flex-shrink: 0; 21 | box-shadow: var(--shadow-3); 22 | scroll-snap-align: start; 23 | 24 | &:nth-child(12n+1) { background: var(--indigo-4) } 25 | &:nth-child(12n+2) { background: var(--violet-4) } 26 | &:nth-child(12n+3) { background: var(--grape-4) } 27 | &:nth-child(12n+4) { background: var(--pink-4) } 28 | &:nth-child(12n+5) { background: var(--red-4) } 29 | &:nth-child(12n+6) { background: var(--orange-4) } 30 | &:nth-child(12n+7) { background: var(--yellow-4) } 31 | &:nth-child(12n+8) { background: var(--lime-4) } 32 | &:nth-child(12n+9) { background: var(--green-4) } 33 | &:nth-child(12n+10) { background: var(--teal-4) } 34 | &:nth-child(12n+11) { background: var(--cyan-4) } 35 | &:nth-child(12n+12) { background: var(--blue-4) } 36 | 37 | &:nth-of-type(10), 38 | &:nth-of-type(11) { 39 | scroll-snap-align: end; 40 | } 41 | } 42 | } 43 | 44 | .overscroller { 45 | inline-size: 20vw; 46 | flex-shrink: 0; 47 | } -------------------------------------------------------------------------------- /src/styles/tricks/perspective-starter-kit.css: -------------------------------------------------------------------------------- 1 | .perspective-starter-kit { 2 | --_slide-size: 35vh; 3 | 4 | perspective: 10px; 5 | perspective-origin: center center; 6 | block-size: var(--_slide-size); 7 | inline-size: 25vw; 8 | overflow-y: auto; 9 | overscroll-behavior-y: contain; 10 | scroll-snap-type: y mandatory; 11 | 12 | & > section { 13 | min-block-size: var(--_slide-size); 14 | scroll-snap-align: start; 15 | scroll-snap-stop: always; 16 | 17 | display: flex; 18 | align-items: center; 19 | justify-content: center; 20 | 21 | &:nth-of-type(even) { 22 | color: var(--blue-0); 23 | background: var(--blue-6); 24 | } 25 | 26 | &:nth-of-type(odd) { 27 | color: var(--cyan-0); 28 | background: var(--cyan-5); 29 | } 30 | 31 | &:nth-child(1) > p { transform: translateZ(2px) } 32 | &:nth-child(2) > p { transform: translateZ(4px) } 33 | &:nth-child(3) > p { transform: translateZ(6px) } 34 | &:nth-child(4) > p { transform: translateZ(7px) } 35 | &:nth-child(5) > p { transform: translateZ(8px) } 36 | &:nth-child(6) > p { transform: translateZ(9px) } 37 | 38 | &.kitchen-sink { 39 | display: grid; 40 | align-content: center; 41 | 42 | & > p{ 43 | &:nth-child(3) { transform: translateZ(3px) } 44 | &:nth-child(2) { transform: translateZ(2px) } 45 | &:nth-child(1) { transform: translateZ(1px) } 46 | } 47 | } 48 | } 49 | } 50 | 51 | .perspective-starter-kit, 52 | .perspective-starter-kit > section { 53 | transform-style: preserve-3d; 54 | } -------------------------------------------------------------------------------- /src/styles/tricks/pull-to-refresh.css: -------------------------------------------------------------------------------- 1 | .pull-to-refresh { 2 | scroll-snap-type: y mandatory; 3 | scroll-snap-stop: always; 4 | overscroll-behavior: contain; 5 | scroll-behavior: smooth; 6 | overflow-y: auto; 7 | max-block-size: 40vh; 8 | border: 1px solid var(--brand-color-3); 9 | } 10 | 11 | .pull-to-refresh-main { 12 | scroll-snap-align: start; 13 | scroll-snap-stop: always; 14 | display: grid; 15 | gap: var(--size-5); 16 | padding: var(--size-5); 17 | 18 | & > p { 19 | text-align: start; 20 | font-size: 1.25rem; 21 | font-family: "BLOKK"; 22 | } 23 | } 24 | 25 | #refresh { 26 | block-size: 150px; 27 | inline-size: 100%; 28 | background: hsl(0 0% 50% / 10%); 29 | display: grid; 30 | gap: 1ch; 31 | align-content: center; 32 | justify-items: center; 33 | position: relative; 34 | 35 | & > svg { 36 | --size: 2.5ch; 37 | fill: none; 38 | stroke: currentColor; 39 | inline-size: var(--size); 40 | block-size: var(--size); 41 | } 42 | 43 | & > span { 44 | font-size: 1.25rem; 45 | } 46 | 47 | &::before { 48 | content: ""; 49 | position: absolute; 50 | inset: 0; 51 | block-size: 10px; 52 | animation: delayed-snap-point 2ms forwards; 53 | } 54 | 55 | &::after { 56 | content: ""; 57 | position: absolute; 58 | inset: auto 0 0; 59 | block-size: 5px; 60 | background: deeppink; 61 | opacity: 0; 62 | } 63 | 64 | &[loading-state="loading"]::after { 65 | animation: indeterminate-loading 1s ease infinite; 66 | } 67 | } 68 | 69 | @keyframes delayed-snap-point { 70 | to { scroll-snap-align: start } 71 | } 72 | 73 | @keyframes indeterminate-loading { 74 | 50% { opacity: 1 } 75 | } 76 | -------------------------------------------------------------------------------- /src/styles/tricks/scroll-linked-tabs.css: -------------------------------------------------------------------------------- 1 | .tabs { 2 | --accent: 328deg 100% 54%; 3 | 4 | display: flex; 5 | flex-direction: column; 6 | overflow: hidden; 7 | position: relative; 8 | } 9 | 10 | .tabs > nav { 11 | display: grid; 12 | overflow-x: auto; 13 | overscroll-behavior-x: contain; 14 | scroll-behavior: smooth; 15 | scroll-snap-type: x mandatory; 16 | font-size: 1.5rem; 17 | margin-block-start: 1rem; 18 | } 19 | 20 | .tabs > nav > div { 21 | display: flex; 22 | } 23 | 24 | .tabs nav::-webkit-scrollbar { 25 | width: 0; 26 | height: 0; 27 | } 28 | 29 | .tabs > nav a { 30 | white-space: nowrap; 31 | color: var(--text-1); 32 | font-weight: bold; 33 | text-decoration: none; 34 | padding: 1ch 1.5rem; 35 | border-block-end: 1px solid transparent; 36 | scroll-snap-align: start; 37 | transition: color .3s ease; 38 | } 39 | 40 | .tabs > nav a:hover { 41 | background: hsl(var(--accent) / 5%); 42 | } 43 | 44 | .tabs > nav a:focus { 45 | outline-offset: -1ch; 46 | } 47 | 48 | .tabs > nav a:target, 49 | .tabs > nav a:active, 50 | .tabs > nav a[active]{ 51 | color: hsl(var(--accent)); 52 | } 53 | 54 | .tabs .indicator { 55 | min-width: 5ch; 56 | height: 2px; 57 | margin-block-end: 1ex; 58 | background: hsl(var(--accent)); 59 | border-radius: 1rem; 60 | } 61 | 62 | .tabs > section { 63 | display: grid; 64 | grid-auto-flow: column; 65 | grid-auto-columns: 100%; 66 | block-size: 100%; 67 | overflow-x: auto; 68 | overflow-y: hidden; 69 | overscroll-behavior-x: contain; 70 | scroll-behavior: smooth; 71 | scroll-snap-type: x mandatory; 72 | } 73 | 74 | .tabs > section > article { 75 | scroll-snap-align: start; 76 | overflow-y: auto; 77 | overscroll-behavior-y: contain; 78 | box-sizing: border-box; 79 | padding: 1rem 1.5rem; 80 | font-family: "Blokk"; 81 | font-size: 1.25rem; 82 | text-align: start; 83 | display: grid; 84 | align-content: start; 85 | 86 | & > h2:not(:first-of-type) { 87 | margin-block-start: var(--size-7); 88 | } 89 | 90 | & > p { 91 | font-size: 1.25rem; 92 | } 93 | } 94 | 95 | .device h2 { 96 | margin-block-end: 0; 97 | font-size: 3rem; 98 | line-height: .75; 99 | } 100 | 101 | .device header { 102 | text-align: start; 103 | } 104 | 105 | .device { 106 | display: flex; 107 | flex-direction: column; 108 | inline-size: 300px; 109 | block-size: 500px; 110 | border-radius: 1ch; 111 | overflow: hidden; 112 | border: 1px solid var(--brand-color-3); 113 | box-shadow: var(--shadow-5); 114 | resize: both; 115 | 116 | @media (width >= 1920px) { 117 | inline-size: 480px; 118 | block-size: 720px; 119 | } 120 | } 121 | 122 | .device > .tabs { 123 | flex: 1; 124 | } 125 | 126 | .device header > svg { 127 | width: 1.25rem; 128 | padding: 1.5rem 1rem 1rem 1.5rem; 129 | } 130 | 131 | .device nav svg { 132 | width: 1em; 133 | pointer-events: none; 134 | } 135 | 136 | #scroll-linked demo-stage > div > h2 { 137 | text-align: start; 138 | color: var(--text-1); 139 | } -------------------------------------------------------------------------------- /src/styles/tricks/scroll-start.css: -------------------------------------------------------------------------------- 1 | @keyframes start-scroll { 2 | from { scroll-snap-align: center } 3 | to { scroll-snap-align: unset } 4 | } 5 | 6 | .scroll-start-trick { 7 | scroll-snap-type: x mandatory; 8 | 9 | & > :nth-child(5) { 10 | animation: start-scroll 2ms; 11 | font-weight: bold; 12 | } 13 | } -------------------------------------------------------------------------------- /src/styles/tricks/slides-starter-kit.css: -------------------------------------------------------------------------------- 1 | .slide-starter-kit { 2 | --_slide-size: 35vh; 3 | 4 | block-size: var(--_slide-size); 5 | inline-size: 25vw; 6 | overflow-y: auto; 7 | overscroll-behavior-y: contain; 8 | scroll-snap-type: y mandatory; 9 | 10 | & > section { 11 | min-block-size: var(--_slide-size); 12 | scroll-snap-align: start; 13 | scroll-snap-stop: always; 14 | 15 | display: flex; 16 | align-items: center; 17 | justify-content: center; 18 | 19 | &:nth-of-type(even) { 20 | color: var(--grape-0); 21 | background: var(--grape-7); 22 | } 23 | 24 | &:nth-of-type(odd) { 25 | color: var(--pink-0); 26 | background: var(--pink-5); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/styles/tricks/smart.css: -------------------------------------------------------------------------------- 1 | #smart-container { 2 | & > * { 3 | transition: 4 | opacity 3s ease, 5 | border-radius 1s ease; 6 | } 7 | 8 | & > :not(.snapped) { 9 | opacity: .1; 10 | } 11 | 12 | & > .snapped { 13 | border-radius: 50%; 14 | } 15 | } -------------------------------------------------------------------------------- /src/styles/tricks/sticky-slide-starter-kit.css: -------------------------------------------------------------------------------- 1 | .sticky-slide-starter-kit { 2 | --_slide-size: 35vh; 3 | 4 | block-size: var(--_slide-size); 5 | inline-size: 25vw; 6 | overflow-y: auto; 7 | overscroll-behavior-y: contain; 8 | scroll-snap-type: y mandatory; 9 | 10 | & > section { 11 | min-block-size: var(--_slide-size); 12 | scroll-snap-align: start; 13 | scroll-snap-stop: always; 14 | 15 | position: sticky; 16 | top: 0; 17 | 18 | display: flex; 19 | align-items: center; 20 | justify-content: center; 21 | 22 | &:nth-of-type(even) { 23 | color: var(--green-0); 24 | background: var(--green-7); 25 | } 26 | 27 | &:nth-of-type(odd) { 28 | color: var(--teal-0); 29 | background: var(--teal-8); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/styles/tricks/stories.css: -------------------------------------------------------------------------------- 1 | #stories h2 { 2 | text-align: start; 3 | color: var(--text-1); 4 | } 5 | 6 | .stories { 7 | display: grid; 8 | grid: 1fr / auto-flow 100%; 9 | gap: 1ch; 10 | overflow-x: auto; 11 | scroll-snap-type: x mandatory; 12 | overscroll-behavior: contain; 13 | touch-action: pan-x; 14 | inline-size: 320px; 15 | block-size: 568px; 16 | border-radius: 1ch; 17 | 18 | @media (width >= 1920px) { 19 | inline-size: 480px; 20 | block-size: 800px; 21 | } 22 | } 23 | 24 | .user { 25 | /* outer */ 26 | scroll-snap-align: start; 27 | scroll-snap-stop: always; 28 | 29 | /* inner */ 30 | display: grid; 31 | grid: [story] 1fr / [story] 1fr; 32 | } 33 | 34 | .story { 35 | grid-area: story; 36 | 37 | background-size: cover; 38 | background-image: 39 | var(--bg), 40 | linear-gradient(to top, hsl(0 0% 98%), hsl(0 0% 90%)); 41 | 42 | user-select: none; 43 | touch-action: manipulation; 44 | 45 | transition: opacity .3s cubic-bezier(0.4, 0.0, 1, 1); 46 | 47 | &.seen { 48 | opacity: 0; 49 | pointer-events: none; 50 | } 51 | } -------------------------------------------------------------------------------- /src/styles/tricks/swipe-ui.css: -------------------------------------------------------------------------------- 1 | .swipe-ui { 2 | border-radius: 1ch; 3 | overflow: hidden; 4 | } 5 | 6 | .swipe-list { 7 | width: 100%; 8 | height: 100%; 9 | overflow-y: scroll; 10 | overscroll-behavior-y: contain; 11 | 12 | display: grid; 13 | grid-auto-rows: 10vh; 14 | gap: 1px; 15 | } 16 | 17 | .swipe-item { 18 | display: grid; 19 | grid-template-columns: 100% 100% 100%; 20 | grid-template-rows: [action] 1fr; 21 | 22 | overflow-x: scroll; 23 | overscroll-behavior-x: contain; 24 | scroll-snap-type: x mandatory; 25 | scroll-snap-stop: always; 26 | 27 | color: white; 28 | background: hsl(200 100% 50%); 29 | 30 | /* &:hover > .action:first-child { 31 | scroll-snap-align: end; 32 | } 33 | 34 | &:hover > .action:last-child { 35 | scroll-snap-align: start; 36 | } */ 37 | 38 | &::-webkit-scrollbar { 39 | height: 0; 40 | } 41 | } 42 | 43 | .swipe-action { 44 | display: flex; 45 | align-items: center; 46 | justify-content: center; 47 | font-size: 1.5rem; 48 | padding: 1ch; 49 | gap: 1ch; 50 | background: hsl(100deg 120% 40%); 51 | 52 | @media (width >= 1920px) { 53 | font-size: 2rem; 54 | font-weight: 300; 55 | } 56 | 57 | &.primary { 58 | scroll-snap-align: center; 59 | overflow-y: hidden; 60 | background: inherit; 61 | z-index: 1; 62 | box-shadow: 0 0 5px 5px hsl(0 0% 0% / 20%); 63 | } 64 | 65 | &.danger { 66 | background: red; 67 | } 68 | 69 | /* &:not(.primary) { 70 | position: sticky; 71 | left: 0; 72 | right: 0; 73 | } */ 74 | 75 | &:first-child { 76 | justify-content: flex-end; 77 | } 78 | 79 | &:last-child { 80 | justify-content: flex-start; 81 | } 82 | 83 | & svg { 84 | block-size: 2ch; 85 | } 86 | } -------------------------------------------------------------------------------- /src/styles/tricks/tap-to-snap.css: -------------------------------------------------------------------------------- 1 | .tap-to-snap { 2 | scroll-snap-type: x mandatory; 3 | scroll-behavior: smooth; 4 | 5 | & > div { 6 | cursor: pointer; 7 | 8 | &:is(:active, :focus) { 9 | scroll-snap-align: center; 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /src/styles/utilities.css: -------------------------------------------------------------------------------- 1 | .lifted, 2 | code-gallery > pre { 3 | background: hsl(var(--hue) var(--saturation) 12%); 4 | box-shadow: var(--shadow-3); 5 | padding-inline: var(--size-7); 6 | padding-block: var(--size-5); 7 | border-radius: var(--radius-3); 8 | } 9 | 10 | .columns { 11 | display: flex; 12 | gap: var(--size-5); 13 | } 14 | 15 | .rows { 16 | display: grid; 17 | gap: var(--size-5); 18 | } 19 | 20 | .vertical { 21 | flex-direction: column; 22 | justify-self: flex-start; 23 | 24 | &.tall { 25 | min-block-size: 45vh; 26 | } 27 | } 28 | 29 | .both { 30 | display: grid; 31 | grid-template-columns: repeat(6, 1fr); 32 | } 33 | 34 | .snap-both { 35 | scroll-snap-type: both mandatory; 36 | 37 | & > * { 38 | scroll-snap-align: center; 39 | } 40 | } 41 | 42 | .snap-x { 43 | scroll-snap-type: x mandatory; 44 | 45 | & > * { 46 | scroll-snap-align: center; 47 | } 48 | } 49 | 50 | .snap-one-x { 51 | scroll-snap-type: x mandatory; 52 | 53 | & > :nth-child(5) { 54 | scroll-snap-align: center; 55 | } 56 | } 57 | 58 | .snap-nested-x { 59 | scroll-snap-type: x mandatory; 60 | 61 | & > div { 62 | &:nth-of-type(even) {text-align: start} 63 | &:nth-of-type(odd) {text-align: end} 64 | 65 | & > span { 66 | display: inline-block; 67 | scroll-snap-align: center; 68 | } 69 | } 70 | } 71 | 72 | .snap-y { 73 | scroll-snap-type: y proximity; 74 | 75 | &.snap-stop { 76 | scroll-snap-type: y mandatory; 77 | 78 | & > * { 79 | scroll-snap-stop: always; 80 | } 81 | } 82 | 83 | & > * { 84 | scroll-snap-align: center; 85 | } 86 | } 87 | 88 | .snap-y-prox { 89 | scroll-snap-type: y proximity; 90 | 91 | & > * { 92 | scroll-snap-align: center; 93 | } 94 | } 95 | 96 | .snap-y-start { 97 | scroll-snap-type: y mandatory; 98 | 99 | & > * { 100 | scroll-snap-align: start; 101 | } 102 | } 103 | 104 | .snap-stop > * { 105 | scroll-snap-stop: always; 106 | } 107 | 108 | .rtl { 109 | direction: rtl; 110 | } 111 | 112 | [badge] { 113 | border-radius: var(--radius-round); 114 | padding-inline: var(--size-5); 115 | border: 1px solid var(--indigo-2); 116 | color: var(--indigo-2); 117 | } -------------------------------------------------------------------------------- /src/utils/Prism.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prism from 'prismjs'; 3 | import 'prismjs/plugins/normalize-whitespace/prism-normalize-whitespace.js'; 4 | const { code, lang} = Astro.props; 5 | const grammar = Prism.languages[lang]; 6 | const nw = Prism.plugins.NormalizeWhitespace; 7 | let html = nw.normalize(code) ; 8 | if (grammar) { 9 | html = Prism.highlight(html, grammar, lang); 10 | } 11 | --- 12 | 13 |
14 | --------------------------------------------------------------------------------