This commit is contained in:
Christofer 2023-08-17 16:45:47 +02:00
parent 0d85f7b54d
commit bfd6e0e968
27 changed files with 696 additions and 296 deletions

View File

@ -56,6 +56,7 @@
"interactjs": "^1.10.18", "interactjs": "^1.10.18",
"prettier-plugin-tailwindcss": "^0.4.1", "prettier-plugin-tailwindcss": "^0.4.1",
"remeda": "^1.24.0", "remeda": "^1.24.0",
"rxjs": "^7.8.1",
"simplex-noise": "^4.0.1", "simplex-noise": "^4.0.1",
"svelte-inview": "^4.0.1", "svelte-inview": "^4.0.1",
"ts-pattern": "^5.0.4" "ts-pattern": "^5.0.4"

View File

@ -26,6 +26,9 @@ dependencies:
remeda: remeda:
specifier: ^1.24.0 specifier: ^1.24.0
version: 1.24.0 version: 1.24.0
rxjs:
specifier: ^7.8.1
version: 7.8.1
simplex-noise: simplex-noise:
specifier: ^4.0.1 specifier: ^4.0.1
version: 4.0.1 version: 4.0.1
@ -2147,6 +2150,12 @@ packages:
queue-microtask: 1.2.3 queue-microtask: 1.2.3
dev: true dev: true
/rxjs@7.8.1:
resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==}
dependencies:
tslib: 2.6.1
dev: false
/sade@1.8.1: /sade@1.8.1:
resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==}
engines: {node: '>=6'} engines: {node: '>=6'}
@ -2520,7 +2529,6 @@ packages:
/tslib@2.6.1: /tslib@2.6.1:
resolution: {integrity: sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==} resolution: {integrity: sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==}
dev: true
/tsutils@3.21.0(typescript@5.1.6): /tsutils@3.21.0(typescript@5.1.6):
resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}

View File

@ -1,3 +1,4 @@
/* eslint-disable no-useless-escape */
import { inview } from 'svelte-inview' import { inview } from 'svelte-inview'
import { pick } from 'remeda' import { pick } from 'remeda'
// const mappingAnimate = { // const mappingAnimate = {
@ -19,6 +20,9 @@ import { pick } from 'remeda'
* @returns * @returns
*/ */
export function animateIn(node, options) { export function animateIn(node, options) {
// Do nothing on mobile
if (getIsMobile()) return { destroy: () => undefined }
const observer = inview(node, { unobserveOnEnter: true, threshold: options.threshold ?? 0.4 }) const observer = inview(node, { unobserveOnEnter: true, threshold: options.threshold ?? 0.4 })
options.duration ??= 840 options.duration ??= 840
@ -73,3 +77,44 @@ export function animateIn(node, options) {
export function lerp(start, end, given) { export function lerp(start, end, given) {
return (1 - given) * start + given * end return (1 - given) * start + given * end
} }
/**
* @param {number} t A number between 0 and 1
* @param {number | undefined} strength
*/
export function easeInT(t, strength) {
return t ** (strength ?? 2)
}
/**
* @param {number} t A number between 0 and 1
* @param {number | undefined} strength
*/
export function easeOutT(t, strength) {
return 1 - (1 - t ** (strength ?? 2))
}
// easeOutT(0.5) //?
// easeOutT(0.99) //?
// easeOutT(0.2) //?
// easeOutT(0) //?
// easeOutT(1) //?
/**
* Taken from https://stackoverflow.com/questions/11381673/detecting-a-mobile-browser/11381730#11381730
*/
export function getIsMobile() {
let check = false
;(function (a) {
if (
/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(
a
) ||
/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(
a.substr(0, 4)
)
)
check = true
})(navigator.userAgent || navigator.vendor || window.opera)
return check
}

View File

@ -4,10 +4,10 @@
/** @type {[string, string, string, string]} */ /** @type {[string, string, string, string]} */
let developers = [ let developers = [
['Fufexan', 'Supporting Developer', 'cyan', 'https://github.com/fufexan'], ['Fufexan', 'Core Developer', 'cyan', 'https://github.com/fufexan'],
['VDawg', 'Webdesign-and dev', 'teal', 'https://github.com/Visual-Dawg'], ['NotAShelf', 'Core Member', 'teal', 'https://github.com/NotAShelf'],
['System-x64', 'Webdev', 'green', 'https://github.com/System-x64'], ['VDawg', 'Webdesign-and dev', 'green', 'https://github.com/Visual-Dawg'],
['That one calculator', 'Package Maintaner', 'lime', 'https://github.com/ThatOneCalculator'] ['System-x64', 'Webdev', 'lime', 'https://github.com/System-x64']
] ]
function createRole(role, color) { function createRole(role, color) {
return `<span class='text-${color}-500'><span class='text-${color}-600'>[ </span>${role}<span class='text-${color}-600'> ]</span></span>` return `<span class='text-${color}-500'><span class='text-${color}-600'>[ </span>${role}<span class='text-${color}-600'> ]</span></span>`
@ -15,13 +15,13 @@
</script> </script>
<footer <footer
class="bg-black/50 mt-16 md:mt-24 lg:mt-32 border-t border-blue-500 relative flex items-center justify-center w-screen" class="bg-black/50 mt-16 md:mt-24 lg:mt-32 border-t border-blue-400/50 relative flex items-center justify-center max-w-screen"
> >
<div <div
class="flex flex-wrap gap-12 justify-between px-8 py-14 max-w-5xl text-slate-300 items-start" class="flex flex-wrap gap-12 justify-between px-8 py-14 max-w-5xl text-slate-300 items-start"
> >
<div class="flex flex-col gap-4"> <div class="flex flex-col gap-4 rounded-lg">
<div class="text-cyan-600 text-sm uppercase font-bold">> Developers</div> <div class="text-slate-400 text-sm uppercase font-bold">Developers</div>
<ul class="flex flex-col gap-3 font-medium"> <ul class="flex flex-col gap-3 font-medium">
<li> <li>
<a href="https://github.com/vaxerski"> <a href="https://github.com/vaxerski">
@ -37,26 +37,26 @@
</li> </li>
{/each} {/each}
<li> <li>
and our <a href="https://github.com/hyprwm/Hyprland/graphs/contributors" target="_blank" <a href="https://github.com/hyprwm/Hyprland/graphs/contributors" target="_blank"
><span class="text-indigo-400">fellow contributors</span></a >and our <span class="text-indigo-400">fellow contributors</span></a
> >
</li> </li>
</ul> </ul>
</div> </div>
<div class="flex flex-col gap-4"> <div class="flex flex-col gap-4">
<div class="text-cyan-600 font-bold text-sm uppercase">Links</div> <div class="text-slate-400 font-bold text-sm uppercase">Links</div>
<ul class="flex flex-col font-medium gap-3"> <ul class="flex flex-col font-medium gap-3">
<li><a href="wiki.hyprland.org/">Wiki</a></li> <li><a href="https://wiki.hyprland.org/">Wiki</a></li>
<li> <li>
<a href="https://wiki.hyprland.org/Getting-Started/Master-Tutorial/">Get started</a> <a href="https://wiki.hyprland.org/Getting-Started/Master-Tutorial/">Get started</a>
</li> </li>
<li>Hall of fame</li> <li><a href="/wall_of_fame">Hall of fame</a></li>
</ul> </ul>
</div> </div>
<div class="flex flex-col gap-4"> <div class="flex flex-col gap-4">
<div class="text-cyan-600 text-sm uppercase font-bold" font-bold>Socials</div> <div class="text-slate-400 text-sm uppercase font-bold" font-bold>Socials</div>
<ul class="flex gap-6"> <ul class="flex gap-6">
<li class=""> <li class="">
<a <a
@ -72,7 +72,7 @@
</ul> </ul>
</div> </div>
<div class="flex gap-4 flex-wrap text-sm text-slate-300 w-full"> <div class="flex gap-4 flex-wrap text-sm text-slate-400 font-medium w-full">
<div>Hyprland is licensed under the BSD 3-Clause "New" or "Revised" License.</div> <div>Hyprland is licensed under the BSD 3-Clause "New" or "Revised" License.</div>
<div>© Hyprland Development 2023.</div> <div>© Hyprland Development 2023.</div>
<div>Doki doki waku waku.</div> <div>Doki doki waku waku.</div>
@ -90,7 +90,7 @@
position: absolute; position: absolute;
top: -450px; top: -450px;
left: 0px; left: 0px;
width: 100vw; width: 100%;
height: 900px; height: 900px;
z-index: -10; z-index: -10;
background: radial-gradient(105vw 450px at 50% 50%, theme(colors.blue.600 / 80%), transparent); background: radial-gradient(105vw 450px at 50% 50%, theme(colors.blue.600 / 80%), transparent);

View File

@ -0,0 +1,64 @@
<script>
import { easeOutT, lerp } from '$lib/Helper.mjs'
import { createNoise2D } from 'simplex-noise'
import { onMount } from 'svelte'
/** Lifespan in milliseconds */
export let lifeSpan = 1500
export let maxSpeed = 20
export let minSpeed = 4
export let maxOpacity = 1
export let scale = 1
const isDescending = Math.random() > 0.8
const wobbliness = lerp(0.0001, 0.004, Math.random())
const speed = Math.random() * (maxSpeed - minSpeed) + minSpeed
let x = Math.random() * 30 - 30
let y = Math.random() * 2
let lifeRemaining = lifeSpan
$: lifePercentage = lifeRemaining / lifeSpan
let timestamp = Date.now()
const noiseY = createNoise2D()
const noiseX = createNoise2D()
const colors = ['#0e4429', '#006d32', '#26a641', '#39d353']
const color = colors.at(Math.ceil(colors.length * Math.random()))
onMount(() => {
let animationId
let i = 0
animate()
async function animate() {
const deltaTime = (timestamp - Date.now()) / 17 // One frame should last roughly 17ms for 60fps
x += noiseX(i, 1) * speed * deltaTime * easeOutT(lifePercentage)
y += noiseY(i, 1) * speed * deltaTime * easeOutT(lifePercentage)
i += wobbliness * deltaTime
lifeRemaining -= Date.now() - timestamp
timestamp = Date.now()
if (lifeRemaining <= -1) return
animationId = requestAnimationFrame(animate)
}
return () => cancelAnimationFrame(animationId)
})
</script>
<div
class="absolute w-6 h-6 rounded-md"
style:translate={`${x}px ${y}px`}
style:background={color}
style:opacity={(lifeRemaining / lifeSpan - (1 - maxOpacity)) ** 5}
style:scale={isDescending ? (lifeRemaining / lifeSpan - (1 - scale)) ** 2 : undefined}
style:top={50 + (Math.random() * 5 - 5) + '%'}
style:left={50 + (Math.random() * 5 - 5) + '%'}
></div>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 515.34 673.26">
<defs>
<style>
.cls-1 {
mix-blend-mode: difference;
}
.cls-2 {
isolation: isolate;
}
.cls-3 {
fill: url(#linear-gradient);
}
</style>
<linearGradient id="linear-gradient" x1="8.93" y1="572.38" x2="572.68" y2="102.08" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#00a2f8"/>
<stop offset="1" stop-color="#00e5cf"/>
</linearGradient>
</defs>
<g class="cls-2">
<g id="Layer_2" data-name="Layer 2">
<g id="Layer_1-2" data-name="Layer 1">
<g class="cls-1">
<path class="cls-3" d="m288.53,0c1.99,2.11,3.26,3.13,4.14,4.42,15.97,23.63,31.7,47.44,47.91,70.91,9.33,13.51,19.26,26.61,29.22,39.67,9.63,12.65,19.8,24.88,29.44,37.53,11.15,14.63,22.45,29.18,32.81,44.36,13.27,19.45,26.64,38.94,38.12,59.44,9.76,17.43,17.56,36.05,25.02,54.64,5.28,13.16,8.82,27.06,12.6,40.78,1.75,6.36,2.24,13.07,3.26,19.62,1.26,8.02,3.4,16.04,3.53,24.08.35,20.94,2.17,41.95-1.48,62.8-4.02,22.99-10.75,45-20.76,66.23-10.12,21.45-22.38,41.26-37.39,59.59-13.6,16.61-29.57,30.33-46.84,42.91-12.68,9.23-26.09,17.07-40.36,23.3-12.84,5.6-26.07,10.09-39.69,13.89-30.75,8.56-61.93,10.44-93.33,8.23-18.93-1.33-38.08-3.65-56.11-10.46-14.82-5.6-29.75-11.13-43.92-18.13-11.19-5.52-21.91-12.44-31.73-20.15-12.88-10.11-25.52-20.81-36.67-32.74-9.99-10.68-18.64-22.87-26.4-35.31-8.18-13.13-15.39-27.01-21.58-41.2-6.69-15.32-11.01-31.45-14.53-47.97-5.48-25.71-3.71-51.44-2.59-77.09.64-14.73,4.53-29.47,8.26-43.86,3.93-15.18,8.68-30.26,14.44-44.84,5.77-14.6,12.47-28.96,20.14-42.65,9.63-17.18,20.25-33.85,31.2-50.23,9.94-14.88,20.68-29.24,31.47-43.52,8.69-11.5,18.17-22.41,26.97-33.83,8.9-11.55,17.46-23.36,26.07-35.13,9.11-12.46,18.29-24.87,27.09-37.55,11.16-16.07,21.91-32.43,32.97-48.57,1.58-2.31,3.88-4.14,5.84-6.19.39.22.78.44,1.18.66.08,1.77.23,3.54.23,5.31.01,26.33.15,52.66-.17,78.99-.05,3.86-1.62,8.15-3.72,11.46-8.5,13.45-17.19,26.8-26.38,39.79-8.71,12.31-18.12,24.13-27.22,36.16-7.5,9.91-14.97,19.83-22.52,29.7-5.24,6.85-10.74,13.5-15.86,20.44-7.16,9.72-14.35,19.45-21.03,29.5-8.06,12.12-15.99,24.36-23.23,36.97-5.18,9.02-9.26,18.69-13.59,28.17-2.4,5.26-4.61,10.64-6.36,16.14-3.1,9.76-5.58,19.71-8.68,29.47-8.72,27.42-6.87,55.63-4.92,83.5.99,14.15,6.11,28.15,10.4,41.89,6.01,19.24,16.32,36.3,27.95,52.74,7.94,11.23,16.95,21.38,27.14,30.36,8.39,7.38,17.5,14.17,27.07,19.92,10.89,6.54,22.23,12.77,34.12,17.07,12.69,4.59,26.1,7.99,39.48,9.68,15.93,2.01,32.16,1.58,48.25,2.34,14.94.7,29.43-2.29,43.93-5.14,18.41-3.62,35.23-11.56,51.58-20.26,19.55-10.4,35.98-25.13,50.37-41.73,14.71-16.97,27.06-36.05,34.92-57,8.29-22.1,15.2-44.97,14.15-69.26-.57-13.13.15-26.34-1.06-39.39-.89-9.61-3.62-19.11-6.16-28.5-2.98-11.03-6.03-22.1-10.16-32.73-4.11-10.59-9.36-20.75-14.52-30.9-4.57-8.99-9.32-17.92-14.66-26.46-6.5-10.39-13.38-20.59-20.68-30.43-11.05-14.9-22.74-29.32-33.91-44.12-13.08-17.33-26.13-34.68-38.77-52.33-10.91-15.22-21.31-30.81-31.71-46.39-1.67-2.5-3-5.79-3.03-8.72-.23-28.49-.15-56.98-.13-85.47,0-.95.24-1.91.58-4.44Z"/>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
src/lib/images/vaxry-github.webp Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

View File

@ -6,12 +6,10 @@
import '@fontsource/ibm-plex-mono/500.css' import '@fontsource/ibm-plex-mono/500.css'
</script> </script>
<div class="flex flex-col min-h-screen overflow-x-hidden"> <Navbar />
<Navbar />
<main class="mx-auto w-full flex flex-col"> <main class="mx-auto w-full overflow-hidden flex flex-col">
<slot /> <slot />
</main> </main>
<Footer /> <Footer />
</div>

View File

@ -1,7 +1,7 @@
<script> <script>
import Community from './CommunitySlice.svelte' import Community from './CommunitySlice.svelte'
import FeaturesSlice from './FeaturesSlice.svelte' import FeaturesSlice from './FeaturesSlice.svelte'
import HallOfFameSlice from './HallOfFameSlice.svelte' import WallOfFameSlice from './WallOfFameSlice.svelte'
import Hero from './Hero.svelte' import Hero from './Hero.svelte'
import InstallSlice from './InstallSlice.svelte' import InstallSlice from './InstallSlice.svelte'
import PreviewRiceSlice from './PreviewRiceSlice.svelte' import PreviewRiceSlice from './PreviewRiceSlice.svelte'
@ -15,11 +15,11 @@
<Hero /> <Hero />
<div class="-mt-8 gap-20 md:gap-[16rem] flex flex-col items-center"> <div class="-mt-8 gap-20 md:gap-[16rem] flex flex-col items-center">
<PreviewRiceSlice class="mb-52" /> <PreviewRiceSlice class="mb-12" />
<FeaturesSlice /> <FeaturesSlice />
<HallOfFameSlice /> <WallOfFameSlice />
<Community /> <Community />

View File

@ -58,10 +58,10 @@
class: 'outline-slate-200' class: 'outline-slate-200'
}, },
{ {
image: '/imgs/profile_pictures/outfoxxed.webp', image: '/imgs/profile_pictures/kcrmson.webp',
coordinates: [53, 399], coordinates: [53, 399],
size: 75, size: 75,
class: 'outline-orange-500' class: 'outline-sky-500'
}, },
{ {
image: '/imgs/profile_pictures/loseardes77.gif', image: '/imgs/profile_pictures/loseardes77.gif',
@ -107,14 +107,14 @@
image: '/imgs/profile_pictures/7.webp', image: '/imgs/profile_pictures/7.webp',
coordinates: [273, 687], coordinates: [273, 687],
size: 52, size: 52,
quote: '"Meds"', quote: '"meds"',
class: 'outline-cyan-500' class: 'outline-cyan-500'
}, },
{ {
image: '/imgs/profile_pictures/kcrmson.webp', image: '/imgs/profile_pictures/outfoxxed.webp',
coordinates: [648, 364], coordinates: [648, 364],
size: 80, size: 80,
class: 'outline-sky-500' class: 'outline-orange-500'
}, },
{ {
image: '/imgs/profile_pictures/kirottum.webp', image: '/imgs/profile_pictures/kirottum.webp',
@ -235,9 +235,9 @@
width: 9rem; width: 9rem;
height: 9rem; height: 9rem;
transition: transition:
rotate 480ms cubic-bezier(0.5, 0, 0.5, 1.5), rotate 480ms cubic-bezier(0.5, 0, 0.5, 1.1),
scale 440ms cubic-bezier(1, -1.4, 0, 2), scale 420ms cubic-bezier(1, 0.1, 0, 2),
filter 240ms; filter 840ms;
filter: drop-shadow(0px 0px 0px cyan) drop-shadow(0px 0px 0px blue); filter: drop-shadow(0px 0px 0px cyan) drop-shadow(0px 0px 0px blue);
&:hover, &:hover,

View File

@ -1,106 +0,0 @@
<script>
import { spring } from 'svelte/motion';
let count = 0;
const displayed_count = spring();
$: displayed_count.set(count);
$: offset = modulo($displayed_count, 1);
/**
* @param {number} n
* @param {number} m
*/
function modulo(n, m) {
// handle negative numbers
return ((n % m) + m) % m;
}
</script>
<div class="counter">
<button on:click={() => (count -= 1)} aria-label="Decrease the counter by one">
<svg aria-hidden="true" viewBox="0 0 1 1">
<path d="M0,0.5 L1,0.5" />
</svg>
</button>
<div class="counter-viewport">
<div class="counter-digits" style="transform: translate(0, {100 * offset}%)">
<strong class="hidden" aria-hidden="true">{Math.floor($displayed_count + 1)}</strong>
<strong>{Math.floor($displayed_count)}</strong>
</div>
</div>
<button on:click={() => (count += 1)} aria-label="Increase the counter by one">
<svg aria-hidden="true" viewBox="0 0 1 1">
<path d="M0,0.5 L1,0.5 M0.5,0 L0.5,1" />
</svg>
</button>
</div>
<style>
.counter {
display: flex;
border-top: 1px solid rgba(0, 0, 0, 0.1);
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
margin: 1rem 0;
}
.counter button {
width: 2em;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
border: 0;
background-color: transparent;
touch-action: manipulation;
font-size: 2rem;
}
.counter button:hover {
background-color: var(--color-bg-1);
}
svg {
width: 25%;
height: 25%;
}
path {
vector-effect: non-scaling-stroke;
stroke-width: 2px;
stroke: #444;
}
.counter-viewport {
width: 8em;
height: 4em;
overflow: hidden;
text-align: center;
position: relative;
}
.counter-viewport strong {
position: absolute;
display: flex;
width: 100%;
height: 100%;
font-weight: 400;
color: var(--color-theme-1);
font-size: 4rem;
align-items: center;
justify-content: center;
}
.counter-digits {
position: absolute;
width: 100%;
height: 100%;
}
.hidden {
top: -100%;
user-select: none;
}
</style>

View File

@ -1,11 +1,9 @@
<script> <script>
import { json } from '@sveltejs/kit'
import clsx from 'clsx' import clsx from 'clsx'
import interact from 'interactjs'
import { createEventDispatcher, getContext, onMount } from 'svelte' import { createEventDispatcher, getContext, onMount } from 'svelte'
import { spring } from 'svelte/motion' import { spring } from 'svelte/motion'
import { contextId } from './CommunitySlice.svelte' import { contextId as ctxId } from './CommunitySlice.svelte'
import { lerp } from '$lib/Helper.mjs' import { getIsMobile, lerp } from '$lib/Helper.mjs'
import { inview } from 'svelte-inview' import { inview } from 'svelte-inview'
/** @type {string} */ /** @type {string} */
@ -20,6 +18,10 @@
/** @type {string | undefined} */ /** @type {string | undefined} */
export let quote = undefined export let quote = undefined
/** @type {symbol}*/
export let contextId = ctxId
export let isAnimating = true
const { biggestSize, getSectionElement } = getContext(contextId) const { biggestSize, getSectionElement } = getContext(contextId)
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
@ -36,33 +38,39 @@
let hasEnteredView = false let hasEnteredView = false
onMount(() => { onMount(() => {
let interactionjs = interact(imageElement).draggable({ if (getIsMobile()) return
inertia: { resistance: lerp(5, 200, relativeSize) },
listeners: {
move({ dx, dy }) {
dragCoordinates.update(([x, y]) => {
x += dx
y += dy
return [x, y]
})
},
start(event) { let interactionjs
dispatch('dragStart', event)
import('interactjs').then(({ default: interact }) => {
interactionjs = interact(imageElement).draggable({
inertia: { resistance: lerp(5, 200, relativeSize) },
listeners: {
move({ dx, dy }) {
dragCoordinates.update(([x, y]) => {
x += dx
y += dy
return [x, y]
})
},
start(event) {
dispatch('dragStart', event)
},
end(event) {
dispatch('dragEnd', event)
}
}, },
end(event) { modifiers: [
dispatch('dragEnd', event) interact.modifiers.restrictRect({
} restriction: getSectionElement,
}, endOnly: true
modifiers: [ })
interact.modifiers.restrictRect({ ]
restriction: getSectionElement, })
endOnly: true
})
]
}) })
return () => interactionjs.off() return () => interactionjs?.off?.()
}) })
</script> </script>
@ -72,10 +80,13 @@
style="width: {size}px; height: {size}px;--delay: {delay}ms;" style="width: {size}px; height: {size}px;--delay: {delay}ms;"
> >
<div <div
class="absolute inset-0 w-full h-full group opacity-0 select-none touch-none" class={clsx(
'absolute inset-0 w-full h-full group select-none touch-none',
isAnimating && 'opacity-0'
)}
style:translate={`calc( ${$dragCoordinates[0]}px ) ${$dragCoordinates[1]}px`} style:translate={`calc( ${$dragCoordinates[0]}px ) ${$dragCoordinates[1]}px`}
use:inview={{ unobserveOnEnter: true, threshold: 0.4 }} use:inview={{ unobserveOnEnter: true, threshold: 0.4 }}
class:_animate={hasEnteredView} class:_animate={isAnimating && hasEnteredView}
on:inview_enter={() => setTimeout(() => (hasEnteredView = true), 750)} on:inview_enter={() => setTimeout(() => (hasEnteredView = true), 750)}
> >
<img <img

View File

@ -16,7 +16,7 @@
<img <img
src={image} src={image}
alt="Rice desktop" alt="Rice desktop"
class="w-full nice-hover object-cover object-top rounded-xl overflow-hidden shadow-2xl hover:scale-[1.01] {imageClass}" class="max-sm:[xmask-image:none] w-full nice-hover object-cover object-top rounded-xl overflow-hidden shadow-2xl hover:scale-[1.01] {imageClass}"
/> />
<img src={image} alt="Rice desktop" aria-hidden="true" class="rice-bg" /> <img src={image} alt="Rice desktop" aria-hidden="true" class="rice-bg" />
</div> </div>
@ -30,7 +30,7 @@
transition: all 540ms cubic-bezier(0.1, -0.81, 0.31, 2); transition: all 540ms cubic-bezier(0.1, -0.81, 0.31, 2);
} }
.rice-bg { .rice-bg {
@apply w-[calc(100%-24px)] pointer-events-none transition-[filter] duration-500 absolute left-3 brightness-150 rounded-3xl -z-10 saturate-[5] h-full blur-2xl -bottom-10 opacity-50; @apply pointer-events-none absolute -bottom-10 left-3 -z-10 h-full w-[calc(100%-24px)] rounded-3xl opacity-50 blur-2xl brightness-150 saturate-[5] transition-[filter] duration-500 max-sm:hidden;
.rice:hover & { .rice:hover & {
@apply brightness-200; @apply brightness-200;

View File

@ -1,9 +1,9 @@
<script> <script>
import clsx from 'clsx' import clsx from 'clsx'
import { getContext } from 'svelte' import { getContext, onMount } from 'svelte'
import { mouseContext } from './FeaturesSlice.svelte' import { mouseContext } from './FeaturesSlice.svelte'
import { spring } from 'svelte/motion' import { spring } from 'svelte/motion'
import Title from '$lib/components/Title.svelte' import { getIsMobile } from '$lib/Helper.mjs'
export let title export let title
export let color = 'cyan' export let color = 'cyan'
@ -11,6 +11,8 @@
/** @type HTMLDivElement */ /** @type HTMLDivElement */
let container let container
let isMobile = false
const fillX = spring(999, { damping: 0.9, stiffness: 0.021, precision: 0.3 }) const fillX = spring(999, { damping: 0.9, stiffness: 0.021, precision: 0.3 })
const fillY = spring(999, { damping: 0.9, stiffness: 0.021, precision: 0.3 }) const fillY = spring(999, { damping: 0.9, stiffness: 0.021, precision: 0.3 })
const borderX = spring(999, { damping: 0.9, stiffness: 0.03, precision: 0.3 }) const borderX = spring(999, { damping: 0.9, stiffness: 0.03, precision: 0.3 })
@ -27,7 +29,13 @@
} }
} }
onMount(() => {
isMobile = getIsMobile()
})
function updateGradient() { function updateGradient() {
if (isMobile) return
const { x: rectX, y: rectY, width, height } = container.getBoundingClientRect() const { x: rectX, y: rectY, width, height } = container.getBoundingClientRect()
const normX = $mouseX - rectX const normX = $mouseX - rectX
@ -55,7 +63,7 @@
</script> </script>
<div <div
class={clsx('card min-h-[20rem] ', $$restProps.class)} class={clsx('card min-h-[20rem] group', $$restProps.class)}
style:--x={$fillX} style:--x={$fillX}
style:--y={$fillY} style:--y={$fillY}
style:--borderX={$borderX} style:--borderX={$borderX}
@ -70,19 +78,19 @@
class:purpleGradient={color === 'purple'} class:purpleGradient={color === 'purple'}
role="contentinfo" role="contentinfo"
> >
<div class="p-8 md:p-12 z-10 w-full h-full"> <div class="p-8 sm:p-12 z-10 w-full h-full flex flex-col justify-end">
<h1 class="text-5xl font-bold mb-6 text-white">{title}</h1> <h1 class="text-5xl font-bold mb-6 text-white">{title}</h1>
<slot>Nothing in the slot here</slot> <slot>Nothing in the slot here</slot>
</div> </div>
<div class="gradient" /> <div class="gradient max-sm:hidden" />
<div class="gradient_black" /> <div class="gradient_black max-sm:hidden" />
<div class="border-gradient" /> <div class="border-gradient max-sm:hidden" />
</div> </div>
<style lang="postcss"> <style lang="postcss">
.card { .card {
@apply relative flex h-full w-full items-center justify-center rounded-3xl bg-slate-900 transition-colors duration-300 hover:bg-blue-900; @apply relative flex h-full w-full items-end justify-end rounded-3xl bg-slate-950 transition-colors duration-300 md:bg-slate-900 md:hover:bg-blue-900;
z-index: 2; z-index: 2;
contain: paint style layout; contain: paint style layout;
} }
@ -114,6 +122,7 @@
top: 0%; top: 0%;
content: ''; content: '';
pointer-events: none; pointer-events: none;
filter: brightness(1.2) saturate(2);
contain: strict; contain: strict;
background: radial-gradient( background: radial-gradient(
320px circle at calc(var(--borderX) * 1px) calc(var(--borderY) * 1px), 320px circle at calc(var(--borderX) * 1px) calc(var(--borderY) * 1px),
@ -149,6 +158,7 @@
translate: -25% 0%; translate: -25% 0%;
transform-origin: top left; transform-origin: top left;
left: 50%; left: 50%;
opacity: 0%;
transition: all 820ms; transition: all 820ms;
content: ''; content: '';
pointer-events: none; pointer-events: none;
@ -162,6 +172,10 @@
.card:hover & { .card:hover & {
scale: 1 1; scale: 1 1;
} }
.group:hover & {
opacity: 100%;
}
} }
} }

View File

@ -4,18 +4,16 @@
<script> <script>
import FeatureCard from './FeatureCard.svelte' import FeatureCard from './FeatureCard.svelte'
import { setContext } from 'svelte' import { setContext, onMount } from 'svelte'
import { writable } from 'svelte/store' import { writable } from 'svelte/store'
import PluginsIcon from '~icons/gg/arrange-back' import PluginsIcon from '~icons/gg/arrange-back'
import ActiveGitIcon from '~icons/gg/git-branch'
import ShortcutsIcon from '~icons/gg/push-chevron-right-o' import ShortcutsIcon from '~icons/gg/push-chevron-right-o'
import BleedingEdgeIcon from '~icons/gg/controller' import BleedingEdgeIcon from '~icons/gg/controller'
import Title from '$lib/components/Title.svelte' import Title from '$lib/components/Title.svelte'
import Hypractive from './Hypractive.svelte'
import { getIsMobile } from '$lib/Helper.mjs'
/** let isMobile = false
* type {{name: string, github: string}}
*/
let createdBy
const context = setContext(mouseContext, { const context = setContext(mouseContext, {
x: writable(0), x: writable(0),
@ -26,6 +24,10 @@
/** @type HTMLDivElement */ /** @type HTMLDivElement */
let featuresContainer let featuresContainer
onMount(() => {
isMobile = getIsMobile()
})
function onMouseEnter() { function onMouseEnter() {
featuresContainer.addEventListener('mousemove', trackMouse) featuresContainer.addEventListener('mousemove', trackMouse)
context.isHoverCards.set(true) context.isHoverCards.set(true)
@ -49,41 +51,61 @@
<div <div
class="grid lg:grid-cols-2 lg:grid-rows-2 w-full gap-6 text-lg text-white/70 font-medium flex-wrap group" class="grid lg:grid-cols-2 lg:grid-rows-2 w-full gap-6 text-lg text-white/70 font-medium flex-wrap group"
role="contentinfo" role="contentinfo"
on:mouseenter={onMouseEnter} on:mouseenter={!isMobile && onMouseEnter}
on:mouseleave={onMouseLeave} on:mouseleave={!isMobile && onMouseLeave}
bind:this={featuresContainer} bind:this={featuresContainer}
> >
<FeatureCard title="Smooth" class="row-span-2"> <FeatureCard title="Smooth" class="row-span-2">
<p> <p class="max-w-[60ch]">
Transition from windows and workspaces smoothly, without abrupt changes. Instant input with Transition from windows and workspaces smoothly, with great animations. High performance.
a custom WSLroot patch included Instant input.
</p></FeatureCard </p></FeatureCard
> >
<FeatureCard title="Easy to configure" color="purple"> <FeatureCard title="Easy to configure" color="purple">
<p> <p class="max-w-[60ch]">
Live reloading config. Easy plain-text format. Sensible defaults. Great documentation. Live reloading config. Easy plain-text format. Sensible defaults. Great documentation.
</p></FeatureCard </p>
>
<div class="absolute _wrapper inset-0 select-none" aria-hidden>
<div
class="absolute text-[440px] -bottom-10 text-slate-500 _configure -right-40 md:right-0 font-mono"
>
{'<>'}
</div>
</div>
</FeatureCard>
<FeatureCard class="" title="Dynamic tiling"> <FeatureCard class="" title="Dynamic tiling">
<p> <p class="max-w-[60ch]">
Automatic tiling which just works. Supports multiple fine-tuneable layouts. Automatic tiling which just works. Supports multiple fine-tuneable layouts.
</p></FeatureCard </p>
> <div class="absolute _wrapper inset-0 select-none" aria-hidden>
<div
class="absolute text-[280px] text-slate-500 font-extrabold gap-y-4 [line-height:1] -z-10 bottom-[20px] tiling right-0 md:right-8 font-mono tiles"
>
<div class="tile" style={''}>[ ]</div>
</div>
</div>
</FeatureCard>
</div> </div>
<div class="mt-14 flex-wrap justify-center flex gap-8"> <div class="mt-14 z-10 flex-wrap justify-center flex sm:flex-row flex-col gap-8">
<div class="icon-feature"> <a
href="https://github.com/hyprland-community/awesome-hyprland#plugins"
target="_blank"
class="icon-feature hover:underline"
>
<PluginsIcon class="h-8 w-8" /> <PluginsIcon class="h-8 w-8" />
Plugin system Plugin system
</div> </a>
<div class="icon-feature"> <Hypractive />
<ActiveGitIcon class="h-8 w-8" /> <a
Hypractive development href="https://wiki.hyprland.org/Configuring/Binds/#global-keybinds"
</div> target="_blank"
<div class="icon-feature"> class="icon-feature hover:underline"
>
<ShortcutsIcon class="h-8 w-8" /> <ShortcutsIcon class="h-8 w-8" />
Global shortcuts for apps Global shortcuts for apps
</div> </a>
<div class="icon-feature"> <div class="icon-feature">
<BleedingEdgeIcon class="h-8 w-8" />Bleeding edge tech <BleedingEdgeIcon class="h-8 w-8" />Bleeding edge tech
</div> </div>
@ -92,6 +114,72 @@
<style lang="postcss"> <style lang="postcss">
.icon-feature { .icon-feature {
@apply flex items-center justify-center gap-3 font-bold opacity-60; @apply flex items-center justify-center gap-3 font-bold text-slate-400;
}
._configure {
@apply bg-gradient-to-tl from-pink-500 to-blue-500 bg-clip-text text-blue-700;
line-height: 1;
z-index: -1;
transition: all 850ms ease-in-out;
color: rgb(255, 121, 170);
opacity: 0.4;
color: transparent;
text-shadow:
10px -10px 40px theme(colors.pink.700 / 20),
5px 5px 20px cyan,
-10px 10px 40px theme(colors.blue.700 / 20);
filter: saturate(2) drop-shadow(8px 8px 20px theme(colors.pink.700))
drop-shadow(-8px -8px 20px theme(colors.blue.700));
._wrapper:hover & {
color: transparent;
opacity: 0.6;
filter: saturate(2) drop-shadow(8px 8px 12px theme(colors.pink.700))
drop-shadow(-8px -8px 12px theme(colors.blue.700));
text-shadow:
15px -15px 40px theme(colors.pink.700 / 80),
8px 8px 20px cyan,
-15px 15px 40px theme(colors.blue.700 / 40);
}
}
.tile {
/* Animate a pulse animation for the glow effect */
/* Use different colors for the different windows */
background: radial-gradient(ellipse, var(--color1, cyan) 50%, var(--color2, magenta));
background-clip: text;
color: transparent;
letter-spacing: -55px;
text-shadow:
-5px 5px 8px color-mix(in srgb, var(--color1, magenta), transparent 90%),
5px -5px 8px color-mix(in srgb, color-mix(in srgb, var(--color1, rgb(0, 187, 255)), black 20%), transparent
10%),
0px 0px 15px var(--color2, magenta);
filter: saturate(1) drop-shadow(8px 8px 24px var(--color2, blue))
drop-shadow(
-8px -8px 24px color-mix(in srgb, var(--color1, rgb(0, 187, 255)), rgba(0, 0, 0, 0.056) 80%)
);
opacity: 0.4;
transition: all 850ms ease-in-out;
._wrapper:hover & {
opacity: 0.7;
text-shadow:
-15px 15px 0px color-mix(in srgb, var(--color1, cyan), transparent 60%),
15px -15px 8px color-mix(in srgb, color-mix(in srgb, var(--colo1r, magenta), rgb(0, 0, 111)
50%), transparent 30%),
0px 0px 15px var(--color2, magenta);
filter: saturate(2) drop-shadow(8px 8px 24px var(--color2, blue))
drop-shadow(
-8px -8px 24px color-mix(in srgb, var(--color1, magenta), rgba(0, 0, 0, 0.056) 20%)
);
}
}
.tiles {
filter: drop-shadow(0px 0px 5px rgb(0, 191, 255));
} }
</style> </style>

View File

@ -3,29 +3,40 @@
import { createNoise2D } from 'simplex-noise' import { createNoise2D } from 'simplex-noise'
import { match } from 'ts-pattern' import { match } from 'ts-pattern'
import clsx from 'clsx' import clsx from 'clsx'
import { getIsMobile } from '$lib/Helper.mjs'
// Idea: Boid behavior // Idea: Boid behavior
const maxSize = 12 const maxSize = 18
const size = Math.max(Math.random() * maxSize, 6) const size = Math.max(Math.random() * maxSize, 6)
/** How much the fireflies can vanish into the edges of the screen. Include their invisible padding for mouse detection. */ /** How much the fireflies can vanish into the edges of the screen. Include their invisible padding for mouse detection. */
const edgeClip = maxSize * 8 const edgeClip = maxSize * 8
const noiseY = createNoise2D() const noiseY = createNoise2D()
const noiseX = createNoise2D() const noiseX = createNoise2D()
const SPEED = Math.random() * 5 + 2
let classes = clsx(Math.random() > 0.5 ? 'bg-primary/70' : 'bg-sky-500/70') let classes = clsx(Math.random() > 0.5 ? 'bg-primary/70' : 'bg-blue-500/70')
let x = 0 let x = 0
let y = 0 let y = 0
// TODO add mouse following behaviour - flock behaviour
// A couple following the mouse throughout the website
onMount(() => { onMount(() => {
x = window.innerWidth / 2 - maxSize * 6 x = window.innerWidth / (Math.random() * 4) - maxSize * 6
y = window.innerHeight / 2 + 100 y = window.innerHeight / (Math.random() * 4) + 100
// The animation is way too heavy for mobile
if (getIsMobile()) return
let animationId let animationId
let i = 0 let i = 0
animate() animate()
return () => cancelAnimationFrame(animationId)
async function animate() { async function animate() {
x += match(x) x += match(x)
.when( .when(
@ -36,7 +47,7 @@
(x) => x < -edgeClip, (x) => x < -edgeClip,
() => 10 () => 10
) )
.otherwise(() => noiseX(i, 1) * 5) .otherwise(() => noiseX(i, 1) * SPEED)
y += match(y) y += match(y)
.when( .when(
(y) => y > window.innerHeight + edgeClip, (y) => y > window.innerHeight + edgeClip,
@ -46,22 +57,22 @@
(y) => y < -edgeClip, (y) => y < -edgeClip,
() => 10 () => 10
) )
.otherwise(() => noiseY(i, 1) * 5) .otherwise(() => noiseY(i, 1) * SPEED)
i += 0.005 i += 0.005
animationId = requestAnimationFrame(animate) animationId = requestAnimationFrame(animate)
} }
return () => cancelAnimationFrame(animationId)
}) })
</script> </script>
<div <div
class="absolute p-24 top-0 left-0 firefly pointer-events-auto opacity-50 hover:opacity-100 transition-opacity z-0" class="absolute hidden max-sm:[contain:strict] md:block p-24 top-0 left-0 firefly pointer-events-auto opacity-50 hover:opacity-100 transition-opacity z-0"
style="--x:{x}px; --y:{y}px;--size:{size}px; --fadeDelay: {Math.random() * 6 - 3}s" style:--x={x + 'px'}
style:--y={y + 'px'}
style="--size:{size}px; --fadeDelay: {Math.random() * 6 - 3}s"
> >
<div class="firefly-inner {classes}" /> <div class={clsx('firefly-inner', classes)} />
</div> </div>
<style lang="postcss"> <style lang="postcss">
@ -72,12 +83,13 @@
} }
.firefly-inner { .firefly-inner {
background-color: theme(colors.sky.400 / 70%);
min-height: var(--size); min-height: var(--size);
min-width: var(--size); min-width: var(--size);
border-radius: 50%; border-radius: 50%;
contain: layout; contain: layout size style;
box-shadow: 0px 0px 25px theme(colors.emerald.400), 0px 0px 12px theme(colors.sky.400); box-shadow:
0px 0px 25px theme(colors.emerald.400),
0px 0px 12px theme(colors.sky.400);
animation: fade 3s ease-in-out infinite alternate; animation: fade 3s ease-in-out infinite alternate;
animation-delay: var(--fadeDelay); animation-delay: var(--fadeDelay);
} }

View File

@ -1,37 +1,36 @@
<script> <script>
import { getIsMobile } from '$lib/Helper.mjs'
import Button from '$lib/components/Button.svelte' import Button from '$lib/components/Button.svelte'
import Logo from '$lib/images/logo.png' import Logo from '$lib/images/logos/hyprland-color.svg'
import { onMount } from 'svelte'
import Firefly from './Firefly.svelte' import Firefly from './Firefly.svelte'
import { inview } from 'svelte-inview' import { inview } from 'svelte-inview'
let isVisible = true let isVisible = true
let hadBeenInvisble = false let isMobile = false
onMount(() => {
isMobile = getIsMobile()
})
</script> </script>
<section <section
class="w-full relative flex flex-col items-center justify-center min-h-screen h-max" class="w-full relative flex flex-col items-center justify-center min-h-[100svh] overflow-x-hidden h-max"
use:inview use:inview
on:inview_change={({ detail: { inView } }) => { on:inview_change={({ detail: { inView } }) => {
isVisible = inView isVisible = inView
hadBeenInvisble = hadBeenInvisble && inView
}} }}
> >
<!-- Hero text and logo --> <!-- Hero text and logo -->
<div class="flex h-screen min-h-max justify-center flex-col items-center z-10"> <div class="flex h-screen min-h-max justify-center flex-col items-center z-10">
<div class="text-center items-center flex flex-col gap-6 mb-8"> <div class="text-center -mt-20 items-center flex flex-col gap-6 mb-8">
<img src={Logo} alt="Hyprland Logo" class="w-32 mb-4 ani-in fill-mode-backwards" /> <img src={Logo} alt="Hyprland Logo" class="h-36 mb-4 ani-in fill-mode-backwards" />
<div class="relative ani-in fill-mode-backwards [animation-delay:584ms]"> <div class="relative ani-in fill-mode-backwards [animation-delay:584ms]">
<h1 <h1
class="text-7xl p-2 font-bold bg-clip-text text-transparent font-london hyprgradient tracking-wider" class="text-5xl md:text-7xl p-2 font-bold bg-clip-text text-transparent font-london hyprgradient tracking-wider md:tracking-widest"
> >
Hyprland Hyprland
</h1> </h1>
<div
aria-hidden="true"
class="text-7xl top-0 pointer-events-none p-2 font-bold title-shadow absolute font-london tracking-wider -z-10"
>
Hyprland
</div>
</div> </div>
</div> </div>
<h2 <h2
@ -46,22 +45,22 @@
<a href="https://wiki.hyprland.org/Getting-Started/Installation/"> <a href="https://wiki.hyprland.org/Getting-Started/Installation/">
<Button size="lg">Install</Button> <Button size="lg">Install</Button>
</a> </a>
<Button type="fancyOutline" size="lg">Github</Button> <a href="https://wiki.hyprland.org/Getting-Started/">
<Button type="fancyOutline" size="lg">Wiki</Button>
</a>
</div> </div>
</div> </div>
<!-- Fireflies --> <!-- Fireflies -->
{#if isVisible} {#if isVisible}
<div <div
class="absolute animate-in fade-in-0 duration-75 pointer-events-none max-w-screen inset-0 overflow-hidden z-0" class="absolute animate-in fade-in-0 [animation-delay:900ms] [animation-duration:4500ms] fill-mode-backwards pointer-events-none max-w-screen inset-0 overflow-hidden -z-10"
> >
<div class="bg-gradient-to-t from-black z-10 w-full h-52 absolute bottom-0" /> <div class="bg-gradient-to-t from-black z-10 w-full h-52 absolute bottom-0" />
{#await new Promise( (resolve) => setTimeout(() => resolve(), hadBeenInvisble ? 0 : 1440) ) then _} {#each { length: 40 } as _}
{#each { length: 40 } as _} <Firefly />
<Firefly /> {/each}
{/each}
{/await}
</div> </div>
{/if} {/if}
@ -82,7 +81,6 @@
/> />
</div> </div>
</div> </div>
<!-- Gradient background //-->
</section> </section>
<style lang="postcss"> <style lang="postcss">
@ -93,15 +91,6 @@
animation: move var(--duration, 50s) ease-in-out var(--offset, 0ms) infinite alternate both; animation: move var(--duration, 50s) ease-in-out var(--offset, 0ms) infinite alternate both;
} }
.title-shadow {
text-shadow:
8px 9px 32px theme(colors.secondary / 10%),
-8px -9px 32px theme(colors.primary / 20%),
1px 0px 3px theme(colors.purple.500 / 50%),
0px 9px 16px theme(colors.black / 50%);
animate: title_effect 1s ease infinite alternate;
}
@keyframes move { @keyframes move {
0% { 0% {
transform: translate3d( transform: translate3d(
@ -144,6 +133,6 @@
} }
.ani-in { .ani-in {
@apply animate-in ease-in-out slide-in-from-bottom-4 fade-in-0 [animation-duration:800ms]; @apply animate-in fade-in-0 slide-in-from-bottom-4 ease-in-out [animation-duration:800ms];
} }
</style> </style>

183
src/routes/Hypractive.svelte Executable file
View File

@ -0,0 +1,183 @@
<script>
import ActiveGitIcon from '~icons/gg/git-branch'
import VaxryImage from '$lib/images/vaxry-github.webp'
import {
Subject,
interval,
map,
of,
scan,
startWith,
switchMap,
merge,
timer,
timeInterval,
filter,
first,
take
} from 'rxjs'
import GitTile from '$lib/components/GitTile.svelte'
import { lerp } from '$lib/Helper.mjs'
import { cubicInOut, expoInOut } from 'svelte/easing'
import DiscordProfilePicture from './DiscordProfilePicture.svelte'
import { setContext } from 'svelte'
const click$ = new Subject()
const ASCENION_CLICKS = 69
const MAX_LIFESPAN_TILE = 2500
const MIN_LIFESPAN_TILE = 800
const MAX_TILES_PER_CLICK = 15
const MIN_TILES_PER_CLICK = 2
const CLICK_EACH_MS = 400
const ASCENION_FALLOFF = -ASCENION_CLICKS / 20
const clickLevel$ = click$.pipe(
timeInterval(),
filter(({ interval }) => interval < CLICK_EACH_MS),
map(() => 1),
switchMap((value) =>
merge(
of(value),
interval(CLICK_EACH_MS + 100).pipe(
take(ASCENION_CLICKS),
map(() => ASCENION_FALLOFF)
)
)
),
scan((level, value) => Math.min(ASCENION_CLICKS, Math.max(level + value, 0))),
startWith(0)
)
const relativeLevel$ = clickLevel$.pipe(map((clicks) => clicks / ASCENION_CLICKS))
const cubibRelativeLevel$ = relativeLevel$.pipe(map(cubicInOut))
const expoRelativeLevel$ = relativeLevel$.pipe(map(expoInOut))
// const hasAscended$ = of(true)
const hasAscended$ = relativeLevel$.pipe(
filter((level) => level >= 1),
first(),
map(() => true),
startWith(false)
)
// Only emit on mouseUp to prevent emitting when the level decreases due to no user interaction
const tiles$ = click$.pipe(
switchMap(() =>
merge(
of(Math.floor(lerp(MIN_TILES_PER_CLICK, MAX_TILES_PER_CLICK, $cubibRelativeLevel$))),
timer(MAX_LIFESPAN_TILE)
)
),
scan(
(acc, value) => (value === 0 ? [] : [...acc, ...Array.from({ length: value }, () => 1)]),
[]
),
startWith([])
)
$: hue = lerp(200, 130, $cubibRelativeLevel$)
$: scale = lerp(0.9, 2, $cubibRelativeLevel$)
/** @type {HTMLDivElement} */
let containerElement
const vaxrySize = 220
const contextId = Symbol('hypractive context')
setContext(contextId, {
biggestSize: vaxrySize * 1.2, // Make it lighter to drag
getSectionElement: () => containerElement
})
function onClick() {
click$.next(1)
}
</script>
<div class="relative overflow-visible">
<button
class="flex hover:underline text-slate-400 gap-3 font-bold items-center active:scale-95 transition-colors drop-shadow-lg shadow-black"
on:click={onClick}
style:color={$relativeLevel$ > 0 ? `hsl(${hue} 64% 53%)` : undefined}
style:scale={$relativeLevel$ > 0 ? scale : undefined}
>
<ActiveGitIcon class="h-8 w-8" />
<span class="transition-colors"> Hypractive development </span>
</button>
<div class="absolute left-1/2 top-1/2 -z-10 pointer-events-none">
{#each $tiles$ as _}
<GitTile
lifeSpan={lerp(MIN_LIFESPAN_TILE, MAX_LIFESPAN_TILE, $cubibRelativeLevel$)}
maxSpeed={lerp(10, 38, $expoRelativeLevel$)}
minSpeed={lerp(1, 9, $expoRelativeLevel$)}
/>
{/each}
</div>
<div class="mask" bind:this={containerElement}>
{#if $hasAscended$}
<div
class="animate-in slide-in-from-bottom-[500px] fade-in-0 slide-in-from-left-20 [animation-duration:2.5s] vaxx-wrapper zoom-in-95 absolute bottom-[240px] left-1/2 z-50 -translate-x-[100px] rounded-full aspect-square"
style:width={vaxrySize + 'px'}
>
<DiscordProfilePicture
image={VaxryImage}
size={vaxrySize}
coordinates={[0, 0]}
class="outline-orange-300"
{contextId}
isAnimating={false}
/>
</div>
{/if}
<!-- Rising sun -->
<div
class="bg-gradient"
style:opacity={$hasAscended$ ? 1 : $relativeLevel$}
style="--relativeLevel: {$hasAscended$ ? 1 : $expoRelativeLevel$ - 0.2}"
/>
</div>
</div>
<style lang="postcss">
.bg-gradient {
position: absolute;
bottom: -100%;
left: 50%;
translate: -50% calc(var(--relativeLevel) * -60%);
z-index: -10;
transition:
opacity 550ms,
translate 1.5s ease-in;
background: radial-gradient(
closest-side,
theme(colors.yellow.200),
theme(colors.orange.300 / 50%),
theme(colors.red.800 / 0%)
);
width: 150vw;
height: 800px;
}
.vaxx-wrapper {
animation-timing-function: cubic-bezier(0.05, -0.82, 0.165, 1);
pointer-events: auto;
filter: drop-shadow(0px 0px 10px theme(colors.orange.200))
drop-shadow(0px 0px 40px theme(colors.orange.300));
}
.mask {
position: absolute;
pointer-events: none;
bottom: 0%;
z-index: 10;
left: 50%;
translate: -50% 0%;
width: 150vw;
height: 1000px;
/* background: linear-gradient(0deg, black 50%, white 50%); */
/* mask-image: linear-gradient(0deg, transparent 50%, white 50%); */
overflow: hidden;
}
</style>

View File

@ -23,16 +23,16 @@
}) })
</script> </script>
<div class="flex flex-col md:flex-row md:gap-4 gap-2 items-center"> <div class="flex group flex-col md:flex-row md:gap-4 gap-2 items-center">
<div <div
class="flex flex-col gap-3 justify-center items-center text-primary text-lg font-medium rounded-full w-32 h-32" class="flex group-focus-within:-translate-y-1 transition-transform flex-col gap-3 justify-center items-center text-primary text-lg font-medium rounded-full w-32 h-32"
> >
<img src={image} alt="Arch Logo" />{name} <img src={image} alt="Arch Logo" />{name}
</div> </div>
<div class="flex flex-col relative font-mono mb-2"> <div class="flex flex-col relative font-mono mb-2">
<button <button
class="flex text-base transition-all min-w-[18rem] items-center font-medium rounded-full border-primary border py-3 pl-6 pr-6 gap-4 justify-center group active:scale-[1.01]" class="flex text-base transition-transform min-w-[18rem] items-center font-medium rounded-full border-primary border py-3 pl-6 pr-6 gap-4 justify-center active:scale-[1.01]"
on:click={$$slots.default ? undefined : copyCommand} on:click={$$slots.default ? undefined : copyCommand}
> >
<slot> <slot>
@ -42,14 +42,14 @@
<span>{command}</span> <span>{command}</span>
</div> </div>
<ClipboardIcon <ClipboardIcon
class="group-hover:opacity-80 group-active:opacity-100 opacity-0 w-6 h-6 hover:!opacity-100 transition-opacity" class="group-hover:opacity-80 text-white group-active:opacity-100 opacity-0 w-6 h-6 hover:!opacity-100 transition-opacity duration-100"
/> />
</div></slot </div>
> </slot>
</button> </button>
<div <div
class="text-green-400 [translate:-50%_0px] select-none pointer-events-none absolute -top-8 w-full left-1/2 hidden max-w-max" class="text-green-400 [translate:-50%_0px] select-none pointer-events-none absolute md:-top-8 max-md:-bottom-6 bg-black/10 backdrop-blur rounded-full z-20 px-2 w-full left-1/2 hidden max-w-max"
class:copy={isShowingCopied} class:copy={isShowingCopied}
> >
Copied to clipboard ✔ Copied to clipboard ✔

View File

@ -10,31 +10,44 @@
import Title from '$lib/components/Title.svelte' import Title from '$lib/components/Title.svelte'
</script> </script>
<section> <section class="pb-6">
<Title class="mb-8"> <Title class="mb-8">
<span slot="title">Install now</span><span slot="subtitle"> For your favourite distro </span> <span slot="title">Install now</span><span slot="subtitle"> For your favourite distro </span>
</Title> </Title>
<div class="flex flex-col md:gap-6 gap-12 items-center" use:animateIn={{ slide: 24, fade: 0 }}> <div class="flex flex-col md:gap-6 gap-12 items-center" use:animateIn={{ slide: 24, fade: 0 }}>
<InstallButton name="Arch" command="pacman -S hyprland" image={archLogo} <div
><div slot="extra"> class="md:outline md:outline-1 flex flex-col gap-12 md:gap-6 md:outline-blue-500 md:from-blue-500/40 md:to-transparent md:bg-gradient-to-tr md:shadow-xl md:p-8 md:rounded-3xl"
AUR git version: <a href="https://aur.archlinux.org/packages/hyprland-git/">hyprland-git</a>
</div></InstallButton
>
<InstallButton name="NixOs" image={nixLogo}
><a
href="https://wiki.hyprland.org/Nix/"
target="_blank"
class="flex gap-4 items-center justify-between w-full">See instructions <LinkOutIcon /></a
></InstallButton
>
<InstallButton name="FreeBSD" command="pkg install hyprland" image={bsdLogo} />
<InstallButton name="openSuse" command="zypper in hyprland" image={suseLogo}
><div slot="extra">or install “hyprland” via YaST2 Software.</div></InstallButton
> >
<InstallButton name="Arch" command="pacman -S hyprland" image={archLogo}
><div slot="extra">
AUR git version: <a
class="hover:underline hover:text-white"
target="_blank"
href="https://aur.aachlinux.org/packages/hyprland-git/">hyprland-git</a
>
</div></InstallButton
>
<InstallButton name="NixOs" image={nixLogo}
><a
href="https://wiki.hyprland.org/Nix/"
target="_blank"
class="flex hover:underline gap-4 items-center justify-between w-full"
>See instructions <LinkOutIcon /></a
></InstallButton
>
<InstallButton name="FreeBSD" command="pkg install hyprland" image={bsdLogo} />
<InstallButton name="openSuse" command="zypper in hyprland" image={suseLogo}
><div slot="extra">or install “hyprland” via YaST2 Software.</div></InstallButton
>
</div>
<a href="https://wiki.hyprland.org/Getting-Started/Installation/#packages" class="mt-10"> <a
<Button size="lg" type="fancyOutline">Install more</Button> target="_blank"
href="https://wiki.hyprland.org/Getting-Started/Installation/#packages"
class="mt-10"
>
<Button size="lg" type="fancyOutline">Install other</Button>
</a> </a>
</div> </div>
</section> </section>

View File

@ -1,6 +1,6 @@
<script> <script>
import { page } from '$app/stores' import { page } from '$app/stores'
import logo from '$lib/images/logo.png' import logo from '$lib/images/logos/hyprland-color.svg'
import GithubIcon from '~icons/ri/github-fill' import GithubIcon from '~icons/ri/github-fill'
import DiscordIcon from '~icons/prime/discord' import DiscordIcon from '~icons/prime/discord'
import MenuIcon from '~icons/mingcute/menu-line' import MenuIcon from '~icons/mingcute/menu-line'
@ -18,9 +18,10 @@
> >
<a <a
href="/" href="/"
class="flex gap-2 font-london tracking-wider lg:px-4 py-1 text-sm rounded-full lg:bg-black/50 items-center font-bold text-white" class="flex gap-4 font-london tracking-wider lg:px-4 py-1 text-sm rounded-full lg:bg-black/10 items-center lg:backdrop-blur font-bold text-white"
> >
<img src={logo} alt="Hyprland Logo" class="w-6" /><span class="lg:block hidden">Hyprland</span <img src={logo} alt="Hyprland Logo" class="w-6" /><span
class="lg:block lg:mt-1 tracking-widest text-xl hidden">Hyprland</span
></a ></a
> >
@ -46,7 +47,7 @@
<a href="https://wiki.hyprland.org">Wiki</a> <a href="https://wiki.hyprland.org">Wiki</a>
</li> </li>
<li aria-current={$page.url.pathname === '/about' ? 'page' : undefined}> <li aria-current={$page.url.pathname === '/about' ? 'page' : undefined}>
<a href="/#">Wall of fame</a> <a href="/wall_of_fame">Wall of fame</a>
</li> </li>
</ul> </ul>
<ul <ul
@ -90,7 +91,7 @@
/* Desktop classes */ /* Desktop classes */
@media screen(lg) { @media screen(lg) {
@apply relative flex-row rounded-full p-6 pl-5; @apply relative flex h-min w-max flex-row rounded-full bg-black/40 p-2 pl-5 outline outline-primary/10;
} }
} }

View File

@ -1,10 +1,12 @@
<script>
import { inview } from 'svelte-inview' import { inview } from 'svelte-inview'
import previewRice from '$lib/videos/end_4_rice_intro.mp4' import previewRice from '$lib/videos/end_4_rice_intro.mp4'
import previewRiceThumbnail from '$lib/videos/end_4_thumbnail.png' import previewRiceThumbnail from '$lib/videos/end_4_thumbnail.png'
import AudioIcon from '~icons/mingcute/volume-line' import AudioIcon from '~icons/mingcute/volume-line'
import MuteIcon from '~icons/mingcute/volume-mute-line' import MuteIcon from '~icons/mingcute/volume-mute-line'
import PauseIcon from '~icons/mingcute/pause-circle-line'
import clsx from 'clsx' import clsx from 'clsx'
import { onMount } from 'svelte'
import { getIsMobile } from '$lib/Helper.mjs'
/** @type HTMLVideoElement */ /** @type HTMLVideoElement */
let videoElement let videoElement
@ -12,21 +14,37 @@
let isVisible = false let isVisible = false
let isShowingControls = false let isShowingControls = false
let isMuted = true let isMuted = true
let isPaused = false
$: console.log({ isVisible })
function toggleMute() { function toggleMute() {
isMuted = !isMuted isMuted = !isMuted
} }
function togglePlay() { function togglePlay() {
videoElement.paused ? videoElement.play() : videoElement.pause() videoElement.paused ? videoElement.play() : videoElement.pause()
isPaused = videoElement.paused
} }
function makeFullscreen() {
videoElement.requestFullscreen()
}
onMount(() => {
const isMobile = getIsMobile()
if (isMobile) {
//
}
})
</script> </script>
<section <section
class="max-w-7xl px-1 -mb-4 lg:px-8 w-full relative animate-in [animation-delay:1700ms] fade-in-0 fill-mode-backwards [animation-duration:2000ms] slide-in-from-bottom-10 z-20 {$$restProps.class}" class="max-w-[1400px] px-1 relative -mb-4 lg:px-8 w-full animate-in [animation-delay:1700ms] fade-in-0 fill-mode-backwards [animation-duration:2000ms] slide-in-from-bottom-10 {$$restProps.class}"
> >
<div <div
class={clsx( class={clsx(
'rounded-xl group overflow-hidden border-sky-400 border-2 transition-all [transition-duration:1460ms] mx-3', 'rounded-xl group relative overflow-hidden border-sky-400 border-2 transition-all [transition-duration:1460ms] mx-3 shadow-2xl shadow-cyan-400/40',
!isVisible && 'opacity-20 scale-90' !isVisible && 'opacity-20 scale-90'
)} )}
role="banner" role="banner"
@ -39,6 +57,7 @@
isVisible = false isVisible = false
videoElement.pause() videoElement.pause()
}} }}
on:inview_leave={() => (isVisible = false)}
on:mouseenter={() => (isShowingControls = true)} on:mouseenter={() => (isShowingControls = true)}
on:mouseleave={() => (isShowingControls = false)} on:mouseleave={() => (isShowingControls = false)}
> >
@ -52,6 +71,7 @@
preload="auto" preload="auto"
poster={previewRiceThumbnail} poster={previewRiceThumbnail}
on:click={togglePlay} on:click={togglePlay}
on:dblclick={makeFullscreen}
/> />
<div <div
class={clsx( class={clsx(
@ -60,7 +80,7 @@
)} )}
> >
<button <button
class="absolute p-2 h-10 bg-black/5 rounded-full w-10 bottom-4 right-8 opacity-70 hover:opacity-100" class="absolute p-2 h-10 bg-black/5 rounded-full w-10 bottom-4 right-4 opacity-70 hover:opacity-100"
on:click|stopPropagation={toggleMute} on:click|stopPropagation={toggleMute}
> >
{#if isMuted} {#if isMuted}
@ -69,15 +89,22 @@
<AudioIcon class="h-full w-full" /> <AudioIcon class="h-full w-full" />
{/if} {/if}
</button> </button>
{#if isPaused}
<div
class="absolute h-14 rounded-full -translate-x-1/2 -translate-y-1/2 w-14 top-1/2 left-1/2 opacity-80 hover:opacity-100 pointer-events-none"
>
<PauseIcon class="h-full w-full" />
</div>
{/if}
</div> </div>
</div> </div>
<div class="preview-rice-bg" aria="hidden" /> <div class="preview-rice-bg overflow-x-hidden" aria="hidden" />
</section> </section>
<style lang="postcss"> <style lang="postcss">
.preview-rice-bg { .preview-rice-bg {
@apply absolute inset-0 -top-20 -z-10 w-screen opacity-50; @apply absolute inset-0 -top-40 -z-10 w-full opacity-50;
/* background-color: red; */ /* background-color: red; */
background-image: radial-gradient(min(150vw, 1400px) 50%, theme(colors.sky.500), transparent); background-image: radial-gradient(closest-side, theme(colors.sky.500), transparent);
} }
</style> </style>

View File

@ -12,7 +12,7 @@
<div class="px-4 -mb-40 z-20"> <div class="px-4 -mb-40 z-20">
<Title> <Title>
<span slot="pre"> Memorials of the ricing legends </span> <span slot="pre"> Memorials of the ricing legends </span>
<span slot="title">Hall of Fame</span> <span slot="title">Wall of Fame</span>
</Title> </Title>
</div> </div>
@ -20,23 +20,23 @@
class="w-full -mt-24 max-w-[1100px] flex relative flex-col gap-16 lg:gap-24 items-center justify-end overflow-hidden md:px-16 [perspective:100px]" class="w-full -mt-24 max-w-[1100px] flex relative flex-col gap-16 lg:gap-24 items-center justify-end overflow-hidden md:px-16 [perspective:100px]"
use:animateIn={{ slide: 24, fade: 0.5, duration: 800 }} use:animateIn={{ slide: 24, fade: 0.5, duration: 800 }}
> >
<a class="absolute bottom-24 left-1/2 z-20 -translate-x-1/2" href="/#"> <a class="absolute bottom-24 left-1/2 z-20 -translate-x-1/2" href="/wall_of_fame">
<Button size="lg" type="fancyOutline">Go to Hall of Fame</Button> <Button size="lg" type="fancyOutline">Go to Wall of Fame</Button>
</a> </a>
<div <div
class="bg-blue-500 w-full [translate:0px_0px_-100px] aspect-square rounded-[50%] absolute top-0 inset-x-0 -z-30 blur-[200px]" class="w-full [translate:0px_40px_-10px] md:[translate:0px_0px_-40px] absolute top-0 inset-0 -z-30 atmosphere"
/> />
<FameRicePreview <FameRicePreview
image="/imgs/ricingcomp1/lauroro.jpg" image="/imgs/ricingcomp1/lauroro.jpg"
containerClass="[translate:0px_0px_-100px] -mb-[30%] hover:[translate:0px_0px_-98px] transition-all duration-500" containerClass="[translate:0px_50px_-100px] -mb-[30%] hover:[translate:0px_0px_-98px] transition-all duration-500"
imageClass="[mask-image:linear-gradient(black,black_45%,transparent_65%)] opacity-50 hover:opacity-60" imageClass="[mask-image:linear-gradient(black,black_45%,transparent_65%)] opacity-50 hover:opacity-60"
/> />
<FameRicePreview <FameRicePreview
image="/imgs/ricingcomp1/amadeus.png" image="/imgs/ricingcomp1/amadeus.png"
containerClass="[translate:0px_0px_-40px] hover:[translate:0px_0px_-38px] -mb-[30%] duration-500 transition-all group" containerClass="[translate:0px_50px_-40px] hover:[translate:0px_0px_-38px] -mb-[30%] duration-500 transition-all group"
imageClass="[mask-image:linear-gradient(black,black_50%,transparent_75%)] opacity-80 group-hover:opacity-100 transition-all duration-500" imageClass="md:[mask-image:linear-gradient(black,black_50%,transparent_75%)] [mask-image:linear-gradient(black,black_10%,transparent_75%)] opacity-80 group-hover:opacity-100 transition-all duration-500"
/> />
<FameRicePreview <FameRicePreview
image="/imgs/ricingcomp1/flicko.png" image="/imgs/ricingcomp1/flicko.png"
@ -48,8 +48,12 @@
</section> </section>
<style lang="postcss"> <style lang="postcss">
.atmosphere {
background: radial-gradient(closest-side, theme(colors.blue.500), transparent);
}
.glow { .glow {
@apply h-[200px] lg:h-[400px]; @apply h-[400px] lg:h-[400px];
width: 100%; width: 100%;
/* min-width: 8800px; */ /* min-width: 8800px; */
position: absolute; position: absolute;

View File

@ -39,6 +39,15 @@ body {
border-radius: 24px; border-radius: 24px;
} }
/* optimize mobile */
.animate-in,
.animate-out,
.ani-in {
@media only screen and (max-width: 640px) {
animation: none !important;
}
}
@keyframes pop { @keyframes pop {
0% { 0% {
scale: 0.98; scale: 0.98;

View File

@ -0,0 +1 @@
export const prerender = true

View File

@ -0,0 +1,7 @@
<div class="h-screen flex items-center justify-center p-8 overflow-hidden">
<img
src="https://i.giphy.com/media/H8w9SE95izloQ/giphy.webp"
alt="Under construction"
class="w-full max-w-4xl"
/>
</div>