Skip to content

Commit

Permalink
feat: effects
Browse files Browse the repository at this point in the history
  • Loading branch information
colinlienard committed May 9, 2024
1 parent 2d61afa commit dbd5149
Show file tree
Hide file tree
Showing 8 changed files with 106 additions and 45 deletions.
18 changes: 15 additions & 3 deletions components/Layout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,25 @@ onUnmounted(() => {
</NuxtLink>
</header>
<main class="flex w-full flex-col items-center gap-16">
<div class="flex w-full flex-col items-center gap-6">
<div class="relative flex w-full flex-col items-center gap-6">
<h2 class="max-w-2xl text-center font-serif text-6xl font-semibold">
Top 100 most
Top
<span class="text-transparent">100</span>
most
<span class="italic">starred</span>
GitHub repositories
</h2>
<Sticker url="/svgs/star.svg" />
<Sticker url="/svgs/100-sticker.svg" class="!absolute -top-6 -translate-x-[6.75rem]" />
<Sticker
url="/svgs/star-sticker.svg"
rotate="90deg"
class="!absolute -top-2 translate-x-80"
/>
<Sticker
url="/svgs/github-sticker.svg"
rotate="-15deg"
class="!absolute -bottom-1 -translate-x-[17rem]"
/>
<div class="flex items-center gap-2 text-slate-400">
<ArrowPathIcon class="h-4" />
<p class="text-sm">Last updated {{ lastUpdated }} ago</p>
Expand Down
9 changes: 5 additions & 4 deletions components/PixelsBackground.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ function randomPixel() {
}
onMounted(() => {
pixels.value = Array.from({ length: 32 }, randomPixel);
const length = Math.round(window.innerWidth / 40);
pixels.value = Array.from({ length }, randomPixel);
intervalId = setInterval(() => {
pixels.value.shift();
Expand All @@ -30,7 +31,7 @@ onUnmounted(() => {

<template>
<div class="absolute inset-[4px] h-[50vh] overflow-hidden">
<div class="tiles absolute inset-0 opacity-50" />
<div class="tileset absolute inset-0 opacity-50" />
<TransitionGroup name="pixels">
<div
v-for="{ id, x, y, color } in pixels"
Expand All @@ -44,7 +45,7 @@ onUnmounted(() => {
</template>

<style scoped>
.tiles {
.tileset {
--bg: #f8fafc;
--color: #e2e8f0;
--space: 0.25rem;
Expand All @@ -65,7 +66,7 @@ onUnmounted(() => {
.pixels-enter-active,
.pixels-leave-active {
transition: opacity 2s ease-in-out;
transition: opacity 1s ease-in-out;
}
.pixels-enter-from,
.pixels-leave-to {
Expand Down
91 changes: 54 additions & 37 deletions components/Sticker.vue
Original file line number Diff line number Diff line change
@@ -1,63 +1,80 @@
<script setup lang="ts">
const { url } = defineProps<{ url: string }>();
const maskUrl = `url(${url})`;
const easing = 0.05;
const max = 15;
const { url, rotate } = defineProps<{ url: string; rotate?: string }>();
const maskUrl = `url(${url})`;
const element = ref<HTMLElement>();
const center = ref<{ x: number; y: number }>();
const pointer = usePointer();
const rotateY = computedWithPrev<number>((prev) => {
if (!element.value) return 0;
const rect = element.value.getBoundingClientRect();
const center = rect.left + rect.width / 2;
const result = -(center - pointer.x);
const capped = Math.min(Math.max(result, -max), max);
return prev + (capped - prev) * easing;
const y = computedWithPrev<number>((prev) => {
if (!center.value) return 0;
return ease(-(center.value.x - pointer.x), prev);
});
const x = computedWithPrev<number>((prev) => {
if (!center.value) return 0;
return ease(center.value.y - pointer.y, prev);
});
const rotateX = computedWithPrev<number>((prev) => {
if (!element.value) return 0;
const rect = element.value.getBoundingClientRect();
const center = rect.top + rect.height / 2;
const result = center - pointer.y;
const fromCenter = computed(() => {
if (!center.value) return 0;
const distance = Math.hypot(center.value.x - pointer.x, center.value.y - pointer.y);
return Math.max(distance / 200, 2) / 4;
});
function ease(result: number, prev: number, max = 15, easing = 0.05) {
const capped = Math.min(Math.max(result, -max), max);
return prev + (capped - prev) * easing;
}
onMounted(() => {
const { width, height, top, left } = element.value!.getBoundingClientRect();
center.value = { x: left + width / 2, y: top + height / 2 };
});
</script>

<template>
<div ref="element" class="sticker relative" :style="{ '--x': rotateX, '--y': rotateY }">
<img class="drop-shadow-lg" :src="url" alt="" />
<div class="shine absolute inset-0" />
<div>
<div
ref="element"
class="sticker relative"
:style="{ '--x': x, '--y': y, '--from-center': fromCenter, '--rotate': rotate }"
>
<img class="drop-shadow-lg" :src="url" alt="" />
<div class="shine absolute inset-0" />
</div>
</div>
</template>

<style scoped>
.sticker {
transform: perspective(300px) rotateX(calc(var(--x) * 1deg)) rotateY(calc(var(--y) * 1deg));
* {
transform: rotate(var(--rotate));
}
}
.shine {
mask-image: v-bind(maskUrl);
background-image: repeating-linear-gradient(-45deg, black, white 5%, black 10%),
repeating-linear-gradient(
0deg,
hsla(283, 49%, 60%, 0.75) calc(5% * 1),
hsla(2, 74%, 59%, 0.75) calc(5% * 2),
hsla(53, 67%, 53%, 0.75) calc(5% * 3),
hsla(93, 56%, 52%, 0.75) calc(5% * 4),
hsla(176, 38%, 50%, 0.75) calc(5% * 5),
hsla(228, 100%, 77%, 0.75) calc(5% * 6),
hsla(283, 49%, 61%, 0.75) calc(5% * 7)
);
background-size: 400%, 100%;
mask-size: calc(100% - 2px);
mask-position: 1px;
mask-repeat: no-repeat;
background-image: url(/images/noise.png),
repeating-linear-gradient(-45deg, black, white 5%, black 10%),
repeating-linear-gradient(purple, red, yellow, green, cyan, purple);
background-size:
50% 50%,
400% 400%,
400% 400%;
background-position:
calc(var(--y) * 1px) calc(var(--x) * 1px),
calc(var(--x) * 1px) calc(var(--y) * 1px);
background-blend-mode: color-burn;
center center,
calc(var(--y) * 1% - 100%) calc(var(--x) * 1% - 100%),
calc(var(--x) * 5%) calc(var(--y) * 5%);
background-blend-mode: overlay, color-burn;
mix-blend-mode: plus-lighter;
filter: brightness(calc((0.5 * 0.3) + 0.5)) contrast(2.3) saturate(1);
filter: brightness(var(--from-center)) contrast(3);
}
</style>
2 changes: 1 addition & 1 deletion pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ function onHoverEffectMouseEnter(event: MouseEvent) {
:key="repo.name"
:to="repo.url"
target="_blank"
class="after:content-[' '] relative table-row *:table-cell *:px-4 *:py-6 *:align-top after:absolute after:inset-0 after:h-[1px] after:bg-slate-300"
class="after:content-[' '] relative table-row cursor-[url(/images/eyes-emoji.png)_12_12,_pointer] *:table-cell *:px-4 *:py-6 *:align-top after:absolute after:inset-0 after:h-[1px] after:bg-slate-300"
@mouseenter="onHoverEffectMouseEnter"
>
<div>
Expand Down
Binary file added public/images/eyes-emoji.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions public/svgs/100-sticker.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions public/svgs/github-sticker.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes

0 comments on commit dbd5149

Please sign in to comment.