[#1] Remove office phone and add email app
All checks were successful
Publish Docker Image / Publish Docker Image (push) Successful in 1m1s
All checks were successful
Publish Docker Image / Publish Docker Image (push) Successful in 1m1s
This commit is contained in:
@@ -15,7 +15,6 @@ import {
|
|||||||
BackSide,
|
BackSide,
|
||||||
} from "three";
|
} from "three";
|
||||||
import { Billboard, Text } from "@react-three/drei";
|
import { Billboard, Text } from "@react-three/drei";
|
||||||
import { useConfig } from "../hooks/useConfig";
|
|
||||||
|
|
||||||
interface ButtonsProps {
|
interface ButtonsProps {
|
||||||
menuTraversal: Stack<View>;
|
menuTraversal: Stack<View>;
|
||||||
@@ -23,7 +22,6 @@ interface ButtonsProps {
|
|||||||
pendingView: View | null;
|
pendingView: View | null;
|
||||||
setPendingView: Dispatch<SetStateAction<View | null>>;
|
setPendingView: Dispatch<SetStateAction<View | null>>;
|
||||||
goPreviousView(): void;
|
goPreviousView(): void;
|
||||||
phoneHovered: boolean;
|
|
||||||
currentView: View;
|
currentView: View;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,11 +33,8 @@ export const Buttons = ({
|
|||||||
pendingView,
|
pendingView,
|
||||||
setPendingView,
|
setPendingView,
|
||||||
goPreviousView,
|
goPreviousView,
|
||||||
phoneHovered,
|
|
||||||
currentView,
|
currentView,
|
||||||
}: ButtonsProps) => {
|
}: ButtonsProps) => {
|
||||||
const config = useConfig();
|
|
||||||
|
|
||||||
const [hovered, setHovered] = useState<View | null>(null);
|
const [hovered, setHovered] = useState<View | null>(null);
|
||||||
|
|
||||||
const desktopRef = useDisableRaycast(currentView !== View.MainView);
|
const desktopRef = useDisableRaycast(currentView !== View.MainView);
|
||||||
@@ -47,8 +42,6 @@ export const Buttons = ({
|
|||||||
const sideRef = useDisableRaycast(currentView !== View.MainView);
|
const sideRef = useDisableRaycast(currentView !== View.MainView);
|
||||||
const cellphoneRef = useDisableRaycast(currentView !== View.DesktopView);
|
const cellphoneRef = useDisableRaycast(currentView !== View.DesktopView);
|
||||||
const pcRef = useDisableRaycast(currentView !== View.DesktopView);
|
const pcRef = useDisableRaycast(currentView !== View.DesktopView);
|
||||||
const resumeRef = useDisableRaycast(currentView !== View.SideView);
|
|
||||||
const phoneRef = useDisableRaycast(currentView !== View.SideView);
|
|
||||||
|
|
||||||
const goToView = useCallback(
|
const goToView = useCallback(
|
||||||
(view: View) => {
|
(view: View) => {
|
||||||
@@ -89,12 +82,12 @@ export const Buttons = ({
|
|||||||
}, [menuTraversal, pendingView, setPendingView]);
|
}, [menuTraversal, pendingView, setPendingView]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (hovered || phoneHovered) {
|
if (hovered) {
|
||||||
document.body.style.cursor = "pointer";
|
document.body.style.cursor = "pointer";
|
||||||
} else {
|
} else {
|
||||||
document.body.style.cursor = "auto";
|
document.body.style.cursor = "auto";
|
||||||
}
|
}
|
||||||
}, [hovered, phoneHovered]);
|
}, [hovered]);
|
||||||
|
|
||||||
const mainMenuSpring = useThreeSpring<MeshStandardMaterial>({
|
const mainMenuSpring = useThreeSpring<MeshStandardMaterial>({
|
||||||
opacity: currentView === View.MainView ? 1 : 0,
|
opacity: currentView === View.MainView ? 1 : 0,
|
||||||
@@ -116,14 +109,11 @@ export const Buttons = ({
|
|||||||
const printerMenuSpring = useThreeSpring<MeshStandardMaterial>({
|
const printerMenuSpring = useThreeSpring<MeshStandardMaterial>({
|
||||||
opacity: currentView === View.PrinterView ? 1 : 0,
|
opacity: currentView === View.PrinterView ? 1 : 0,
|
||||||
});
|
});
|
||||||
const sideMenuSpring = useThreeSpring<MeshStandardMaterial>({
|
|
||||||
opacity: currentView === View.SideView ? 1 : 0,
|
|
||||||
});
|
|
||||||
const desktopViewSpring = useThreeSpring<BufferGeometry>({
|
const desktopViewSpring = useThreeSpring<BufferGeometry>({
|
||||||
scale: hovered === View.DesktopView ? 1.25 : 1,
|
scale: hovered === View.DesktopView ? 1.25 : 1,
|
||||||
});
|
});
|
||||||
const sideViewSpring = useThreeSpring<BufferGeometry>({
|
const resumeViewSpring = useThreeSpring<BufferGeometry>({
|
||||||
scale: hovered === View.SideView ? 1.25 : 1,
|
scale: hovered === View.ResumeView ? 1.25 : 1,
|
||||||
});
|
});
|
||||||
const cellphoneViewSpring = useThreeSpring<BufferGeometry>({
|
const cellphoneViewSpring = useThreeSpring<BufferGeometry>({
|
||||||
scale: hovered === View.CellphoneView ? 1.25 : 1,
|
scale: hovered === View.CellphoneView ? 1.25 : 1,
|
||||||
@@ -134,15 +124,9 @@ export const Buttons = ({
|
|||||||
const creditsViewSpring = useThreeSpring<BufferGeometry>({
|
const creditsViewSpring = useThreeSpring<BufferGeometry>({
|
||||||
scale: hovered === View.CreditsView ? 1.25 : 1,
|
scale: hovered === View.CreditsView ? 1.25 : 1,
|
||||||
});
|
});
|
||||||
const resumeViewSpring = useThreeSpring<BufferGeometry>({
|
|
||||||
scale: hovered === View.ResumeView ? 1.25 : 1,
|
|
||||||
});
|
|
||||||
const printerViewSpring = useThreeSpring<BufferGeometry>({
|
const printerViewSpring = useThreeSpring<BufferGeometry>({
|
||||||
scale: hovered === View.PrinterView ? 1.25 : 1,
|
scale: hovered === View.PrinterView ? 1.25 : 1,
|
||||||
});
|
});
|
||||||
const phoneViewSpring = useThreeSpring<BufferGeometry>({
|
|
||||||
scale: hovered === View.PhoneView ? 1.25 : 1,
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -242,16 +226,16 @@ export const Buttons = ({
|
|||||||
position={[2.525, 6, 6.75]}
|
position={[2.525, 6, 6.75]}
|
||||||
onClick={
|
onClick={
|
||||||
currentView === View.MainView
|
currentView === View.MainView
|
||||||
? () => goToView(View.SideView)
|
? () => goToView(View.ResumeView)
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
onPointerOver={
|
onPointerOver={
|
||||||
currentView === View.MainView
|
currentView === View.MainView
|
||||||
? () => setHovered(View.SideView)
|
? () => setHovered(View.ResumeView)
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
onPointerOut={() => setHovered(null)}
|
onPointerOut={() => setHovered(null)}
|
||||||
scale={sideViewSpring.scale}
|
scale={resumeViewSpring.scale}
|
||||||
>
|
>
|
||||||
<sphereGeometry args={[0.6, 32, 32]} />
|
<sphereGeometry args={[0.6, 32, 32]} />
|
||||||
<animated.meshStandardMaterial
|
<animated.meshStandardMaterial
|
||||||
@@ -260,7 +244,10 @@ export const Buttons = ({
|
|||||||
opacity={mainMenuSpring.opacity}
|
opacity={mainMenuSpring.opacity}
|
||||||
/>
|
/>
|
||||||
</animated.mesh>
|
</animated.mesh>
|
||||||
<animated.mesh position={[2.525, 6, 6.75]} scale={sideViewSpring.scale}>
|
<animated.mesh
|
||||||
|
position={[2.525, 6, 6.75]}
|
||||||
|
scale={resumeViewSpring.scale}
|
||||||
|
>
|
||||||
<sphereGeometry args={[0.65, 32, 32]} />
|
<sphereGeometry args={[0.65, 32, 32]} />
|
||||||
<animated.meshStandardMaterial
|
<animated.meshStandardMaterial
|
||||||
transparent
|
transparent
|
||||||
@@ -277,7 +264,7 @@ export const Buttons = ({
|
|||||||
fillOpacity={mainMenuSpring.opacity}
|
fillOpacity={mainMenuSpring.opacity}
|
||||||
outlineOpacity={mainMenuSpring.opacity}
|
outlineOpacity={mainMenuSpring.opacity}
|
||||||
>
|
>
|
||||||
Resume & Contact
|
Resume
|
||||||
</AnimatedText>
|
</AnimatedText>
|
||||||
</Billboard>
|
</Billboard>
|
||||||
</group>
|
</group>
|
||||||
@@ -450,105 +437,6 @@ export const Buttons = ({
|
|||||||
</AnimatedText>
|
</AnimatedText>
|
||||||
</Billboard>
|
</Billboard>
|
||||||
</group>
|
</group>
|
||||||
{/* Side Menu */}
|
|
||||||
<group>
|
|
||||||
<animated.mesh
|
|
||||||
ref={resumeRef}
|
|
||||||
position={[2.845, 4.75, 6.454]}
|
|
||||||
onClick={
|
|
||||||
currentView === View.SideView
|
|
||||||
? () => goToView(View.ResumeView)
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
onPointerOver={
|
|
||||||
currentView === View.SideView
|
|
||||||
? () => setHovered(View.ResumeView)
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
onPointerOut={() => setHovered(null)}
|
|
||||||
scale={resumeViewSpring.scale}
|
|
||||||
>
|
|
||||||
<sphereGeometry args={[0.175, 32, 32]} />
|
|
||||||
<animated.meshStandardMaterial
|
|
||||||
transparent
|
|
||||||
color="white"
|
|
||||||
opacity={sideMenuSpring.opacity}
|
|
||||||
/>
|
|
||||||
</animated.mesh>
|
|
||||||
<animated.mesh
|
|
||||||
position={[2.845, 4.75, 6.454]}
|
|
||||||
scale={resumeViewSpring.scale}
|
|
||||||
>
|
|
||||||
<sphereGeometry args={[0.175 + 7 / 480, 32, 32]} />
|
|
||||||
<animated.meshStandardMaterial
|
|
||||||
transparent
|
|
||||||
color="black"
|
|
||||||
opacity={sideMenuSpring.opacity}
|
|
||||||
side={BackSide}
|
|
||||||
/>
|
|
||||||
</animated.mesh>
|
|
||||||
<Billboard position={[2.845, 5.1875, 6.454]}>
|
|
||||||
<AnimatedText
|
|
||||||
font="/assets/inter.ttf"
|
|
||||||
fontSize={0.21875}
|
|
||||||
outlineWidth={7 / 480}
|
|
||||||
fillOpacity={sideMenuSpring.opacity}
|
|
||||||
outlineOpacity={sideMenuSpring.opacity}
|
|
||||||
>
|
|
||||||
Resume
|
|
||||||
</AnimatedText>
|
|
||||||
</Billboard>
|
|
||||||
{config.phoneNumber && (
|
|
||||||
<>
|
|
||||||
<animated.mesh
|
|
||||||
ref={phoneRef}
|
|
||||||
position={[3.75, 5.125, 7]}
|
|
||||||
onClick={
|
|
||||||
currentView === View.SideView
|
|
||||||
? () => goToView(View.PhoneView)
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
onPointerOver={
|
|
||||||
currentView === View.SideView
|
|
||||||
? () => setHovered(View.PhoneView)
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
onPointerOut={() => setHovered(null)}
|
|
||||||
scale={phoneViewSpring.scale}
|
|
||||||
>
|
|
||||||
<sphereGeometry args={[0.175, 32, 32]} />
|
|
||||||
<animated.meshStandardMaterial
|
|
||||||
transparent
|
|
||||||
color="white"
|
|
||||||
opacity={sideMenuSpring.opacity}
|
|
||||||
/>
|
|
||||||
</animated.mesh>
|
|
||||||
<animated.mesh
|
|
||||||
position={[3.75, 5.125, 7]}
|
|
||||||
scale={phoneViewSpring.scale}
|
|
||||||
>
|
|
||||||
<sphereGeometry args={[0.175 + 7 / 480, 32, 32]} />
|
|
||||||
<animated.meshStandardMaterial
|
|
||||||
transparent
|
|
||||||
color="black"
|
|
||||||
opacity={sideMenuSpring.opacity}
|
|
||||||
side={BackSide}
|
|
||||||
/>
|
|
||||||
</animated.mesh>
|
|
||||||
<Billboard position={[3.75, 5.515, 7]}>
|
|
||||||
<AnimatedText
|
|
||||||
font="/assets/inter.ttf"
|
|
||||||
fontSize={0.21875}
|
|
||||||
outlineWidth={7 / 480}
|
|
||||||
fillOpacity={sideMenuSpring.opacity}
|
|
||||||
outlineOpacity={sideMenuSpring.opacity}
|
|
||||||
>
|
|
||||||
Contact
|
|
||||||
</AnimatedText>
|
|
||||||
</Billboard>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</group>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ export function Scene(props: JSX.IntrinsicElements["group"]) {
|
|||||||
|
|
||||||
// States
|
// States
|
||||||
const [pendingView, setPendingView] = useState<View | null>(null);
|
const [pendingView, setPendingView] = useState<View | null>(null);
|
||||||
const [phoneHovered, setPhoneHovered] = useState(false);
|
|
||||||
const [backHovered, setBackHovered] = useState(false);
|
const [backHovered, setBackHovered] = useState(false);
|
||||||
const [backClicked, setBackClicked] = useState(false);
|
const [backClicked, setBackClicked] = useState(false);
|
||||||
const [menuTraversal, setMenuTraversal] = useState<Stack<View>>(() => {
|
const [menuTraversal, setMenuTraversal] = useState<Stack<View>>(() => {
|
||||||
@@ -182,7 +181,6 @@ export function Scene(props: JSX.IntrinsicElements["group"]) {
|
|||||||
pendingView={pendingView}
|
pendingView={pendingView}
|
||||||
setPendingView={setPendingView}
|
setPendingView={setPendingView}
|
||||||
goPreviousView={goPreviousView}
|
goPreviousView={goPreviousView}
|
||||||
phoneHovered={phoneHovered}
|
|
||||||
currentView={currentView}
|
currentView={currentView}
|
||||||
/>
|
/>
|
||||||
<group>
|
<group>
|
||||||
@@ -321,67 +319,6 @@ export function Scene(props: JSX.IntrinsicElements["group"]) {
|
|||||||
</Html>
|
</Html>
|
||||||
</mesh>
|
</mesh>
|
||||||
</group>
|
</group>
|
||||||
<group
|
|
||||||
position={[4, 4.74056, 7.25]}
|
|
||||||
rotation={[-Math.PI, -Math.PI / 4, -Math.PI]}
|
|
||||||
scale={0.3}
|
|
||||||
>
|
|
||||||
<group
|
|
||||||
position={[-0.45957, -1.57735, -0.97302]}
|
|
||||||
rotation={[-Math.PI / 2, 0, 0]}
|
|
||||||
scale={100}
|
|
||||||
onClick={
|
|
||||||
config.phoneNumber && currentView === View.PhoneView
|
|
||||||
? () => {
|
|
||||||
window.open(
|
|
||||||
`tel:${config.phoneNumber}`,
|
|
||||||
"_blank",
|
|
||||||
"noopener,noreferrer"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
onPointerOver={
|
|
||||||
config.phoneNumber && currentView === View.PhoneView
|
|
||||||
? () => setPhoneHovered(true)
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
onPointerOut={() => setPhoneHovered(false)}
|
|
||||||
>
|
|
||||||
<mesh
|
|
||||||
castShadow
|
|
||||||
receiveShadow
|
|
||||||
geometry={nodes.Top.geometry}
|
|
||||||
material={materials.TopMaterial}
|
|
||||||
/>
|
|
||||||
<mesh
|
|
||||||
castShadow
|
|
||||||
receiveShadow
|
|
||||||
geometry={nodes.OfficePhoneBody.geometry}
|
|
||||||
material={materials.OfficePhoneBodyMaterial}
|
|
||||||
/>
|
|
||||||
<mesh
|
|
||||||
castShadow
|
|
||||||
receiveShadow
|
|
||||||
geometry={nodes.Screen.geometry}
|
|
||||||
material={materials.ScreenMaterial}
|
|
||||||
/>
|
|
||||||
<mesh
|
|
||||||
castShadow
|
|
||||||
receiveShadow
|
|
||||||
geometry={nodes.Buttons.geometry}
|
|
||||||
material={materials.HandleAndButtonsMaterial}
|
|
||||||
/>
|
|
||||||
<mesh
|
|
||||||
castShadow
|
|
||||||
receiveShadow
|
|
||||||
geometry={nodes.Handle.geometry}
|
|
||||||
material={materials.HandleAndButtonsMaterial}
|
|
||||||
position={[-0.01639, -0.0078, 0.02006]}
|
|
||||||
rotation={[-0.37437, 0, Math.PI / 2]}
|
|
||||||
/>
|
|
||||||
</group>
|
|
||||||
</group>
|
|
||||||
<Text
|
<Text
|
||||||
position={[-2.415, 12.5, -6]}
|
position={[-2.415, 12.5, -6]}
|
||||||
font="/assets/inter-bold.ttf"
|
font="/assets/inter-bold.ttf"
|
||||||
|
|||||||
@@ -36,11 +36,6 @@ export const views: PerspectiveCameraProps[] = [
|
|||||||
position: [3.0143, 5.5, 6.0997],
|
position: [3.0143, 5.5, 6.0997],
|
||||||
rotation: [-2.55743, -0.69621, -2.74104],
|
rotation: [-2.55743, -0.69621, -2.74104],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
// SideView
|
|
||||||
position: [0.5, 7.75, 4.15],
|
|
||||||
rotation: [-2.1005, -0.68155, -2.35619],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
// CreditsView
|
// CreditsView
|
||||||
position: [1.25, 5.9822, -2.075],
|
position: [1.25, 5.9822, -2.075],
|
||||||
@@ -56,8 +51,7 @@ export enum View {
|
|||||||
CellphoneView = 4,
|
CellphoneView = 4,
|
||||||
DesktopView = 5,
|
DesktopView = 5,
|
||||||
PhoneView = 6,
|
PhoneView = 6,
|
||||||
SideView = 7,
|
CreditsView = 7,
|
||||||
CreditsView = 8,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const hashtoView: Record<string, View> = {
|
export const hashtoView: Record<string, View> = {
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import {
|
|||||||
mdiWifi,
|
mdiWifi,
|
||||||
mdiBattery80,
|
mdiBattery80,
|
||||||
mdiHelp,
|
mdiHelp,
|
||||||
|
mdiEmail,
|
||||||
} from "@mdi/js";
|
} from "@mdi/js";
|
||||||
import Icon from "@mdi/react";
|
import Icon from "@mdi/react";
|
||||||
import { useRef, useState } from "react";
|
import { useRef, useState } from "react";
|
||||||
@@ -88,6 +89,17 @@ export const CellphoneUI = () => {
|
|||||||
<div className={`${appClass} ${fillerClass}`}>
|
<div className={`${appClass} ${fillerClass}`}>
|
||||||
<Icon path={mdiCalculator} className="text-neutral-300" />
|
<Icon path={mdiCalculator} className="text-neutral-300" />
|
||||||
</div>
|
</div>
|
||||||
|
{config.email && (
|
||||||
|
<a
|
||||||
|
href={`mailto:${config.email}`}
|
||||||
|
target="_blank"
|
||||||
|
className={appClass}
|
||||||
|
onMouseOver={handleEnter}
|
||||||
|
onMouseOut={handleLeave}
|
||||||
|
>
|
||||||
|
<Icon path={mdiEmail} className="text-neutral-300" />
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
{config.socials?.matrix && (
|
{config.socials?.matrix && (
|
||||||
<a
|
<a
|
||||||
href={`https://matrix.to/#/${config.socials.matrix}`}
|
href={`https://matrix.to/#/${config.socials.matrix}`}
|
||||||
|
|||||||
@@ -66,6 +66,11 @@ export async function register() {
|
|||||||
format: "phone",
|
format: "phone",
|
||||||
nullable: true,
|
nullable: true,
|
||||||
},
|
},
|
||||||
|
email: {
|
||||||
|
type: "string",
|
||||||
|
format: "email",
|
||||||
|
nullable: true,
|
||||||
|
},
|
||||||
fallbackUrl: {
|
fallbackUrl: {
|
||||||
type: "string",
|
type: "string",
|
||||||
format: "uri",
|
format: "uri",
|
||||||
|
|||||||
1
src/types/config.d.ts
vendored
1
src/types/config.d.ts
vendored
@@ -16,6 +16,7 @@ export interface Config {
|
|||||||
tags?: string[];
|
tags?: string[];
|
||||||
}[];
|
}[];
|
||||||
phoneNumber?: string;
|
phoneNumber?: string;
|
||||||
|
email?: string;
|
||||||
fallbackUrl?: string;
|
fallbackUrl?: string;
|
||||||
name: [string, string];
|
name: [string, string];
|
||||||
status?: string;
|
status?: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user