({
+ charging: false,
+ chargingTime: 0,
+ dischargingTime: 0,
+ level: 1,
+ });
+ const batteryPercent = useMemo(() => (battery.level * 100).toString() + "%", [battery]);
+ const batteryIcon = useMemo(() => {
+ if (battery.charging) {
+ return ;
+ }
+
+ if (battery.level !== 1) {
+ return ;
+ }
+
+ return ;
+ }, [battery]);
+
+ useEffect(() => {
+ window.navigator.getBattery?.().then((battery) => setBattery(battery));
+ }, []);
+
+ return (
+
+ {batteryPercent}
+ {batteryIcon}
+
+ );
+};
diff --git a/app/home/components/Profile/Profile.css.ts b/app/components/Profile/Profile.css.ts
similarity index 100%
rename from app/home/components/Profile/Profile.css.ts
rename to app/components/Profile/Profile.css.ts
diff --git a/app/home/components/Profile/index.tsx b/app/components/Profile/index.tsx
similarity index 95%
rename from app/home/components/Profile/index.tsx
rename to app/components/Profile/index.tsx
index dc35376..04d28ab 100644
--- a/app/home/components/Profile/index.tsx
+++ b/app/components/Profile/index.tsx
@@ -2,7 +2,7 @@ import Image from "next/image";
import Link from "next/link";
import { PiGithubLogo, PiLinkedinLogo } from "react-icons/pi";
-import { Window } from "../../../components/Window";
+import { Window } from "../Window";
import * as css from "./Profile.css";
export const Profile = () => {
diff --git a/app/home/components/Resume/Resume.css.ts b/app/components/Resume/Resume.css.ts
similarity index 100%
rename from app/home/components/Resume/Resume.css.ts
rename to app/components/Resume/Resume.css.ts
diff --git a/app/home/components/Resume/index.tsx b/app/components/Resume/index.tsx
similarity index 91%
rename from app/home/components/Resume/index.tsx
rename to app/components/Resume/index.tsx
index 21b40da..bf6873d 100644
--- a/app/home/components/Resume/index.tsx
+++ b/app/components/Resume/index.tsx
@@ -3,8 +3,8 @@ import axios from "axios";
import { PDFium } from "pdfium.js";
import { useCallback, useEffect, useRef, useState } from "react";
-import { Window } from "../../../components/Window";
-import { PDFRenderer } from "../../../modules/pdf-renderer";
+import { Window } from "../Window";
+import { PDFRenderer } from "../../modules/pdf-renderer";
import * as css from "./Resume.css";
export const Resume = () => {
diff --git a/app/home/components/Settings/Settings.css.ts b/app/components/Settings/Settings.css.ts
similarity index 100%
rename from app/home/components/Settings/Settings.css.ts
rename to app/components/Settings/Settings.css.ts
diff --git a/app/home/components/Settings/index.tsx b/app/components/Settings/index.tsx
similarity index 92%
rename from app/home/components/Settings/index.tsx
rename to app/components/Settings/index.tsx
index e3982f0..f085385 100644
--- a/app/home/components/Settings/index.tsx
+++ b/app/components/Settings/index.tsx
@@ -1,5 +1,5 @@
import type { PropsWithChildren } from "react";
-import { Window } from "../../../components/Window";
+import { Window } from "../Window";
import * as css from "./Settings.css";
interface RowProps {
diff --git a/app/home/components/Shortcuts.tsx b/app/components/Shortcuts.tsx
similarity index 94%
rename from app/home/components/Shortcuts.tsx
rename to app/components/Shortcuts.tsx
index df959cb..143129d 100644
--- a/app/home/components/Shortcuts.tsx
+++ b/app/components/Shortcuts.tsx
@@ -2,8 +2,8 @@
import Image from "next/image";
import { useCallback, useContext } from "react";
-import { Shortcut } from "../../components/Shortcut";
-import { LayerContext } from "../../contexts/LayerContext";
+import { LayerContext } from "../contexts/LayerContext";
+import { Shortcut } from "./Shortcut";
export const ProfileShortcut = () => {
const { addLayer } = useContext(LayerContext);
diff --git a/app/components/Window/index.tsx b/app/components/Window/index.tsx
index c3291a5..a3f11ad 100644
--- a/app/components/Window/index.tsx
+++ b/app/components/Window/index.tsx
@@ -2,8 +2,9 @@
import { assignInlineVars } from "@vanilla-extract/dynamic";
import { useCallback, useState } from "react";
-import { useDrag } from "../../hooks";
-import type { DragEvent, DragEventHandler } from "../../hooks/useDrag";
+import { useDrag } from "@/hooks";
+import type { DragEvent, DragEventHandler } from "@/hooks/useDrag";
+
import { Layer } from "../Layer";
import * as css from "./Window.css";
diff --git a/app/components/lock-screen/index.tsx b/app/components/lock-screen/index.tsx
new file mode 100644
index 0000000..d963a1a
--- /dev/null
+++ b/app/components/lock-screen/index.tsx
@@ -0,0 +1,32 @@
+"use client";
+import { assignInlineVars } from "@vanilla-extract/dynamic";
+import { useContext, useEffect, useState } from "react";
+
+import { LockContext } from "@/contexts/LockContext";
+import { ClockIndicator } from "../ClockIndicator";
+import { LoginProfile } from "../LoginProfile";
+import { Wallpaper } from "../Wallpaper";
+import * as css from "./lock-screen.css";
+
+export const LockScreen = () => {
+ const { isLocked } = useContext(LockContext);
+ const [isVisible, setVisible] = useState(true);
+
+ useEffect(() => {
+ if (isLocked && !isVisible) {
+ setVisible(true);
+ }
+ }, [isLocked, isVisible]);
+
+ return (
+ setVisible(false)}
+ >
+
+
+
+
+ );
+};
diff --git a/app/components/lock-screen/lock-screen.css.ts b/app/components/lock-screen/lock-screen.css.ts
new file mode 100644
index 0000000..c21bbbe
--- /dev/null
+++ b/app/components/lock-screen/lock-screen.css.ts
@@ -0,0 +1,40 @@
+import { createVar, keyframes, style } from "@vanilla-extract/css";
+
+export const isVisible = createVar();
+
+export const wrapper = style({
+ position: "absolute",
+ inset: 0,
+ zIndex: 100,
+ visibility: isVisible,
+});
+
+const unlock = keyframes({
+ "0%": {
+ opacity: 1,
+ },
+ "100%": {
+ opacity: 0,
+ }
+});
+
+const lock = keyframes({
+ "0%": {
+ opacity: 0,
+ },
+ "100%": {
+ opacity: 1,
+ },
+});
+
+export const unlockAnim = style([wrapper, {
+ animationName: unlock,
+ animationDuration: "0.25s",
+ animationFillMode: "forwards",
+}]);
+
+export const lockAnim = style([wrapper, {
+ animationName: lock,
+ animationDuration: "0.25s",
+ animationFillMode: "forwards",
+}]);
diff --git a/app/contexts/LockContext.ts b/app/contexts/LockContext.ts
new file mode 100644
index 0000000..b5dc3fd
--- /dev/null
+++ b/app/contexts/LockContext.ts
@@ -0,0 +1,13 @@
+import { createContext } from "react";
+
+export interface ILockContext {
+ isLocked: boolean;
+ lock: () => void;
+ unlock: () => void;
+}
+
+export const LockContext = createContext({
+ isLocked: false,
+ lock: () => {},
+ unlock: () => {},
+});
diff --git a/app/contexts/MenuBarContext.ts b/app/contexts/MenuBarContext.ts
new file mode 100644
index 0000000..7a04892
--- /dev/null
+++ b/app/contexts/MenuBarContext.ts
@@ -0,0 +1,23 @@
+import { createContext } from "react";
+
+type MenuItemType = "default" | "check" | "sub-menu" | "divider";
+export interface MenuItem {
+ id: string;
+ name: string;
+ type: MenuItemType;
+ disabled: boolean;
+ checked: boolean;
+ onClick: () => void;
+}
+
+export interface IMenuBarContext {
+ openedMenuId: string | null;
+ openMenu: (menuId: string) => void;
+ closeMenu: () => void;
+}
+
+export const menuBarContext = createContext({
+ openedMenuId: null,
+ openMenu: (_) => {},
+ closeMenu: () => {},
+});
diff --git a/app/home/page.tsx b/app/home/page.tsx
deleted file mode 100644
index 77fb5df..0000000
--- a/app/home/page.tsx
+++ /dev/null
@@ -1,87 +0,0 @@
-import { LayerManager } from "../components/Layer";
-import { MenuBar } from "../components/MenuBar";
-import { Profile } from "./components/Profile";
-import { Resume } from "./components/Resume";
-import { Settings } from "./components/Settings";
-import * as Shortcut from "./components/Shortcuts";
-// import { scrollbarStyle } from "../../components/WindowFrame";
-
-// const GitHubRepoWrapper = styled.div`
-// width: 100%;
-// margin: 4px 0;
-// padding: 12px 10px;
-// display: flex;ㄷㄷㄴㅇㅊㄴㅌ
-// flex-direction: column;
-// border: 1px rgba(255, 255, 255, 0.25) solid;
-// border-radius: 3px;
-// cursor: pointer;
-// transition: all 0.15s ease-out;
-// :hover {
-// background-color: rgba(255, 255, 255, 0.02);
-// }
-// > .repo-title {
-// display: flex;
-// align-items: baseline;
-// margin-bottom: 8px;
-// > .ant-typography {
-// margin-left: 6px;
-// font-size: 16px;
-// font-weight: 500;
-// }
-// }
-// > .ant-typography {
-// font-size: 12px;
-// font-weight: 300;
-// color: rgba(255, 255, 255, 0.8);
-// }
-// > .repo-language {
-// margin-top: 12px;
-// display: flex;
-// align-items: baseline;
-
-// > .lang-color {
-// width: 8px;
-// height: 8px;
-// border-radius: 4px;
-// margin-right: 4px;
-// }
-// > .ant-typography {
-// color: rgba(255, 255, 255, 0.6);
-// font-size: 10px;
-// }
-// }
-// `;
-
-// const RepositoryTab = (props: RepositoryTabProps) => {
-// const { loading, repositories } = props;
-
-// return (
-//
-// {loading ? (
-// } />
-// ) : repositories.length ? (
-// repositories.map((repo, i) => )
-// ) : (
-// No repository
-// )}
-//
-// );
-// };
-
-const Main = () => {
- return (
-
-
-
-
-
-
-
-
-
-
-
- );
-};
-
-export default Main;
diff --git a/app/login/page.tsx b/app/login/page.tsx
deleted file mode 100644
index 952b5e1..0000000
--- a/app/login/page.tsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import { ClockIndicator } from "./components/ClockIndicator";
-import { LoginProfile } from "./components/LoginProfile";
-
-const Login = () => {
- return (
- <>
-
-
- >
- );
-};
-
-export default Login;
diff --git a/app/page.tsx b/app/page.tsx
index 0313b5a..6d7b335 100644
--- a/app/page.tsx
+++ b/app/page.tsx
@@ -1,7 +1,50 @@
-import { redirect } from "next/navigation";
+"use client";
+import { useCallback, useState } from "react";
+
+import { LockContext } from "./contexts/LockContext";
+import type { ILockContext } from "./contexts/LockContext";
+import { LockScreen } from "./components/lock-screen";
+import { LayerManager } from "./components/Layer";
+import { MenuBar } from "./components/MenuBar";
+import * as Menus from "./components/Menus";
+import * as Shortcut from "./components/Shortcuts";
+import { Resume } from "./components/Resume";
+import { Profile } from "./components/Profile";
+import { Settings } from "./components/Settings";
const Index = () => {
- redirect("/login");
+ const [isLocked, setLock] = useState(true);
+ const lock = useCallback(() => setLock(true), []);
+ const unlock = useCallback(() => setLock(false), []);
+
+ const lockContextValue: ILockContext = {
+ isLocked,
+ lock,
+ unlock,
+ };
+
+ return (
+
+
+ ]}
+ rightMenu={[
+ ,
+ ,
+ ]}
+ />
+
+
+
+
+
+
+
+
+
+
+
+ );
};
export default Index;
diff --git a/app/window.d.ts b/app/window.d.ts
new file mode 100644
index 0000000..73cad7a
--- /dev/null
+++ b/app/window.d.ts
@@ -0,0 +1,15 @@
+
+declare global {
+ interface Battery {
+ charging: boolean;
+ chargingTime: number;
+ dischargingTime: number;
+ level: number;
+ }
+
+ interface Navigator extends globalThis.Navigator {
+ getBattery?: () => Promise;
+ }
+}
+
+export { Battery };
diff --git a/tsconfig.json b/tsconfig.json
index 28f53ec..b3761fd 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -24,7 +24,10 @@
{
"name": "next"
}
- ]
+ ],
+ "paths": {
+ "@/*": ["./app/*"],
+ }
},
"include": [
"**/*.ts",