Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions locales/en.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
scroll: Scroll down
button:
about: About
about: About Me
resume: View Resume
back: Back
go: GO
up-next: Up Next
Expand All @@ -23,7 +25,9 @@ footer:

# content
home:
section_1: I believe that ideas in the form of code, design, and curiosity can build products that benefit everyone
section_1:
whoami: I'm a
title: I build idea, design, and curiosity in the form of code, and turning them into beautifully crafted products.
section_2:
title: What I've been working on recently
subtitle: And many more
Expand Down
8 changes: 6 additions & 2 deletions locales/id.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
scroll: Scroll ke bawah
button:
about: Tentang
about: Tentang Aku
resume: Lihat Resume
back: Kembali
go: Pergi
up-next: Selanjutnya
Expand All @@ -23,7 +25,9 @@ footer:

# content
home:
section_1: Aku percaya bahwa ide berupa code, desain, dan rasa ingin tahu mampu menciptakan produk yang bermanfaat untuk semua
section_1:
whoami: Aku
title: Aku mewujudkan ide, desain, dan rasa ingin tahu dalam bentuk code, dan mengubahnya menjadi produk yang sempurna.
section_2:
title: Karya yang sedang kukerjakan baru-baru ini
subtitle: Dan masih banyak lagi
Expand Down
9 changes: 9 additions & 0 deletions src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,21 @@ declare module 'vue' {
FooterBackground: typeof import('./components/partials/FooterBackground.vue')['default']
FooterOverlay: typeof import('./components/FooterOverlay.vue')['default']
HeaderOverlay: typeof import('./components/HeaderOverlay.vue')['default']
HeroBackgroundTag: typeof import('./components/partials/index/HeroBackgroundTag.vue')['default']
HeroButtonIndicator: typeof import('./components/partials/index/HeroButtonIndicator.vue')['default']
HeroContent: typeof import('./components/partials/index/HeroContent.vue')['default']
HeroCTA: typeof import('./components/partials/index/HeroCTA.vue')['default']
HeroHeading: typeof import('./components/partials/index/HeroHeading.vue')['default']
IndexFirstSection: typeof import('./components/partials/index/IndexFirstSection.vue')['default']
IndexSecondSection: typeof import('./components/partials/index/IndexSecondSection.vue')['default']
IndexThirdSection: typeof import('./components/partials/index/IndexThirdSection.vue')['default']
LayoutDivider: typeof import('./components/partials/LayoutDivider.vue')['default']
LinkCTA: typeof import('./components/LinkCTA.vue')['default']
NavOverlay: typeof import('./components/NavOverlay.vue')['default']
PreviousButton: typeof import('./components/partials/PreviousButton.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
ScrollIndicator: typeof import('./components/partials/ScrollIndicator.vue')['default']
SocialCard: typeof import('./components/partials/about/SocialCard.vue')['default']
SocialLink: typeof import('./components/partials/about/SocialLink.vue')['default']
ToggleButton: typeof import('./components/partials/ToggleButton.vue')['default']
Expand Down
2 changes: 1 addition & 1 deletion src/components/HeaderOverlay.vue
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const returnInert = computed(() => {
</script>

<template>
<header :inert="returnInert" gap="1.5" transition="composite" duration="500" lg="flex flex-col translate-y-0 justify-end opacity-100" :class="!isOnBottom && `translate-y-40 opacity-0`">
<header :inert="returnInert" gap="1.5" transition="composite" duration="500" lg="flex flex-col translate-y-0 justify-end opacity-100" :class="!isOnBottom && `translate-y-80 md:opacity-0`">
<div flex gap="4 lg:16" text="sm" class="justify-between md:items-end">
<section v-for="(section, i) in HEADER" :key="i" transition="composite" duration="500" first="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-(x-8 y-4)" last="flex-(~ wrap) flex-col lg:flex-row items-start md:items-end justify-end gap-2 lg:gap-8" class="max-w-fit" :class="notTopBottom && `swipe-left`">
<div v-for="(card, idx) in section" :key="idx" flex="~ col" w="40" gap="1.5">
Expand Down
42 changes: 42 additions & 0 deletions src/components/LinkCTA.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<script setup lang="ts">
interface Prop {
to: string
label: string
color?: 'primary' | 'secondary' | 'neutral'
}

const { color = 'primary' } = defineProps<Prop>()

const wrapperColorMap = {
primary: 'bg-primary/10 text-primary border-primary',
secondary: 'bg-foreground/10 text-foreground border-foreground',
neutral: 'bg-foreground/5 text-foreground border-foreground',
}

const overlayColorMap = {
primary: 'bg-primary/90 text-black',
secondary: 'bg-foreground/90 text-background',
neutral: 'bg-background',
}

const spanClassName = 'text-(lg nowrap) tracking-widest font-bold select-none lg:text-2xl sm:text-xl'
</script>

<template>
<RouterLink relative :to="to" p="y-1 x-2 sm:y-2 sm:x-3" class="wrapper-img group/button text-center *:first:absolute-overlay" border="2" :class="wrapperColorMap[color]">
<slot name="overlay">
<div aria-hidden="true" ease="out-expo" duration="500" transition="composite" class="flex-centered group-focus/button:opacity-0 group-hover/button:opacity-0" :class="overlayColorMap[color]">
<span :class="spanClassName">{{ label }}</span>
</div>
</slot>
<slot>
<span :class="spanClassName">{{ label }}</span>
</slot>
</RouterLink>
</template>

<style scoped>
.wrapper-img {
background-image: var(--images-pattern-graph-paper);
}
</style>
16 changes: 16 additions & 0 deletions src/components/partials/ScrollIndicator.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<script setup lang="ts">
const { t } = useI18n()
const { isScrolling, isToBottom, isOnBottom } = useInjectedScroll()
const isScrollingDown = computed(() => isScrolling.value || isToBottom.value || isOnBottom.value)
</script>

<template>
<div aria-hidden="true" fixed flex="~ items-end justify-end sm:justify-center" m="y-10 sm:y-20 md:y-24 lg:y-32 x-12" transition="composite duration-300" class="events-none inset-0" :class="isScrollingDown ? 'opacity-0 animate-paused' : 'opacity-75'">
<div class="animate-bounce">
<span select="none" text="sm md:base" font="medium jetbrains-mono">
{{ t('scroll') }}
</span>
<div m="x-auto" i="carbon-chevron-down" />
</div>
</div>
</template>
2 changes: 1 addition & 1 deletion src/components/partials/about/BackgroundText.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const isVisible = useElementVisibility(ref)
<template>
<div ref="ref" aria-hidden="true" class="wrapper">
<div transition="composite" duration="2000" class="curtain" :class="isVisible ? '-translate-y-full' : 'translate-y-none'" />
<span class="background-text text-20 leading-none font-fugazOne pointer-events-none truncate 2xl:text-80 lg:text-56 md:text-40 sm:text-36">
<span class="background-text text-20 leading-none font-fugaz-one pointer-events-none truncate 2xl:text-80 lg:text-56 md:text-40 sm:text-36">
<slot>
{{ text }}
</slot>
Expand Down
38 changes: 38 additions & 0 deletions src/components/partials/index/HeroBackgroundTag.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<script setup lang="ts">
interface Prop {
isVisible: boolean
}
type Tag = 'develop' | 'build'

const props = defineProps<Prop>()
const tag = ref<Tag>('develop')

function toggleTag() {
tag.value = tag.value === 'develop' ? 'build' : 'develop'
}

const spanClassName = 'font-black inline-block text-nowrap first:text-5xl last:text-4xl first:sm:text-6xl last:sm:text-5xl'
</script>

<template>
<div aria-hidden="true" overflow="hidden" class="group/tag opacity-20 cursor-help select-none dark:opacity-15" @click="toggleTag">
<div transition="composite" duration="1000" delay="300" ease="out-expo" class="mx-1.5 text-right translate-y-2" :class="!props.isVisible && `translate-y-full`">
<span class="mask-text w-fit uppercase" :class="spanClassName">
<Transition mode="out-in" name="fade">
<span v-if="tag === 'develop'">{{ tag }}</span>
<span v-else>{{ tag }}</span>
</Transition>
</span>
<span transition="composite" duration="300" class="mask-text origin-bottom-left group-active/tag:scale-90" :class="spanClassName">
ING
</span>
</div>
</div>
</template>

<style scoped>
.mask-text {
mask-image: var(--images-pattern-diagonal-lines);
color: var(--color-foreground);
}
</style>
29 changes: 29 additions & 0 deletions src/components/partials/index/HeroButtonIndicator.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<script setup lang="ts">
defineProps<{
fadeDirection: 'left' | 'right'
}>()

const overlayClassMap = {
left: 'bg-linear-to-r',
right: 'bg-linear-to-l',
}
</script>

<template>
<div aria-hidden="true" relative class="opacity-25 events-none">
<div p="y-1 x-2 sm:y-2 sm:x-3" class="indicator-content">
<slot />
</div>
<div class="absolute-overlay from-transparent to-background from-25%" :class="overlayClassMap[fadeDirection]" />
</div>
</template>

<style scoped>
.indicator-content {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
}
</style>
26 changes: 26 additions & 0 deletions src/components/partials/index/HeroCTA.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<script setup lang="ts">
interface Prop {
isVisible: boolean
}
const props = defineProps<Prop>()

const { t } = useI18n()
const ctaClassName = 'w-full scale-105 sm:w-sm'
</script>

<template>
<div border="~ x-none dashed foreground/25">
<div transition="composite" duration="2000" m="x-auto" class="wrap" :class="props.isVisible && `skew-x-10`">
<div flex="~ col sm:row" gap="2 sm:4" transition="composite" duration="1000" ease="out-expo" :class="!props.isVisible && `-translate-x-1/5`">
<HeroButtonIndicator fade-direction="right" class="hidden sm:block">
<div i="carbon-chevron-right" />
</HeroButtonIndicator>
<LinkCTA to="/about" :label="t('button.about')" color="primary" class="uppercase origin-right" :class="ctaClassName" />
<LinkCTA to="/resume" :label="t('button.resume')" color="secondary" class="uppercase origin-left" :class="ctaClassName" />
<HeroButtonIndicator fade-direction="left" class="hidden sm:block">
<div v-for="i in 5" :key="i" i="carbon-chevron-right" />
</HeroButtonIndicator>
</div>
</div>
</div>
</template>
23 changes: 23 additions & 0 deletions src/components/partials/index/HeroContent.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<script setup lang="ts">
interface Prop {
isVisible: boolean
}

const props = defineProps<Prop>()
const { t } = useI18n()
</script>

<template>
<div>
<div aria-hidden="true" m="x-auto" class="wrap translate-y-1/2" sm="border-(l-2 dotted primary rounded-xl)">
<div text="3xl sm:4xl md:5xl" i="carbon-quotes" />
</div>
<HeroBackgroundTag :is-visible="props.isVisible" />
<HeroHeading />
<div m="x-auto" class="wrap">
<h2 text="lg sm:xl md:2xl lg:3xl" font="medium" leading="relaxed">
{{ t('home.section_1.title') }}
</h2>
</div>
</div>
</template>
44 changes: 44 additions & 0 deletions src/components/partials/index/HeroHeading.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<script setup lang="ts">
const { t } = useI18n()
</script>

<template>
<div relative overflow="hidden">
<div aria-hidden="true" absolute top="0" left="0" h="full" w="full" class="pattern-bg opacity-20 dark:opacity-15" />
<div m="x-auto" overflow="hidden" class="wrap">
<div relative z="10" overflow="hidden">
<h1 text="3xl sm:4xl md:5xl lg:6xl" font="black" class="uppercase">
{{ t('home.section_1.whoami') }} DEVELOPER
</h1>
</div>
<div aria-hidden="true" m="lg:r-4" absolute top="0" right="0" overflow="hidden" transition="composite" duration="1000" ease="in-out-circ" class="events-none group-hover:skew-x-0 md:skew-x-90">
<span text="4xl sm:5xl md:6xl lg:7xl nowrap" font="black" class="pattern-text">
<span class="hidden xl:inline">
COMPOSITOR-ONLY
</span>
<span class="xl:hidden">
/dev/
</span>
</span>
</div>
</div>
</div>
</template>

<style scoped>
.pattern-bg {
background-image: var(--images-pattern-diagonal-lines);
background-attachment: fixed;
}

.pattern-text {
color: var(--color-background);
}

@supports (-webkit-text-stroke: 1px var(--color-foreground)) {
.pattern-text {
-webkit-text-stroke: 1px rgb(var(--color-foreground-raw) / 0.2);
color: var(--color-background);
}
}
</style>
20 changes: 20 additions & 0 deletions src/components/partials/index/IndexFirstSection.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<script setup lang="ts">
const visibilityTarget = useTemplateRef('sectionRef')
const isVisible = useElementVisibility(visibilityTarget, {
threshold: 2 / 3,
})
</script>

<template>
<section ref="sectionRef" transition="composite duration-1000 ease-out-expo" class="section-idx origin-top items-center" :class="!isVisible && `opacity-0 scale-y-50 events-none`">
<div flex="~ 1 col" gap="8" overflow="hidden" class="group">
<HeroContent :is-visible="isVisible" />
<HeroCTA :is-visible="isVisible" />
<div aria-hidden="true" grid="~ cols-12" p="x-0.5" class="opacity-50 skew-x-45">
<div border="t-2 dotted foreground" class="col-span-1" />
<div border="t-2 dotted primary" m="x-1" class="col-span-8" />
<div border="t-2 dotted foreground" class="col-span-3" />
</div>
</div>
</section>
</template>
42 changes: 42 additions & 0 deletions src/components/partials/index/IndexSecondSection.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<script setup lang="ts">
import { WORKS } from '~/constants'

const { t } = useI18n()

useHead({
title: () => t('button.home'),
})
const visibilityTarget = useTemplateRef('sectionRef')
const isVisible = useElementVisibility(visibilityTarget, {
threshold: 1 / 3,
})

// TODO: Replicate and improve from old portfolio style
</script>

<template>
<section ref="sectionRef" text="right" transition="composite duration-1000 ease-out-expo" class="section-idx origin-top-left items-center" :class="!isVisible && `opacity-0 scale-x-50 events-none`">
<div flex="~ 1 col" class="group/content works-section-wrapper">
<div transition="composite" ease="out-expo" duration="1000" class="rotate-works">
<h1>{{ t('home.section_2.title') }}</h1>
<ul class="w-screen -translate-x-4" transition="composite" duration="300" ease="out-back">
<li v-for="work in WORKS" :key="work.href" class="group list-works font-extrabold uppercase from-transparent bg-linear-to-r hover:(text-black to-primary)" gap="8" border="b foreground dashed">
<RouterLink :to="work.href || '/not-found'" flex p="y-2" class="text-5xl items-center justify-end" gap="4" transition="composite" ease="out-expo" w="full">
<h1 text="7xl" transition="composite" duration="500" ease="out-expo" class="group-hover:tracking-wider group-hover:-translate-x-1/10">
todo
</h1>
<div class="i-carbon-condition-point" text="3xl" transition="composite" duration="300" ease="out-back" group-hover="rotate-90" />
</RouterLink>
</li>
</ul>
<h2>{{ t('home.section_2.subtitle') }}</h2>
</div>
</div>
</section>
</template>

<style scoped>
.rotate-works {
transform: rotateX(9deg) rotateY(-12deg);
}
</style>
Loading
Loading