diff options
| author | Xe Iaso <me@christine.website> | 2022-12-28 11:35:45 -0500 |
|---|---|---|
| committer | Xe Iaso <me@christine.website> | 2022-12-28 11:35:45 -0500 |
| commit | f6a10af0a81a1b3a83bdce660ed5ee88abcc063a (patch) | |
| tree | 64430939d9d96419b0b230b4944e29d464e1b0cd | |
| parent | 793e1c79bfaecbc14e868fdf91d802a88be39384 (diff) | |
| download | xesite-unwrapped-2022.tar.xz xesite-unwrapped-2022.zip | |
first attemptunwrapped-2022
Signed-off-by: Xe Iaso <me@christine.website>
| -rw-r--r-- | blog/xesite-unwrapped-2022.markdown | 16 | ||||
| -rw-r--r-- | css/shim.css | 172 | ||||
| -rw-r--r-- | dhall/stories.dhall | 47 | ||||
| -rw-r--r-- | dhall/types/Story.dhall | 5 | ||||
| -rw-r--r-- | dhall/types/StoryStep.dhall | 3 | ||||
| -rw-r--r-- | dhall/types/package.dhall | 2 | ||||
| -rw-r--r-- | lib/xesite_markdown/src/lib.rs | 8 | ||||
| -rw-r--r-- | lib/xesite_templates/src/lib.rs | 20 | ||||
| -rwxr-xr-x | src/frontend/build.sh | 1 | ||||
| -rw-r--r-- | src/frontend/stories.tsx | 119 | ||||
| -rw-r--r-- | static/unwrapped-2022.json | 25 |
11 files changed, 418 insertions, 0 deletions
diff --git a/blog/xesite-unwrapped-2022.markdown b/blog/xesite-unwrapped-2022.markdown new file mode 100644 index 0000000..677538e --- /dev/null +++ b/blog/xesite-unwrapped-2022.markdown @@ -0,0 +1,16 @@ +--- +title: Xesite Unwrapped 2022 +date: 2022-12-31 +tags: + - JavaScript + - shitposting + - WordArt +--- + +<noscript> + <p>I'm sorry but you will need to enable JavaScript support for this post. I + use advanced JavaScript features to create the wonderment that is this + creation.</p> +</noscript> + +<xeblog-story name="unwrapped-2022"></xeblog-story> diff --git a/css/shim.css b/css/shim.css index 2e1df90..7a3ff89 100644 --- a/css/shim.css +++ b/css/shim.css @@ -112,3 +112,175 @@ figcaption { background-color: #fbf1c7; } } + +.stories { + display: grid; + grid: 1fr / auto-flow 100%; + gap: 1ch; + overflow-x: auto; + scroll-snap-type: x mandatory; + overscroll-behavior: contain; + touch-action: pan-x; + + min-width: 512px; + min-height: 512px; + max-width: 1024px; + max-height: 1024px; + + border-radius: 3ch; + + box-shadow: + 0 5px 2.5px hsla(200, 95%, 3%, .037), + 0 12px 6.5px hsla(200, 95%, 3%, .053), + 0 22.5px 13px hsla(200, 95%, 3%, .065), + 0 40.2px 24px hsla(200, 95%, 3%, .077), + 0 75.2px 44px hsla(200, 95%, 3%, .093), + 0 180px 80px hsla(200, 95%, 3%, .13) +} + +.user { + scroll-snap-align: start; + scroll-snap-stop: always; + display: grid; + grid: [story] 1fr / [story] 1fr; +} + +.story { + grid-area: story; + + background-size: cover; + background-image: + var(--bg), + linear-gradient(to top, lch(98 0 0), lch(90 0 0)); + + user-select: none; + touch-action: manipulation; + + transition: opacity .3s cubic-bezier(0.4, 0.0, 1, 1); + + &.seen { + opacity: 0; + pointer-events: none; + } +} + +*.wordart { + border: 0; + padding: 0; + margin: 0; + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; +} + +.wordart { + font-family: Arial, sans-serif; + font-size: 4em; + font-weight: bold; + position: relative; + z-index: 1; + display: inline-block; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.wordart.superhero { + transform: skew(0, -15deg) scale(1, 1.5); + -webkit-transform: skew(0, -15deg) scale(1, 1.5); + -moz-transform: skew(0, -15deg) scale(1, 1.5); + -o-transform: skew(0, -15deg) scale(1, 1.5); + -ms-transform: skew(0, -15deg) scale(1, 1.5); +} + +.wordart { + font-family: Arial, sans-serif; + font-size: 4em; + font-weight: bold; + position: relative; + z-index: 1; + display: inline-block; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.wordart.superhero { + transform: skew(0, -15deg) scale(1, 1.5); + -webkit-transform: skew(0, -15deg) scale(1, 1.5); + -moz-transform: skew(0, -15deg) scale(1, 1.5); + -o-transform: skew(0, -15deg) scale(1, 1.5); + -ms-transform: skew(0, -15deg) scale(1, 1.5); +} + +.wordart.superhero .text { + font-family: Impact; + background: #fdea00; + background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJod…EiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+); + background: -moz-linear-gradient(top, #fdea00 0%, #fdcf00 44%, #fc2700 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fdea00), color-stop(44%, #fdcf00), color-stop(100%, #fc2700)); + background: -webkit-linear-gradient(top, #fdea00 0%, #fdcf00 44%, #fc2700 100%); + background: -o-linear-gradient(top, #fdea00 0%, #fdcf00 44%, #fc2700 100%); + background: -ms-linear-gradient(top, #fdea00 0%, #fdcf00 44%, #fc2700 100%); + background: linear-gradient(to bottom, #fdea00 0%, #fdcf00 44%, #fc2700 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdea00', endColorstr='#fc2700', GradientType=0); + background-clip: text; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; +} + +.wordart.superhero .text:before { + content: attr(data-text); + position: absolute; + z-index: -1; + text-shadow: 0.01em 0em 0 #802700, 0em 0.01em 0 #c23d00, 0.02em 0.01em 0 #802700, 0.01em 0.02em 0 #c23d00, 0.03em 0.02em 0 #802700, 0.02em 0.03em 0 #c23d00, 0.04em 0.03em 0 #802700, 0.03em 0.04em 0 #c23d00, 0.05em 0.04em 0 #802700, 0.04em 0.05em 0 #c23d00, 0.06em 0.05em 0 #802700, 0.05em 0.06em 0 #c23d00, 0.07em 0.06em 0 #802700, 0.06em 0.07em 0 #c23d00, 0.08em 0.07em 0 #802700, 0.07em 0.08em 0 #c23d00; +} + +.wordart.blues.text { + font-family: Impact, sans-serif; + color: #24c0fd; + text-shadow: 0.13em -0.13em 0px #0000aa; + letter-spacing: -0.05em; +} + +.story-text.text { + font-family: "Comic Sans MS", "Comic Sans", cursive; + position: relative; + font-size: calc(34px + (36 + 36 * 0.7) * ((100vw - 320px) / 1920)); + line-height: calc(46px + (65 + 65 * 0.7) * ((100vw - 320px) / 1920)); + font-weight: 300; + background-color: #22012D; + color: #F603AA; + display: inline-block; + padding-left: 30px; + padding-right: 30px; +} + +.story-text.box { + border-top-left-radius: 1rem; + border-top-right-radius: 1rem; + border-bottom-left-radius: 1rem; + border-bottom-right-radius: 1rem; +} + +.story-text.box::after{ + content: ""; + position: absolute; + width: 2rem; + height: 2rem; + background-color: white; + z-index:5; + right: -2rem; + bottom:0rem; + border-radius: 100%; +} + +.story-text.box::before{ + content: ""; + position: absolute; + width: 1rem; + height: 1rem; + background-color: #F603AA; + z-index:4; + right: -1rem; + bottom:0rem; + overflow: hidden; +} diff --git a/dhall/stories.dhall b/dhall/stories.dhall new file mode 100644 index 0000000..8900269 --- /dev/null +++ b/dhall/stories.dhall @@ -0,0 +1,47 @@ +let xesite = ./types/package.dhall + +let Prelude = ./Prelude.dhall + +let Story = xesite.Story + +let Step = xesite.StoryStep + +let stories = + [ Story::{ + , name = "unwrapped-2022" + , steps = + [ Step::{ + , file = "title" + , title = "Xesite 2022" + , text = "The last year all wrapped up!" + } + , Step::{ + , file = "posts" + , title = "Blogposts" + , text = "Xe wrote \$NUMBER posts this year!" + } + , Step::{ + , file = "talks" + , title = "Talks" + , text = "Xe gave 4 talks this year! Which one was your favorite?" + } + , Step::{ + , file = "commits" + , title = "340 commits" + , text = "There were 340 commits to Xesite this year!" + } + ] + } + ] + +let storyToMapValue = + \(story : Story.Type) -> { mapKey = story.name, mapValue = story } + +let map = + Prelude.List.map + Story.Type + (Prelude.Map.Entry Text Story.Type) + storyToMapValue + stories + +in { stories, map } diff --git a/dhall/types/Story.dhall b/dhall/types/Story.dhall new file mode 100644 index 0000000..1f11a2e --- /dev/null +++ b/dhall/types/Story.dhall @@ -0,0 +1,5 @@ +let Step = ./StoryStep.dhall + +in { Type = { name : Text, steps : List Step.Type } + , default = { name = "", steps = [] : List Step.Type } + } diff --git a/dhall/types/StoryStep.dhall b/dhall/types/StoryStep.dhall new file mode 100644 index 0000000..3c7ac4f --- /dev/null +++ b/dhall/types/StoryStep.dhall @@ -0,0 +1,3 @@ +{ Type = { file : Text, title : Text, text : Text } +, default = { file = "", text = "", title = "" } +} diff --git a/dhall/types/package.dhall b/dhall/types/package.dhall index 4f4166e..75abd4a 100644 --- a/dhall/types/package.dhall +++ b/dhall/types/package.dhall @@ -10,5 +10,7 @@ , Salary = ./Salary.dhall , SeriesDescription = ./SeriesDescription.dhall , Stock = ./Stock.dhall +, Story = ./Story.dhall +, StoryStep = ./StoryStep.dhall , StockKind = ./StockKind.dhall } diff --git a/lib/xesite_markdown/src/lib.rs b/lib/xesite_markdown/src/lib.rs index 941761d..0c6900a 100644 --- a/lib/xesite_markdown/src/lib.rs +++ b/lib/xesite_markdown/src/lib.rs @@ -175,6 +175,14 @@ pub fn render(inp: &str) -> Result<String> { el.replace(&xesite_templates::talk_warning().0, ContentType::Html); Ok(()) }), + element!("xeblog-story", |el| { + let name = el + .get_attribute("name") + .ok_or(Error::MissingElementAttribute("name".to_string()))?; + + el.replace(&xesite_templates::story(name).0, ContentType::Html); + Ok(()) + }), element!("xeblog-video", |el| { let path = el .get_attribute("path") diff --git a/lib/xesite_templates/src/lib.rs b/lib/xesite_templates/src/lib.rs index 1149aaa..2f830f8 100644 --- a/lib/xesite_templates/src/lib.rs +++ b/lib/xesite_templates/src/lib.rs @@ -96,6 +96,26 @@ pub fn sticker(name: String, mood: String) -> Markup { } } +pub fn story(name: String) -> Markup { + let uuid = uuid::Uuid::new_v4(); + let uuid = format!("{uuid}").replace("-", ""); + let story_script = PreEscaped(format!( + r#" +<script type="module"> +import {{ init }} from "/static/js/stories.js?cachebust={uuid}"; + +init("{uuid}", "{name}"); +</script> +"# + )); + + html! { + div id=(uuid) { + (story_script) + } + } +} + pub fn video(path: String) -> Markup { let stream_url = format!( "https://cdn.xeiaso.net/file/christine-static/{}/index.m3u8", diff --git a/src/frontend/build.sh b/src/frontend/build.sh index 33577ae..81b4485 100755 --- a/src/frontend/build.sh +++ b/src/frontend/build.sh @@ -10,3 +10,4 @@ set -e export RUST_LOG=info denobuild ./mastodon_share_button.tsx ../../static/js/mastodon_share_button.js denobuild ./wasiterm.tsx ../../static/js/wasiterm.js +denobuild ./stories.tsx ../../static/js/stories.js diff --git a/src/frontend/stories.tsx b/src/frontend/stories.tsx new file mode 100644 index 0000000..cb52439 --- /dev/null +++ b/src/frontend/stories.tsx @@ -0,0 +1,119 @@ +import { g, u, x } from "xeact"; + +type Story = { + steps: Step[], +}; + +type Step = { + file: string, + title: string, + text: string, +}; + +const init = async (elemID: string, story: string) => { + let root = g(elemID); + x(root); + let resp = await fetch(u(`/static/${story}.json`)); + if (!resp.ok) { + root.appendChild(<div> + <big>Oopsie-whoopsie!</big> + <p>Oopsie-whoopsie uwu we made a fucky-wucky! A wittle fucko boingo! The code monkeys at our headquarters are working reawy hard to fix this!</p> + <code> + Wanted response to be ok, but unexpectedly got: {resp.status} + </code> + </div>); + return; + } + + let data: Story = await resp.json(); + console.log(data); + + const steps = data.steps.map(s => { + console.log(s); + //<article class="story" style="--bg: url(https://picsum.photos/480/840);"></article> + const style = `--bg: url(https://cdn.xeiaso.net/file/christine-static/stories/${story}/${s.file}.jpg)`; + console.log(style); + const result = <article class="story" style={style}> + <br /> + <br /> + <center><div class="wordart superhero"><span class="text">{s.title}</span></div></center> + <br /> + <br /> + <div class="story-text text box">{s.text}</div> + </article>; + console.log(result.style.cssText); + + result.style.cssText = result.style.cssText.replace("\\", ""); + console.log(result.style.cssText); + + return result; + }); + + const stories = <div class="stories"> + <section class="user"> + {steps} + </section> + </div>; + + root.appendChild(stories); + + const median = stories.offsetLeft + (stories.clientWidth / 2); + const state = { + current_story: stories?.firstElementChild?.lastElementChild, + }; + + const navigateStories = (direction: "next" | "prev") => { + const story = state.current_story; + const lastItemInUserStory = story?.parentNode?.firstElementChild; + const firstItemInUserStory = story?.parentNode?.lastElementChild; + const hasNextUserStory = story?.parentElement?.nextElementSibling; + const hasPrevUserStory = story?.parentElement?.previousElementSibling; + + if (direction === "next") { + if (lastItemInUserStory === story && !hasNextUserStory) return; + else if (lastItemInUserStory === story && hasNextUserStory) { + state.current_story = + story.parentElement.nextElementSibling.lastElementChild; + story?.parentElement.nextElementSibling.scrollIntoView({ + behavior: "smooth", + }); + } else { + story?.classList.add("seen"); + state.current_story = story?.previousElementSibling; + } + } else if (direction === "prev") { + if (firstItemInUserStory === story && !hasPrevUserStory) return; + else if (firstItemInUserStory === story && hasPrevUserStory) { + state.current_story = + story.parentElement.previousElementSibling.firstElementChild; + story.parentElement.previousElementSibling.scrollIntoView({ + behavior: "smooth", + }); + } else { + story?.nextElementSibling?.classList.remove("seen"); + state.current_story = story?.nextElementSibling; + } + } + + console.log(state.current_story.innerText); + }; + + root.addEventListener("click", (e) => { + if (!(e.target instanceof HTMLElement)) { + return; + } + if (e.target?.nodeName !== "ARTICLE") { + return; + } + + navigateStories(e.clientX > median ? "next" : "prev"); + }); + + document.addEventListener("keydown", ({ key }) => { + if (key === "ArrowDown" || key === "ArrowUp") { + navigateStories(key === "ArrowDown" ? "next" : "prev"); + } + }); +}; + +export { init }; diff --git a/static/unwrapped-2022.json b/static/unwrapped-2022.json new file mode 100644 index 0000000..80caef6 --- /dev/null +++ b/static/unwrapped-2022.json @@ -0,0 +1,25 @@ +{ + "name": "unwrapped-2022", + "steps": [ + { + "file": "title", + "text": "The last year all wrapped up!", + "title": "Xesite 2022" + }, + { + "file": "posts", + "text": "Xe wrote $NUMBER posts this year!", + "title": "Blogposts" + }, + { + "file": "talks", + "text": "Xe gave 4 talks this year! Which one was your favorite?", + "title": "Talks" + }, + { + "file": "commits", + "text": "There were 340 commits to Xesite this year!", + "title": "340 commits" + } + ] +} |
