Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
hamster1963 committed Jul 26, 2024
0 parents commit 3085a41
Show file tree
Hide file tree
Showing 66 changed files with 2,172 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
NezhaBaseUrl=http://0.0.0.0:8008
NezhaAuth=5hAY3QX6Nl9B3UOQgB26KdsdS1dsdUdM
Binary file added .github/shotOne.png
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 .github/shotTwo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
48 changes: 48 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts

# pwa
/public/sw.js
/public/sw.js.map
/public/swe-worker-development.js
/public/workbox*.js
/public/workbox*.js.map

/.idea/

.env

10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<h1 align="center">HomeDash</h1>
<div align="center">
<strong>HomeDash 是一个基于 Next.js 和 Shadcn 的仪表盘</strong>
<br>
<strong>Demo地址: https://dash.buycoffee.top</strong>

![screen-shot-one](/.github/shotOne.png)
![screen-shot-two](/.github/shotTwo.png)

</div>
43 changes: 43 additions & 0 deletions app/(main)/ClientComponents/LiveTag.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"use client";
import { useEffect, useState } from "react";
import { toast } from "sonner";

import { Badge } from "@/components/ui/badge";
import { verifySSEConnection } from "@/lib/sseFetch";

export default function LiveTag() {
const [connected, setConnected] = useState(false);

useEffect(() => {
// Store the promise in a variable
const ssePromise = verifySSEConnection(
"https://home.buycoffee.tech/v2/VerifySSEConnect",
);
setTimeout(() => {
toast.promise(ssePromise, {
loading: "Connecting to SSE...",
success: "HomeDash SSE Connected",
error: "Error connecting to SSE",
});
});
// Handle promise resolution separately
ssePromise
.then(() => {
setConnected(true);
})
.catch(() => {
setConnected(false);
});
}, []);

return connected ? (
<Badge className={"flex items-center justify-center gap-1 px-2"}>
Synced
<span className="h-2 w-2 rounded-full bg-green-500"></span>
</Badge>
) : (
<Badge className={"flex items-center justify-center gap-1 px-2"}>
Static<span className="h-2 w-2 rounded-full bg-red-500"></span>
</Badge>
);
}
34 changes: 34 additions & 0 deletions app/(main)/ClientComponents/ServerListClient.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"use client";

import ServerCard from "@/components/ServerCard";
import { nezhaFetcher } from "@/lib/utils";
import useSWR from "swr";

export default function ServerListClient() {
const { data } = useSWR('/api/server', nezhaFetcher, {
refreshInterval: 2000,
});
if (!data) return null;
const sortedResult = data.result.sort((a: any, b: any) => a.id - b.id);

return (
<section className={"grid grid-cols-1 gap-2 md:grid-cols-2"}>
{sortedResult.map(
(server: any) => (
<ServerCard
key={server.id}
id={server.id}
cpu={server.status.CPU}
name={server.name}
up={server.status.NetOutSpeed / 1024 / 1024}
down={server.status.NetInSpeed / 1024 / 1024}
status={server.status.Uptime !== 0 ? "online" : "offline"}
uptime={server.status.Uptime / 86400}
mem={(server.status.MemUsed / server.host.MemTotal) * 100}
stg={server.status.DiskUsed / server.host.DiskTotal}
/>
),
)}
</section>
);
}
75 changes: 75 additions & 0 deletions app/(main)/ClientComponents/ServerOverviewClient.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
"use client";

import { Card, CardContent } from "@/components/ui/card";
import blogMan from "@/public/blog-man.webp";
import Image from "next/image";
import useSWR from "swr";
import { formatBytes, nezhaFetcher } from "@/lib/utils";
import { Loader } from "@/components/loading/Loader";

export default function ServerOverviewClient() {
const { data } = useSWR('/api/server', nezhaFetcher);

return (
<section className="grid md:grid-cols-4 gap-4 grid-cols-2">
<Card>
<CardContent className="px-6 py-3" >
<section className="flex gap-1 flex-col">
<p className="text-md font-medium">Total servers</p>
<div className="flex items-center gap-2">
<span className="relative flex h-2 w-2">
<span className="relative inline-flex h-2 w-2 rounded-full bg-blue-500"></span>
</span>
{data ? <p className="text-lg font-semibold">{data?.result.length}</p> : <div className="h-7 flex items-center"><Loader visible={true} /></div>}
</div>
</section>
</CardContent>
</Card>
<Card>
<CardContent className="px-6 py-3" >
<section className="flex gap-1 flex-col">
<p className="text-md font-medium">Online servers</p>
<div className="flex items-center gap-2">
<span className="relative flex h-2 w-2">
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-green-500 opacity-75"></span>
<span className="relative inline-flex h-2 w-2 rounded-full bg-green-500"></span>
</span>
{data ? <p className="text-lg font-semibold">{data?.live_servers}</p> : <div className="h-7 flex items-center"><Loader visible={true} /></div>}
</div>
</section>
</CardContent>
</Card>
<Card>
<CardContent className="px-6 py-3" >
<section className="flex gap-1 flex-col">
<p className="text-md font-medium">Offline servers</p>
<div className="flex items-center gap-2">
<span className="relative flex h-2 w-2">
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-red-500 opacity-75"></span>
<span className="relative inline-flex h-2 w-2 rounded-full bg-red-500"></span>
</span>
{data ? <p className="text-lg font-semibold">{data?.offline_servers}</p> : <div className="h-7 flex items-center"><Loader visible={true} /></div>}
</div>


</section>
</CardContent>
</Card>
<Card>
<CardContent className="px-6 py-3 relative" >
<section className="flex gap-1 flex-col">
<p className="text-md font-medium">Total bandwidth</p>
{data ? <p className="text-lg font-semibold">{formatBytes(data?.total_bandwidth)}</p> : <div className="h-7 flex items-center"><Loader visible={true} /></div>}
</section>
<Image
className="pointer-events-none absolute right-3 top-[-85px] z-10 w-20"
alt={'Hamster1963'}
src={blogMan}
priority
placeholder="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAL0AAAFACAMAAADeco1xAAABvFBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEAAAAAAAAAAAAAAAAAAAANDQ2rq6sAAAD////7+/sEBAQPDw/09PT5+fnx8fETExMJCQkMDAzp6enk5ORzc3Nubm6ioqIsLCwxMTHs7Ozf39/T09NHR0cGBgba2to1NTUaGRrHx8eEhIQdHR3m5uZBQUEgICD29vawsLCqqqp9fX0XFxfAwMCfn5+ZmZnc3NzDw8OPj49cXFwoKCjQ0NAiIiIVFRWWlpaJiYnh4eG2traBgYElJSW4uLimpqY9PT05OTnX19ezs7N5eXlWVlZTU1NLS0tERES9vb2MjIx3d3fV1dXJycmtra2cnJxgYGBZWVljY2P4+Pi6urqTk5NpaWlQUFBmZmZNTU3Ozc7u7u5ra2vLy8u8vLwMo0bGAAAAPXRSTlMA/O1tjfHitZIKBKQH+vf0DugqnpgRPRjDx0ZCMd7TvrF0h2cuHH03JCAVzGDZW1PKuldPStCteSepgfXpPpiFWAAAFtdJREFUeNrU3PdTGlsUB/CLii2xRqOJsaQYX0x/qe/NfM/SQZoCgtiwYg22KL6oacaoMSam/MMPUHGFXYFkdyGfcRzlB+e4c8+5555lYTngzu3njKeU/RHqrsQCvViO+lt3CoqvNtw6d4WxR0+eXr3Fct/liqaa6uoL5YBKjSg1Wu4UVAC4+7i9lUW0n2e5qvWcClCrIagqr6WguKiqvpLlphsPkYa/Wa4p+edZ9d9F5UiHuiDXFk9pC8qRtmssx1xHBsrv5xewHNKQh8yU5VAFbahCpor+YjkivxyZy3uWE8l7vgC/5lJ+Wy3LsvYW/LrCqyx7Ll+vu3Ibv+MRy5565FXgd5RdZ9nzAL9Lla2+obQh/y5+m/oKy4p8SOJJdnrOZkijmGXBvXJIo+wiU9wzFaRyiSms/RwkVKBoz9PedgmSalSwYyitV0FaT5mC6iGxvDammNpGSK1QubpTA+lVPGbKaIMcChVK3ALIQaFGv64KcrjJFHEf8rjDROVea5kkT5ENtxgyuatAp1/6AHI5x2RXl4cjf2L0tVXg+ePKThHkUsBkd74eR/7E6J+XQS75TMifkrVifWaud5gxqvtMfg2QS1MJE/YHdAoRbUx2DyGbeyyR4tF7AGiRqz3+vTKIcIyvOKZ+ul59frm67bTavzq9yMy/THZX8iBii1zjm3SIi319sC3u59Z21QwRxsUwsKSnQ6GB6bVlIhrc2ltYtr7IlXnsHRXEmLw7ATryzqQBHG/o0E8t0nC7ksmuRnTZd9EJrqu7J9RvHqdD1lxZOucgyLRKyX72H139/5COvGoms/ONENRr4CzEp+8iIt17ihlFWqpambzON0GQl6wjQ8QzZ/ZTXABpyWtn8sqHsK/cAJx6OrGNMMXZkZYaJrO2FhWE7JATTo5O2DCtp2N7ubFwGDtfCCFWmvO8JZ4FODg6ZsuZk20LhPhJ/54jHv3iB4rrRxqaS5j82tQQMEkx77tIwIQnR3pMxkoKIWCcIvQ2Y4AEDCMdLUwB1SoIsFPEGIbo16N/whTQqhaNfm2FIgzJ0efOewULxK+9bVpPHVMDfZQgnCtnK7FGZ4wiXNrwlBFfky6+F2loqmMKqHx0AclCFDXaP7sxxFEiN1LLu8EUUi9U7w/pKZnBkSPjnEMNZQKdgrjF3JgDxl1CoulBEuVHKuWKBC/eLWh6iGgoQFFjnxJWjhNnu3SRKUkgbxejS0QzxpHej14dnbKTC5X+xDMk8XJElml4t53AMEd8XD/O1swU1aZCIs0mEQX3AcyG6LQ+Y/ZvWfGVFiHJd4pyLUwYKEGXOcee5njeiETGeRLRYcSZikqYwv4qRCIbidDN4gyNDeeZ4v5BItMEiXh9VvDVLAsakGSpiyiz/r6iBcUsK24iibObEnAU1aMRPYffr2bZ8XceEvWO8RoGvWvP7e2J/eSAoIpbLHseq5DEsTg6b9AZOjbtn50eAGPiE5HC4sssm5Ieb6u6DcDsG+jVIsr3dWuXoizrphx5/zRPSXVC5XlQefmCyqQBPEbHvv9NJ8UtaBMWzYOiVpZtpflqnLj7F2P3PC/fb26+79PTaeM4Vv/sQeODBpYTqvOf/XutuObCuZaWa5EkbG/0ciRoUqtClPpeCctRJUWwk4j3Y8M+j3fWrKp6ePNiO8s1lf9eb8Y6R+L6raQLvvRvjKCqKD9nHtaLqL5+oQmAu5PEzbwIUowl8NEH9dPHufG8/K2rl8o9KzuYDQ2SuN3wDsVZxr0a1D9iWVddk4fZ4Rnq1vTTGbgpXx/xcJvWXhRdYVlVV1CBpdA3Ihp0mFZJlGXd8ybpNb9RfZVl0f1GaBe/UYwfn0nMpyVTQKgQuXGukmVJSTGwckBH+nyeBZFqOYXZCeFksOFhLcuK1mbAykvUZRhHKZnruwlfLCTiVexoqLzqJpi2iM8P82RC2dEF1jVY+UTivuAaU96NRmgT13LIDOf4PB379sY2ALwOcHQGnbesjSnteST45Es6sw6Yw5/f2pftk7bXI8CLzz2UwqbpKVNYXRPMgjn6w+rQ4IhvfcxCqdkqFG6XS5qhWSZh+uCnrblFfygwY6C0dBivM0XVAHMkGdsDRVue68AaR5KZMSmZt1fUcHSSdLiVAqaYytsw/yApzT1RbukUAJMkqc3yaqaQy2XY4EhShoE7TBm1d2HspkODUi0gdzFTRgEQilfqpQ6ShPUhU8TFMri5k31mhiQxfleRMX7JbWhddKw78rMkXubVMQU8AxYpbsLcRZI4KH/O5FethlNHce/MFpJE0KzE+bwIGn5b3K/tlKRgUp/2IpPdHeAjneCcPgNlpIOjZD1BsrxoYHKrK4Rvnk7ofEu7lAluSOA1+yRHnb7LTG4XgHHi6TA5OMpE1yQlmB/fntMTdY7Ifu0fqdDPEY8LYcpIYJz4dEP7K8PdFGExyt0jtzfCfEB8P+GmjLx6w4990ulePsqbLu0NJq8awE+n2LFGmdj92sfLVYdzgY651DJPxO+r4NXRKW/xhTJx4Ka4iaVXOt5vMu+1rYUw9dBpNryjTCzaeAkcJJ6hxhImo9IiwE8J9vGWMsB5AyRi8gmT002gfzcpGtgpAz96xaeZsnbIj8ow0k1R37ro2DcfXlIGrG4Ss3OByedGFTQBihmd/W6hQ6sezUwmFWcpRGLcN5lsWu8Cw/FhvK3/P4p5CW0HpW/T9J5E6B3ynWvbLwHbHMXNTw7pYqmG6UFKn39gl4TJ2aTVNgOvDcQ33x1brJlttW53Fg4nlQ8BZx8l48KwUfr0s+Jbm72qlsmisgiYDZIAixFjlD6D0UpirDLN0kqKAJ9wZZnAUcnpdI2OznSmjv47ielvYXKobAGMExTFuQYTu5wBHZHL3z+iATQj7q0U/4AjLJq0xmIWI/2yMR/vSF1jwYQ+YYoWNkyIm93bJXEdXk801zmOkrzEVcZkCd70gY51Tv6kE50+7GzgtP5VEvPJF47NUnQHlMSK+0xytQ8BjZ1fNvgJMAoBvv9E56wbndolXTRdZpL3KrQxqdU1AwiJLoR9CDFtkaAxfKKviGYQt5XYHPVoKiQ/m7TehvjNKX2oFyImhatKr47msEcRu9ZAwsLRSv5hdSX1AIZJ2MFrAJmEH9R8IQocTSQMa3biMcxqJJ/BXhN/X7d+zowzaMaJh1u1W21bNnwg2jxqsqnP6acTQ9J/vuqNcrxYJkHdbpzNEy9T+p53Ds+Sf3V+RNtHpO+mI6sjX/T8JzuKWJzMN2SHfEhFO0pRrsVpaPYDOqIP2EhIVNP27nHt0gD/MElVFor07vp3SIPPRZaxfsAxF6SoNWwl1aDjvmEDWkh8smoD3Lqe8Vffbf7lAwPF9X1FWqY/GqGdeqM/yssRo4VO415jgaI+4fNb1DBJ/Q3MOgCT2awBjBuhboqZcSBdzlAH74GxPUpkxzpF6L29FsOSxG1OPiL8wT6LpWtz2eY1acJ7XUQLPqRDC+125LLzDFKSN1ihiL1oMQpLHP1NAEbj3PGamV9e15r2X5mQkmZpLdTzXzcJOP3W6gnNq9g9k49EulmJV86/wMfgDnr98Tgs9tcanO3Fyne7S0divo0SDzeji3xz91qi42+Jr/2z2IOPPWsw2ygu+DasEQs8/GW8x0JnG12gBG9jA6EObQGT1HWYgsS57F7TO+Lhfgx7PThN6/y4N2GhNHC2eTplxmM9fBpO4ugfQXOw7AzPHQSTQnCFphza48hXXgW6OEqX3Zrw7Ko3ls5BU43k9d5rejtIwvQdB58WXi6Y3R2UkfnpPuL5qF2lw2sv8W71VzlSDgw6TR8pM7sDdjoxhyGKmdc+ZZIqaUSYUujCFGVGP2CluGUMxydpzZJ3aVZKoTvj6PtMJ3/0g2aKO17/vU2lTFKPVYuUgivj6McwFg/e81pHR/TTUo/SbpWnjP5HptEPLvV20qFxeDspbqVc4nPt87J3lEJPptHrF9/E2+wwv1yt46LUReczpTCRYfT8w1m/hXhsuCPxylGvUwqj2KZfwG2NYNtAfJOQeLOtrVpJvXLWKHM9G0mfWUABtDBJlTYN6M7MwI6ZSXg5ytDMjgcDAUrg8jRJOxI5f8kUFC3bC8Mb01oNgCHKxO7CmgmY6qBEnT51K5NOe/4TFRZISOfyvhHHRmwhl4FLr1xuDjsAOAKCt6HRIF29+b+9O21r6ojiAD4JJIDsoIBhKxCxyL4v7X+4CYSQQMIqa2gALUuJqCAlgIgbWEVobb9wmSskXMjc3GpM5/bp7wUPPr4ZyGVyzpmTM+Xmi9kgV43v+KA0NuE9HTjwL40P9VCe3pHBE48EwLfcSyM5itkMmrxUE2Sz15/aYyd4+iY8syvu9QfBpZGfXUN/9J4ZmhkeWfSvH++vjYHZWOelAVOxqYlk1ZXignNc+dI/2ZXgcyAqqc+2MDF9ZsLhlBCy9aCX33WEhhg8Ml21yul/ITOb7lVgemroCF9q6WqgsRfOtF6NfW2Hyw1LqgkKzuU3P/3kf7D88shrA6TZh/0s0IpkYQpRnVAl++jadvhs4utihTsJ1ep1joevVGaajG16EI1t/GqN4f7acHgQYsVX3JCXa0QEa0e7R+/c64Mvfp6TTxxYZrSCSHZeIipFJsbWPbPqvQg0P+HmF3+4txqRKcPMt8Agb8irJ4iopBc07OUAS8d9oz0XEfPtL9pk6ttM4Nmhl+0CC+PsfD8C6ckqolF0MA95n7K/1olPFxFfKEHJt+blWfO1hAN5ycUAoq++90E3i8KBLTvn73bejegOaNj4NHsOf3c8PC8rGIoIU19tNAAGY3VyvXrwUNTVCnVuysZ5s92N1bxOcGbPbp9GBN4gogtcrkYtTU/KX+WddG4VTXJSZBx7tDi55H/6fBrG0so8TsZobb+djmhW5LrFMCv47rHvmK1f3IhACnoQlTIheLbBqjtPfpXfgEfRJY9iC73eQ4tP9x0wtyUUpVx9YirZ0qMblUvUH9jqneP0DWTOVUTy8iWiU9aI5vd72A9xzMK8Y/n0Jyd9+o/LwWzw5ZbDUNzWXpeXc+dWysXqa6EJmwr8EFvddBKYZ19UeIISoguMXw4t99zyfvOG1WPlWKHmerLpejI/6pOQbso2lzaHZuVp4Rxm++TYL/SVBJ89yuiwoBcajPYo3q/88iPUz449zVms+PspYoz6y+DAvq8PmeV1edaOogIJmgTl0GCeumyAv3sNatzz0OKpImj1jLOspZdtmWyUUR68c9wwe3tQun/4ce9w/qdlaDIgj8FenbP7gH16CjVrm2PQQDlWYZA9+syIxLbMlFbVZjHvcyqzb0CLDTt9BmCTbgHSqwOo8m9BizVFHfl4/qISC4tcwsPAHOXZmTj/vylo4pd3mj159JP7T6g6XIYmH7tpmH3/L8oMBdB0ftw3y23bfGgbuviIELS43x0E0PdqEMDCiA9qFl7YoMm64tHfH/pciT2PMuuyEfjASZUHx1yhI2pNPizhzOkTAKwVStXbXWgy9l4R/LnPI/yE8xQpCRgdoZH4sf3PhtLb9sD8+vkfUDXqhza+x4o64CJ7gnyh3rQbZZmwPYpc/3oTHp0Ya2PvV8HF3/X73Xb5yUkInztVAysz9Br7Qqi4eopY40cL6rH35CI7P7mcXWUlAxtBes1K6NNpj8CRYcAXck5DI+mN4jSOhcjKWdr1ZkjsNVFaDH1cYbsPkRhSmzLwzbE8R+F3CRZlot0G3H99rei2YT//zosIGgtJHeJha+5KRYe91yokmOA86L7ad7rDv46hukk+cIsL95Uz/+sVnaIC4PmV1+gQP3GugCmukEPoasSHX/H3iAht4Cnl6VgYVJZRvM6li9DiMmPXPcLkmxAPyke/xxN5sLClFjjsV/RGrrKpPdtT3nSEGVI7Yn/znPZdf7uPU0W+lwusbiqbcKXZ2R9yzQirtijaouJkKhx/Ib2IRFaTjbEdxd75Y0lizqVR6qbKFM6U79jiz/E9Bf/sp6MR+PVPGrbcJfc/nUuyKufDx4+nNzSvulylUFmZAdtyd2jXdN5l7wdGMK118brllb9tHrAHR0VhCfBxm8pGJpIIU5YJfNeUQhSsBsTR2KIcfa2ikai6lZgOx5SLBUUbGUXnT1RFfYSuqLiSa5vPgGYSRV4p4Bh9t882J74yxBXbd+a8uH0jepm+OSkTgLlG/XP78WXbpg9haNF2MtVc03KPqClFnB25pmPWwZ5WiziTfIjZqL17RsRdRhmJkZx0xFdmW0sOiRUL4oitPYfEUA24knIRayVWElOV4EomlemIqYIqElvJ4GFxVGE1YicjMYvEWCe42lmuVmZGTGR3dllJzJWCq+K88eg2vlZ6QUI++QZulICrKdScn42vkFlQWUS+jSwzuMKxSFV7QbYBTKb5dmd5Qr2lMK/QUl/RnthZUGs0gMt4+2Ydp+31W9/En6d4T7Zampstd6uyyBUp+VZLXVliamNDSXG20ZR5xmQ01zYk5VbW3c0n39T3meAq+qchU8qt/DtVVd9X3bmXlUbiQC2zSs8hossDDzuRFF0LeFidUXRN4GENNKKrAQ87iRddArhqhb2oJKQdXCViXJGhpgtcrUR45eC6TYSXCK5SIrxkcCUR4d0E13dEeLngaiPCSwVXJxGeyupTifBUVp9LhKey+ptEeP+vXrP/V69tv//3L3/8z6/+pq5Xn6zr1SfqevXlut5zunS9+kpdxzllul59gq4j5BpdZydNus5rm3VdU7Doup6TB64CIrwicDUQ4ak0uLSKX0OuygRPbRoRXb5Rz2cnKp2w2eJdkR5hThqP6Q4RnUqXRaZIt7tzNIDHYCXCKwXXXSK878BlIcJLBVc9EV6yWmeX8MrBVUaEV6bW0Si8Cl2n5U26PjRs+a8mVzpoErEa9Bwif5+h58a0W9l6bmm80aDWDCu8cl0HOjkZ4Ekg4isHR4P4zz0haam4zpzUXih+RYRJS07HZTZfSaH4fbBhrVO7noDN5pjw7B8vv3e90UHpPqzjhxn625Dr8cwfPZR5pKvVJ1y5JOdQB9Fl2HeBIXpJt1cHxyYhKWbl9Zz9jkaiFym3agzryjnCkg6aeD8rqzUDx5szNGxRD8Xvz0ogCzx/6wqv3ih++VhWubrr3r3vwJmFTyMXE0r0UMI8U2bbY3cHzbyYvy8BzhN5DLvdp4v4jDQZAiMX2+TrgQVg4hn71oOMZiI8qxHPaJhrPgB86qe9E7CJX0+41Xr16vfhd8Dazi6kdybRc9obnfjYQ68IruLMwKbwWWEivP30mqGD0f0P3ZOoIUIrw9o45RmRKonIagyO15RrvE/ojsAKg+095Rt2itwZVWZwBqkKl03cIDktGbYgVeMSN0i+k4TAXzTK6kXtzrEUY+M1Veeyibn6tMoMbA3TKB7bhExQchqBEzuNZtgp4uorjAg8oNGN94m3emsb8HybajAiXGqbVZ6JtQfdVItJ0ToCi6rZxTdUm0XBVt9i7JufoVo9E2v1FtPEe6rV0qFNqNVXZQdeU23s/lEJqG4h4miT/FQT14EHQGm9SOWou4ZTbVvNSQDI7CwkQinHExrV0OCsBJgThTutSmIFenV/uqcBNFQIWANsdPRTNf1vZ8cAU6pFyL6KXGmScs29OFkAUNIuavdoM1a4Ec1TDwBjaotIu4xSWinWIwbCH2b75FlsYrccd5ixMnx1ax88tQEoKS8iostpRWD+MQ2Z8R85ABTfLBR/xo88HtkEx2GwX877Hj1nSzfntojf/XShI7EYWJgdWB74/Ftv0dNp/pksS2JDBgBTdaJFP7/1yzqauuqqRHlT+htY/m+YP5T9egAAAABJRU5ErkJggg=="
/>
</CardContent>
</Card>
</section>
)
}
62 changes: 62 additions & 0 deletions app/(main)/header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
"use client";

import React, { useEffect, useState } from "react";
import Image from "next/image";
import { Separator } from "@/components/ui/separator";
import { DateTime } from "luxon";

function Header() {
return (
<div className="mx-auto w-full max-w-5xl">
<section className="flex items-center justify-between">
<section className="text-md flex items-center font-medium">
<div className="mr-1 flex flex-row items-center justify-start">
<Image
width={40}
height={40}
unoptimized
alt="apple-touch-icon"
src={"/apple-touch-icon.png"}
className="relative !m-0 h-6 w-6 border-2 border-white object-cover object-top !p-0 transition duration-500 group-hover:z-30 group-hover:scale-105"
/>
</div>
HomeDash
<Separator
orientation="vertical"
className="mx-2 hidden h-4 w-[1px] md:block"
/>
<p className="hidden text-sm font-medium opacity-40 md:block">
Simple and beautiful dashboard
</p>
</section>
{/* <LiveTag /> */}
</section>
<Overview />
</div>
);
}

function Overview() {
const [mouted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
const time = DateTime.TIME_SIMPLE;
time.hour12 = true;

return (
<section className={"md:mt-16 mt-10 flex flex-col"}>
<p className="text-md font-semibold">👋 Overview</p>
<div className="flex items-center gap-1.5">
<p className="text-sm font-medium opacity-50">where the time is</p>
{mouted && (
<p className="opacity-1 text-sm font-medium">
{DateTime.now().setLocale("en-US").toLocaleString(time)}
</p>
)}
</div>
</section>
);
}

export default Header;
21 changes: 21 additions & 0 deletions app/(main)/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from "react";

import Header from "@/app/(main)/header";
import BlurLayers from "@/components/BlurLayer";

type DashboardProps = {
children: React.ReactNode;
};

export default function MainLayout({ children }: DashboardProps) {
return (
<div className="flex min-h-screen w-full flex-col">
<main className="flex min-h-[calc(100vh_-_theme(spacing.16))] flex-1 flex-col gap-4 bg-muted/40 p-4 md:p-10 md:pt-8">
<Header />
<BlurLayers />
{/* <Nav /> */}
{children}
</main>
</div>
);
}
57 changes: 57 additions & 0 deletions app/(main)/nav.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
"use client";

import { clsx } from "clsx";
import Link from "next/link";
import { usePathname } from "next/navigation";
import React from "react";

import { cn } from "@/lib/utils";

export const siteUrlList = [
{
name: "Home",
header: "👋 Overview",
url: "/",
},
{
name: "Service",
header: "🎛️ Service",
url: "/service",
},
];
export default function Nav() {
const nowPath = usePathname();
return (
<div className={"flex flex-col items-center justify-center"}>
<div
className={
"fixed bottom-6 z-50 flex items-center gap-1 rounded-[50px] bg-stone-700 bg-opacity-80 px-2 py-1.5 backdrop-blur-lg"
}
>
{siteUrlList.map((site, index) => (
<div key={site.name} className={"flex items-center gap-1"}>
{index !== 0 && (
<p key={index} className={"pointer-events-none text-stone-500"}>
/
</p>
)}
<Link
key={site.name}
href={site.url}
scroll={true}
className={cn(
"rounded-[50px] px-2.5 py-1.5 text-[16px] font-[500] text-stone-400 transition-colors sm:hover:text-white",
clsx(
nowPath === site.url &&
"bg-stone-500 text-white dark:bg-stone-600",
),
)}
>
{site.name}
</Link>
</div>
))}
</div>
</div>
);
}
Loading

0 comments on commit 3085a41

Please sign in to comment.