Skip to content

Commit

Permalink
FEATURE(contact): 初始化 Creepy Face
Browse files Browse the repository at this point in the history
  • Loading branch information
SuneBear committed Sep 22, 2023
1 parent 4b801db commit 40e04c2
Show file tree
Hide file tree
Showing 17 changed files with 277 additions and 7 deletions.
2 changes: 1 addition & 1 deletion app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import '~/styles/main.styl'
// Scaffolding
body
margin: 0
font-family: "Inter", "Roboto", "Helvetica", "Arial", sans-serif
font-family: "Noto Sans SC", "Inter", "Roboto", "Helvetica", "Arial", sans-serif
background: $secondary100
color: $primary100
font-size: 1rem
Expand Down
78 changes: 78 additions & 0 deletions components/business-card.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<template lang="pug">
hover-spotlight-card.business-card.flex.gap-40px(
class="lt-sm:flex-col"
:rotateFactor="5"
:light-size="500"
enableOutside
enableParallax
@click="handleCardClick"
)
sune-creepy-face.flex-shrink-0
.main-part.flex.flex-col.flex-1.flex-justify-between
.top-part
h2.info-name.my-0 熊舒乐
h3.info-title.mt-2 {{age}} 岁 · 前端工程师

.bottom-part.text-right
p.my-0.into-contact( @click.stop="handleCopyClick(wechat)" ) 微信:{{ wechat }}
p.my-0.into-contact( @click.stop="handleCopyClick(email)" ) 邮箱:{{ email }}
</template>

<script lang="ts" setup>
import { useClipboard } from '@vueuse/core'
const { copy } = useClipboard()
const birthDate = new Date('1994-10-11')
const nowDate = new Date()
const wechat = 'sune94'
const email = 'hi@sunebear.com'
const age = computed(() => {
return nowDate.getFullYear() - birthDate.getFullYear()
})
const handleCardClick = () => {
// window.open(`mailto:${email}?subject=前端外包合作`)
}
const handleCopyClick = (val: string) => {
// copy(val)
}
</script>

<style lang="stylus">
.business-card
--radius: 2px
--light-color: brand(5)
padding: 30px
width: s('min(80vw, 500px)')
aspect-ratio: 1/0.55
// cursor pointer
@media $mediaInMobile
aspect-ratio: 0.65/1
activeState()
background: white
box-shadow: 2px 2px 24px 0px rgba(0, 0, 0, 0.1)
@media $mediaInMobile
activeState()
&:hover
activeState()
// @TODO: 把 Mask 抽象成组件
.main-part
mask-image: repeating-linear-gradient(black, black 2px, transparent 2.5px)
.info-name
font-size: 40px
font-weight: 100
.info-title
opacity: 0.7
font-weight: 400
.into-contact
opacity: 0.8
</style>
86 changes: 86 additions & 0 deletions components/hover-spotlight-card.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<template lang="pug">
.hover-spotlight-card(
ref="el"
:class="{ 'enable-parallax': enableParallax }"
:style="{ '--cursor-x': elementX, '--cursor-y': elementY, '--light-size': `${lightSize}px`, ...transformStyle }"
)
.spotlight( v-if="enableHover" )
slot
</template>

<script setup lang="ts">
import { useMouseInElement } from '@vueuse/core'
const props = withDefaults(defineProps<{
enableHover: boolean,
enableParallax: boolean,
enableOutside: boolean,
rotateFactor: number
lightSize: number
}>(), {
lightSize: 400,
rotateFactor: 15,
enableHover: true
})
const el = ref(null)
const cardMouse = useMouseInElement(el, { handleOutside: props.enableOutside })
const { elementX, elementY, isOutside } = cardMouse
const transformStyle = computed(() => {
if (!props.enableParallax) return
const x = cardMouse.elementX.value - cardMouse.elementWidth.value / 2
const y = cardMouse.elementY.value - cardMouse.elementHeight.value / 2
const mousePX = x / cardMouse.elementWidth.value
const mousePY = y / cardMouse.elementHeight.value
const rx = mousePX * props.rotateFactor
const ry = mousePY * props.rotateFactor
return {
transform: (cardMouse.isOutside.value && !props.enableOutside) ? null : `perspective(800px) rotateY(${rx}deg) rotateX(${ry}deg)`
}
})
defineExpose({
isOutside
})
</script>

<style lang="stylus">
.hover-spotlight-card
overflow: hidden
position: relative
--light-color: brand(8)
--radius: 12px
--border: 2px
--y: s('calc(var(--cursor-y) * 1px)')
--x: s('calc(var(--cursor-x) * 1px)')
&.enable-parallax
transition: all 318ms, transform 0.6s cubic-bezier(0.23, 1, 0.32, 1)
transform-style: preserve-3d
.spotlight
pointer-events: none;
user-select: none;
position: absolute;
z-index: 1;
opacity: 0;
top: var(--border);
bottom: var(--border);
left: var(--border);
right: var(--border);
border-radius: var(--radius);
will-change: background, opacity;
background: radial-gradient(var(--light-size) circle at var(--x) var(--y), var(--light-color),transparent)
contain: strict
transition: opacity 400ms ease 0s
&:hover
.spotlight
opacity: 1
/html.dark &
--light-color: rgba(255,255,255,0.1)
</style>
72 changes: 72 additions & 0 deletions components/sune-creepy-face.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<template lang="pug">
.sune-creepy-face(
data-augmented-ui="tr-clip bl-clip br-clip-y both"
)
img(
:class="{ 'need-flip': needFlip }"
ref="faceImg"
src="/sune-creepy-face/serious.jpg"
)
</template>

<script lang="ts" setup>
import creepyface from 'creepyface'
const faceImg = ref<HTMLImageElement>()
const needFlip = ref(false)
const initFace = () => {
if (!faceImg.value) return
// @TODO: 重新拍一组度数颗粒更小的
creepyface(faceImg.value, {
hover: '/sune-creepy-face/hover.jpg',
looks: [
{ angle: 0, src: '/sune-creepy-face/0.jpg' },
{ angle: 45, src: '/sune-creepy-face/45.jpg' },
{ angle: 45 + 270, src: '/sune-creepy-face/45.jpg' },
{ angle: 90, src: '/sune-creepy-face/90.jpg' },
{ angle: 90 + 180, src: '/sune-creepy-face/90.jpg' },
{ angle: 135, src: '/sune-creepy-face/135.jpg' },
{ angle: 135 + 90, src: '/sune-creepy-face/135.jpg' },
{ angle: 180, src: '/sune-creepy-face/180.jpg' },
],
fieldOfVision: 0,
// timeToDefault: -1,
timeToDefault: 1500,
onDebug: ({src, point, angle}) => {
needFlip.value = angle as number > 200
&& !src.includes('180.jpg')
&& !src.includes('/0.jpg')
}
})
}
onMounted(() => {
initFace()
})
</script>

<style lang="stylus">
.sune-creepy-face
--aug-border-all: 2px
--aug-border-bg: '#383838'
--aug-tr: 10px
--aug-bl: 13px
--aug-br: 10px
width: 144px
height: 144px
background-image: linear-gradient(transparent 0%, rgba(187, 187, 187, 0.5) 50%)
background-size: 1000px 3px
// border-top-left-radius: 10px
overflow hidden
img
display: block
width: 100%
height: 100%
opacity: 0.7
&.need-flip
transform: scaleX(-1)
</style>
8 changes: 6 additions & 2 deletions nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export default defineNuxtConfig({

app: {
head: {
title: "Stylus Pug Starter",
title: "熊舒乐的自由职业之路",
meta: [
{
"name": "viewport",
Expand All @@ -48,7 +48,11 @@ export default defineNuxtConfig({
}
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.png' }
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.png' },
{ href: '/augmented-ui.min.css', rel: 'stylesheet', type: 'text/css' },
{ href: 'https://fonts.googleapis.com', rel: 'preconnect' },
{ href: 'https://fonts.gstatic.com', rel: 'preconnect', crossorigin: true },
{ href: 'https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@100;300;400;500;600;700&display=swap', rel: 'stylesheet' }
],
script: [
{ id: 'check-dark-light',
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"unplugin-icons": "^0.17.0"
},
"dependencies": {
"@vueuse/core": "^10.4.1"
"@vueuse/core": "^10.4.1",
"creepyface": "^8.1.3"
}
}
19 changes: 17 additions & 2 deletions pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,29 @@
nuxt-icon( name="youtube" )

theme-switcher

.section.section-contact.flex.flex-col.items-center.gap-5vh
business-card
</template>

<script lang="ts" setup>
</script>

<style lang="stylus">
.page.page-home
max-width: 1000px
margin: 0 auto
padding: 20px fluid-value(20, 100)
// max-width: 1000px
// padding: 20px fluid-value(20, 100)
.section
width: 100%
height: 100vh
height: 100dvh
background-color: #FFFFFA
.section-contact
padding-top: 25dvh
@media $mediaInMobile
padding-top: 10dvh
</style>
9 changes: 9 additions & 0 deletions public/augmented-ui.min.css

Large diffs are not rendered by default.

Binary file added public/sune-creepy-face/0.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/sune-creepy-face/135.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/sune-creepy-face/180.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/sune-creepy-face/45.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/sune-creepy-face/90.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/sune-creepy-face/hover.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/sune-creepy-face/serious.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion styles/themes/basic.styl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Default theme is light
:root
defineColorVar(--brand, #5438FF)
defineColorVar(--brand, #3898ff)
--brand-gradient: linear-gradient(180deg, #0E55EE 0%, #002A86 100%)
--v-primary-rgb: 66, 66, 66
--v-secondary-rgb: 255, 255, 255
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2431,6 +2431,11 @@ create-require@^1.1.1:
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==

creepyface@^8.1.3:
version "8.1.3"
resolved "https://registry.yarnpkg.com/creepyface/-/creepyface-8.1.3.tgz#d08ea3739f5a44e3b70bed87df2a1107273eba0b"
integrity sha512-YJ1G0eGb0aL3hYmVkWmEHaR9VvTIu1Fh/veD2Y8G+flhdovI/+y7WmxV1L1GSPF8x/8Ena81PpCFvZIPeN6s4g==

cross-spawn@^7.0.0, cross-spawn@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
Expand Down

0 comments on commit 40e04c2

Please sign in to comment.