Skip to content

Commit

Permalink
feat: settings
Browse files Browse the repository at this point in the history
  • Loading branch information
colinlienard committed May 10, 2024
1 parent dbd5149 commit 3a4cf4f
Show file tree
Hide file tree
Showing 10 changed files with 130 additions and 20 deletions.
20 changes: 20 additions & 0 deletions app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,23 @@
<NuxtPage />
</Layout>
</template>

<!-- <script setup lang="ts">
const pointer = usePointer();

onMounted(() => {
window.addEventListener('mousemove', pointer.move);
});

onUnmounted(() => {
window.removeEventListener('mousemove', pointer.move);
});
</script>

<template>
<main class="flex h-screen items-center justify-center gap-4 bg-slate-50">
<Sticker url="/svgs/star-sticker.svg" />
<Sticker url="/svgs/100-sticker.svg" />
<Sticker url="/svgs/github-sticker.svg" />
</main>
</template> -->
18 changes: 18 additions & 0 deletions assets/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,25 @@
src: url(/fonts/SourceSerifPro-SemiboldIt.otf) format('otf');
}

body {
overflow-y: scroll;
}

*::selection {
background-color: #99f6e4;
}
}

@layer components {
.box {
@apply flex items-center gap-2 text-nowrap rounded-lg border border-solid border-slate-300 bg-slate-50 px-3 py-2 outline-0 outline-teal-100 [&>svg]:h-4;
}

.input {
@apply transition-[border] focus-within:!border-teal-400 focus-within:outline focus-within:outline-4 hover:border-slate-400;
}

.button {
@apply transition-[background-color] hover:bg-white active:bg-slate-100 active:transition-none;
}
}
3 changes: 3 additions & 0 deletions components/Button.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<template>
<button class="box button shadow-sm"><slot /></button>
</template>
16 changes: 16 additions & 0 deletions components/Input.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<script setup lang="ts">
const model = defineModel<string>();
const { placeholder } = defineProps<{ placeholder: string }>();
</script>

<template>
<label class="box input cursor-text">
<slot />
<input
v-model="model"
class="bg-transparent outline-none placeholder:text-slate-400"
type="text"
:placeholder="placeholder"
/>
</label>
</template>
23 changes: 20 additions & 3 deletions components/Layout.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
<script setup lang="ts">
import { ArrowPathIcon } from 'heroicons';
import { ArrowPathIcon, CheckIcon, MagnifyingGlassIcon, XMarkIcon } from 'heroicons';
const buildTime = useState(() => Date.now());
const duration = Date.now() - buildTime.value;
const hours = Math.floor(duration / 60 / 60 / 1000);
const lastUpdated = hours > 0 ? `${hours} hour${hours > 1 ? 's' : ''}` : 'less than an hour';
const pointer = usePointer();
const settings = useSettings();
onMounted(() => {
window.addEventListener('mousemove', pointer.move);
Expand All @@ -32,7 +33,7 @@ onUnmounted(() => {
GitHub
</NuxtLink>
</header>
<main class="flex w-full flex-col items-center gap-16">
<main class="flex w-full flex-col items-center">
<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
Expand All @@ -45,7 +46,7 @@ onUnmounted(() => {
<Sticker
url="/svgs/star-sticker.svg"
rotate="90deg"
class="!absolute -top-2 translate-x-80"
class="!absolute top-1 translate-x-[19.5rem]"
/>
<Sticker
url="/svgs/github-sticker.svg"
Expand All @@ -57,6 +58,22 @@ onUnmounted(() => {
<p class="text-sm">Last updated {{ lastUpdated }} ago</p>
</div>
</div>
<div class="mt-16 flex w-full gap-2 py-8">
<Input v-model="settings.search" placeholder="Search by name" class="w-full">
<MagnifyingGlassIcon />
</Input>
<Select placeholder="Languages" class="w-full" />
<Button @click="settings.showOwners = !settings.showOwners">
<CheckIcon v-if="settings.showOwners" />
<XMarkIcon v-else />
Show owners
</Button>
<Button @click="settings.showFullDescription = !settings.showFullDescription">
<CheckIcon v-if="settings.showFullDescription" />
<XMarkIcon v-else />
Show full description
</Button>
</div>
<slot />
</main>
</div>
Expand Down
12 changes: 12 additions & 0 deletions components/Select.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<script setup lang="ts">
import { ChevronDownIcon } from 'heroicons';
const { placeholder } = defineProps<{ placeholder: string }>();
</script>

<template>
<div class="box input justify-between">
<p class="text-slate-400">{{ placeholder }}</p>
<ChevronDownIcon />
</div>
</template>
6 changes: 3 additions & 3 deletions components/Sticker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@ const center = ref<{ x: number; y: number }>();
const pointer = usePointer();
const y = computedWithPrev<number>((prev) => {
if (!center.value) return 0;
if (!center.value) return -4;
return ease(-(center.value.x - pointer.x), prev);
});
const x = computedWithPrev<number>((prev) => {
if (!center.value) return 0;
if (!center.value) return -12;
return ease(center.value.y - pointer.y, prev);
});
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;
return Math.min(Math.max(distance / 400, 0.5), 0.8);
});
function ease(result: number, prev: number, max = 15, easing = 0.05) {
Expand Down
8 changes: 8 additions & 0 deletions composables/useSettings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const useSettings = defineStore('settings', () => {
return reactive({
search: '',
languages: [] as string[],
showOwners: false,
showFullDescription: false,
});
});
44 changes: 30 additions & 14 deletions pages/index.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
<script setup lang="ts">
import { StarIcon } from 'heroicons';
const { data: repositories } = await useFetch('/api/repositories');
const { data } = await useFetch('/api/repositories');
const settings = useSettings();
const repositories = computed(() => {
if (!settings.search) return data.value;
return data.value?.filter((repo) =>
repo.name.toLowerCase().includes(settings.search.toLowerCase()),
);
});
const hoverEffect = ref({ height: 0, top: 0, opacity: 0 });
function formatDuration(age: number) {
const years = Math.floor(age / 12 / 30 / 24 / 60 / 60 / 1000);
return `${years} years old`;
return `${years} y.o.`;
}
function onHoverEffectMouseEnter(event: MouseEvent) {
Expand All @@ -18,17 +26,17 @@ function onHoverEffectMouseEnter(event: MouseEvent) {
</script>

<template>
<section class="table">
<section class="table w-[64rem] table-fixed">
<div
class="after:content-[' '] sticky top-0 z-10 table-header-group bg-slate-50 after:absolute after:inset-x-0 after:-bottom-[1px] after:h-[1px] after:bg-slate-300"
>
<div class="table-row text-slate-400 *:table-cell *:px-4 *:py-6">
<div>Rank</div>
<div>Name</div>
<div>Stars</div>
<div>Description</div>
<div>Language</div>
<div>Age</div>
<div class="w-[8%]">Rank</div>
<div class="w-[30%]">Name</div>
<div class="w-[12%]">Stars</div>
<div class="w-[30%]">Description</div>
<div class="w-[12%]">Language</div>
<div class="w-[8%]">Age</div>
</div>
</div>
<div class="relative table-row-group" @mouseleave="hoverEffect.opacity = 0">
Expand All @@ -45,7 +53,7 @@ function onHoverEffectMouseEnter(event: MouseEvent) {
:key="repo.name"
:to="repo.url"
target="_blank"
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"
class="after:content-[' '] relative table-row cursor-alias *:table-cell *:px-4 *:py-6 *:align-top after:absolute after:inset-0 after:h-[1px] after:bg-slate-300"
@mouseenter="onHoverEffectMouseEnter"
>
<div>
Expand All @@ -56,9 +64,12 @@ function onHoverEffectMouseEnter(event: MouseEvent) {
</div>
</div>
<div>
<div class="flex items-center gap-2 text-nowrap">
<div class="flex items-center gap-2">
<img :src="repo.image" :alt="`GitHub ${repo.ownerName} avatar`" class="h-6 rounded" />
<h3 class="font-semibold">{{ repo.name }}</h3>
<h3>
<span v-if="settings.showOwners" class="text-slate-500">{{ repo.ownerName }}/</span>
{{ repo.name }}
</h3>
</div>
</div>
<div>
Expand All @@ -67,14 +78,19 @@ function onHoverEffectMouseEnter(event: MouseEvent) {
<span>{{ repo.starsNumber.toLocaleString() }}</span>
</div>
</div>
<div class="text-slate-400">{{ repo.description }}</div>
<div class="text-slate-500">
<p v-if="settings.showFullDescription">{{ repo.description }}</p>
<p v-else class="overflow-hidden text-ellipsis whitespace-nowrap">
{{ repo.description }}
</p>
</div>
<div>
<div v-if="repo.language" class="flex items-center gap-1">
<div class="h-2 w-2 rounded-full" :style="{ backgroundColor: repo.language.color }" />
{{ repo.language?.name }}
</div>
</div>
<div class="text-nowrap">{{ formatDuration(repo.age) }}</div>
<div>{{ formatDuration(repo.age) }}</div>
</NuxtLink>
</div>
</section>
Expand Down
Binary file removed public/images/eyes-emoji.png
Binary file not shown.

0 comments on commit 3a4cf4f

Please sign in to comment.