Compare commits

..

39 Commits

Author SHA1 Message Date
Robert Burgess ff979a2cfc test
Build KX3DEX.radio / Build and Deploy (push) Successful in 28m58s Details
2024-08-15 15:49:05 -04:00
Dex d6958ea3ea Adding Version releases
Build KX3DEX.radio / Build and Deploy (push) Successful in 29m55s Details
2024-05-06 22:39:45 -04:00
Dex 221d7f9c72 revert
Build KX3DEX.radio / Build and Deploy (push) Successful in 32m45s Details
2024-05-06 20:42:54 -04:00
Dex 84b0d5923d Test new version method.
Build KX3DEX.radio / Build and Deploy (push) Failing after 30m43s Details
2024-05-06 18:19:33 -04:00
Dex 6e12955241 deploy testing
Build KX3DEX.radio / Build and Deploy (push) Failing after 46s Details
2024-05-06 16:32:11 -04:00
Dex 571d5558b1 Test pulling version
Build KX3DEX.radio / Build and Deploy (push) Failing after 35s Details
2024-05-06 16:06:30 -04:00
Dex 38ad6bbe53 Resolve docker build.
Build KX3DEX.radio / Build and Deploy (push) Failing after 32s Details
2024-05-06 15:10:14 -04:00
Dex fe7bbf995f Fix release & publish
Build KX3DEX.radio / Build and Deploy (push) Failing after 2m13s Details
2024-05-06 14:00:39 -04:00
Dex d44acad05c Update Deployment.
Build KX3DEX.radio / Build and Deploy (push) Failing after 31s Details
2024-05-06 13:54:56 -04:00
Dex 6b0be661bd update release step
Build KX3DEX.radio / Build and Deploy (push) Failing after 2m21s Details
2024-05-06 13:03:39 -04:00
Dex 21ae7fa91c Update Homepage
Build KX3DEX.radio / Build and Deploy (push) Has been cancelled Details
2024-05-05 03:14:09 -04:00
Dex 03d159e358 Fix text.
Build KX3DEX.radio / Build and Deploy (push) Successful in 31m58s Details
2024-05-04 22:41:14 -04:00
Dex d2262d7f2d Next test.
Build KX3DEX.radio / Build and Deploy (push) Failing after 1m31s Details
2024-05-04 22:36:24 -04:00
Dex 874fd6d9c3 remove argocd
Build KX3DEX.radio / Build and Deploy (push) Successful in 29m27s Details
2024-05-04 00:00:20 -04:00
Dex ae27af92a7 Adding ArgoCD
Build KX3DEX.radio / Build and Deploy (push) Failing after 33m13s Details
2024-05-01 03:11:59 -04:00
Dex 9bf6a0e4b5 Update Version
Build KX3DEX.radio / Build and Deploy (push) Successful in 31m32s Details
2024-04-10 22:41:52 -04:00
Dex 1af01fa8a7 add mobile menu and v1 of DexNet
Build KX3DEX.radio / Build and Deploy (push) Successful in 31m18s Details
2024-04-10 22:40:31 -04:00
Dex e0ed17bd66 Merge branch 'master' of https://gitea.simplysyncedllc.com/Dex/kx3dex_radio
Build KX3DEX.radio / Build and Deploy (push) Successful in 30m2s Details
2024-03-31 23:32:13 -04:00
Dex 9e81d7be45 fix spelling 2024-03-31 23:32:04 -04:00
Dex Burgess d675ceb261 Delete bu_Dockerfile
Build KX3DEX.radio / Build and Deploy (push) Successful in 28m18s Details
2024-03-30 06:18:36 +00:00
Dex 8dfe805cef Memory Updates
Build KX3DEX.radio / Build and Deploy (push) Successful in 27m14s Details
2024-03-30 00:41:31 -04:00
Dex 076025f977 Change QEMU
Build KX3DEX.radio / Build and Deploy (push) Has been cancelled Details
2024-03-30 00:04:47 -04:00
Dex 325d736536 just arm
Build KX3DEX.radio / Build and Deploy (push) Failing after 22s Details
2024-03-29 23:54:19 -04:00
Dex bf32f4a33a only arm build
Build KX3DEX.radio / Build and Deploy (push) Failing after 7m37s Details
2024-03-29 23:45:41 -04:00
Dex Burgess f18cee6775 Update .gitea/workflows/merge-master-tag-deploy.yaml
Build KX3DEX.radio / Build and Deploy (push) Failing after 8m49s Details
2024-03-30 00:51:51 +00:00
Dex Burgess 7ad8713fb9 Update .gitea/workflows/merge-master-tag-deploy.yaml
Build KX3DEX.radio / Build and Deploy (push) Failing after 31s Details
2024-03-30 00:49:28 +00:00
Dex 6dcae4ffa8 New approach
Build KX3DEX.radio / Build and Deploy (push) Failing after 8m38s Details
2024-03-29 15:56:37 -04:00
Dex dc90d2ac4d Dockerfile update
Build KX3DEX.radio / Build and Deploy (push) Has started running Details
2024-03-29 15:42:41 -04:00
Dex 2d81c10377 opf
Build KX3DEX.radio / Build and Deploy (push) Failing after 8m16s Details
2024-03-29 14:13:24 -04:00
Dex d3b581574a up
Build KX3DEX.radio / Build and Deploy (push) Failing after 36s Details
2024-03-29 14:11:54 -04:00
Dex bbf7753ad0 another deployment change
Build KX3DEX.radio / Build and Deploy (push) Failing after 15s Details
2024-03-29 14:10:33 -04:00
Dex 889a70fe65 update versions in deploy yaml
Build KX3DEX.radio / Build and Deploy (push) Failing after 24s Details
2024-03-29 12:22:26 -04:00
Dex 5bca013e5a fix format issue
Build KX3DEX.radio / Build and Deploy (push) Failing after 29s Details
2024-03-29 12:09:27 -04:00
Dex 065b364390 Add QEMU and Buildx 2024-03-29 12:06:07 -04:00
Dex d4215470c1 new build 2024-03-29 11:50:03 -04:00
Dex 4f39a6169c New build YAML
Build KX3DEX.radio / Build and Deploy (push) Failing after 22s Details
2024-03-29 11:41:06 -04:00
Dex ec8649d0c6 update docker file
Build KX3DEX.radio / Build and Deploy (push) Failing after 5m26s Details
2024-03-28 17:16:20 -04:00
Dex 6711b3f240 fix url
Build KX3DEX.radio / Build and Deploy (push) Failing after 5m6s Details
2024-03-28 15:48:01 -04:00
Dex 1d54c34812 fix build step
Build KX3DEX.radio / Build and Deploy (push) Failing after 14s Details
2024-03-28 15:46:53 -04:00
40 changed files with 828 additions and 219 deletions

View File

@ -13,20 +13,39 @@ jobs:
- name: Check out repository code - name: Check out repository code
uses: actions/checkout@v4 uses: actions/checkout@v4
- uses: actions/github-script@v7
id: set-result
with:
script: |
var fs = require("fs")
var content = fs.readFileSync("package.json", { encoding: 'utf8', flag: 'r' })
var pkg = JSON.parse(content)
return pkg.version
result-encoding: string
- name: Get result
run: echo "gitea.simplysyncedllc.com/dex/kx3dex_radio:${{steps.set-result.outputs.result}}"
- name: Install QEMU
run: apt-get update && apt-get install -y qemu-user-static
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Setup Node - name: Setup Node
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: '18.20.0' node-version: '18.20.0'
- name: Create a new release and publish package. - name: Create a new release and publish package.
id: release
run: | run: |
CURR_VER="$(cat package.json | jq -r .name)_v$(cat package.json | jq -r .version)" CURR_VER="$(cat package.json | jq -r .name)_v$(cat package.json | jq -r .version)"
CURR_NAME="$(cat package.json | jq -r .name) v$(cat package.json | jq -r .version)" CURR_NAME="$(cat package.json | jq -r .name) v$(cat package.json | jq -r .version)"
echo "Checking https://gitea.simplysyncedllc.com/api/v1/repos/${{ gitea.repository }}/releases for name ${CURR_NAME}" echo "Checking https://gitea.simplysyncedllc.com/api/v1/repos/${{ gitea.repository }}/releases for name ${CURR_NAME}"
if curl -s -X GET -H "Authorization: token ${{ secrets.action_token }}" https://gitea.simplysyncedllc.com/api/v1/repos/${{ gitea.repository }}/releases | grep -o "\"name\"\:\"${CURR_NAME}\"" > /dev/null; then if curl -s -X GET -H "Authorization: token ${{ secrets.ACTION_TOKEN }}" https://gitea.simplysyncedllc.com/api/v1/repos/${{ gitea.repository }}/releases | grep -o "\"name\"\:\"${CURR_NAME}\"" > /dev/null; then
echo "Skipping ${{ gitea.job }} since $CURR_NAME already exists"; echo "Skipping ${{ gitea.job }} since $CURR_NAME already exists";
exit 0 exit 0
fi fi
@ -38,7 +57,7 @@ jobs:
echo "Creating ${CURR_VER} release on gitea" echo "Creating ${CURR_VER} release on gitea"
RELEASE_RESULT=$(curl \ RELEASE_RESULT=$(curl \
-X POST \ -X POST \
-H "Authorization: token ${{ secrets.action_token }}" \ -H "Authorization: token ${{ secrets.ACTION_TOKEN }}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
https://gitea.simplysyncedllc.com/api/v1/repos/${{ gitea.repository }}/releases \ https://gitea.simplysyncedllc.com/api/v1/repos/${{ gitea.repository }}/releases \
-d "{\"tag_name\":\"${CURR_VER}\",\"name\":\"${CURR_NAME}\",\"body\":\"Automatic release from gitea :\n\n${{ gitea.event.head_commit.message }}\"}") -d "{\"tag_name\":\"${CURR_VER}\",\"name\":\"${CURR_NAME}\",\"body\":\"Automatic release from gitea :\n\n${{ gitea.event.head_commit.message }}\"}")
@ -49,24 +68,18 @@ jobs:
curl \ curl \
-X POST \ -X POST \
-H "Authorization: token ${{ secrets.action_token }}" \ -H "Authorization: token ${{ secrets.ACTION_TOKEN }}" \
-H "Content-Type: application/json" \
https://gitea.simplysyncedllc.com/api/v1/repos/${{ gitea.repository }}/releases/$RELEASE_ID/assets https://gitea.simplysyncedllc.com/api/v1/repos/${{ gitea.repository }}/releases/$RELEASE_ID/assets
- name: Build and push
- name: Build Docker container and put in gitea registry. uses: docker/build-push-action@v5
run: |
echo "${{ secrets.action_token }}" | docker login gitea.dex -u dex --password-stdin
docker build -t gitea.simplysyncedllc.com/dex/kx3dex_radio:latest .
docker push gitea.simplysyncedllc.com/dex/kx3dex_radio:latest
- name: Build Docker for arm64
uses: docker/build-push-action@v4
if: ${{ gitea.ref_name != 'latest' }}
with: with:
context: . context: .
platforms: linux/arm64 file: ./Dockerfile
build-args: | platforms: |
VERSION=${{ gitea.ref_name }} linux/arm64
push: true push: true
tags: | tags: |
gitea.simplysyncedllc.com/dex/kx3dex_radio:${{ gitea.ref_name }} gitea.simplysyncedllc.com/dex/kx3dex_radio:latest
gitea.simplysyncedllc.com/dex/kx3dex_radio:${{steps.set-result.outputs.result}}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,34 +1,24 @@
FROM node:20-alpine AS base
# Install dependencies only when needed # Install dependencies only when needed
FROM base AS deps FROM node:18-alpine3.19 AS deps
RUN apk add --no-cache libc6-compat RUN apk add --no-cache libc6-compat
WORKDIR /app WORKDIR /app
COPY package.json yarn.lock ./
# Install dependencies based on the preferred package manager RUN yarn config set network-timeout 100000
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./ RUN yarn install
RUN \
if [ -f yarn.lock ]; then yarn; \
elif [ -f package-lock.json ]; then npm ci; \
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \
else echo "Lockfile not found." && exit 1; \
fi
# Rebuild the source code only when needed # Rebuild the source code only when needed
FROM base AS builder FROM node:18-alpine3.19 AS builder
WORKDIR /app WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules COPY --from=deps /app/node_modules ./node_modules
COPY . . COPY . .
RUN \ RUN yarn build
if [ -f yarn.lock ]; then yarn run build; \
elif [ -f package-lock.json ]; then npm run build; \
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm run build; \
else echo "Lockfile not found." && exit 1; \
fi
# Production image, copy all the files and run next # Production image, copy all the files and run next
FROM base AS runner FROM node:18-alpine3.19 AS runner
WORKDIR /app WORKDIR /app
ENV NODE_ENV production ENV NODE_ENV production
@ -37,11 +27,7 @@ RUN addgroup --system --gid 1001 kx3dex_radio
RUN adduser --system --uid 1001 kx3dex_radio RUN adduser --system --uid 1001 kx3dex_radio
COPY --from=builder /app/public ./public COPY --from=builder /app/public ./public
# COPY --from=builder /app/package.json ./package.json COPY --from=builder /app/package.json ./package.json
# Set the correct permission for prerender cache
RUN mkdir .next
RUN chown kx3dex_radio:kx3dex_radio .next
# Automatically leverage output traces to reduce image size # Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing # https://nextjs.org/docs/advanced-features/output-file-tracing
@ -56,4 +42,3 @@ ENV PORT 3000
ENV HOSTNAME "0.0.0.0" ENV HOSTNAME "0.0.0.0"
CMD ["node", "server.js"] CMD ["node", "server.js"]
#CMD HOSTNAME="0.0.0.0" node server.js

View File

@ -1,40 +0,0 @@
"use client"
import * as React from "react"
import { MoonIcon, SunIcon } from "@radix-ui/react-icons"
import { useTheme } from "next-themes"
import { Button } from "@/components/ui/button"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
export function ModeToggle() {
const { setTheme } = useTheme()
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" size="icon">
<SunIcon className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
<MoonIcon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
<span className="sr-only">Toggle theme</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onClick={() => setTheme("light")}>
Light
</DropdownMenuItem>
<DropdownMenuItem onClick={() => setTheme("dark")}>
Dark
</DropdownMenuItem>
<DropdownMenuItem onClick={() => setTheme("system")}>
System
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
}

View File

@ -7,7 +7,7 @@ export default function DexNetPage() {
<div> <div>
<h1 className="text-2xl font-black text-center mb-10">DexNet VHF/UHF Comm Plan Guide</h1> <h1 className="text-2xl font-black text-center mb-10">DexNet VHF/UHF Comm Plan Guide</h1>
<p className="text-lg">With the crazyness of the world I thought it would be worth while to have a communications plan for family and close personal friends. There are many out there such as the S2 Underground for HF communications and a net. However, I did not see much in terms of a more localized one. So I set out to do just that. I have attached the file in a PDF format to be printed. The print is designed to be cut out and placed in 4in x 6in laminating pouches. Before laminating the pouches there are sections to be filled out and decided upon by those in your communications group. Personally I used a hold punch in the top left and used a small caribeener to hold them together.</p> <p className="text-lg">With the crazyness of the world I thought it would be worth while to have a communications plan for family and close personal friends. There are many other guides out there such as the S2 Underground for HF communications and a net. However, I did not see much in terms of a more localized one. So I set out to do just that. I have attached the file in a PDF format to be printed. The print is designed to be cut out and placed in 4in x 6in laminating pouches. Before laminating the pouches there are sections to be filled out and decided upon by those in your communications group. Personally I used a hole punch in the top left and used a small caribeener to hold them together.</p>
<div className="flex align-center justify-center"> <div className="flex align-center justify-center">
<Image <Image
src={dexnet_cover} src={dexnet_cover}
@ -19,7 +19,7 @@ export default function DexNetPage() {
/> />
</div> </div>
<h2 className="text-xl font-black text-center mt-10"> <h2 className="text-xl font-black text-center mt-10">
<Link href="#">Download Here - LINK COMING SOON</Link> <Link href="KX3DEX_DexNet_v1.pdf">Download Version 1</Link>
</h2> </h2>
</div> </div>
) )

View File

@ -2,69 +2,54 @@
@tailwind components; @tailwind components;
@tailwind utilities; @tailwind utilities;
@layer base { @layer base {
:root { :root {
--background: 0 0% 100%; --background: 0 0% 100%;
--foreground: 222.2 84% 4.9%; --foreground: 240 10% 3.9%;
--card: 0 0% 100%; --card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%; --card-foreground: 240 10% 3.9%;
--popover: 0 0% 100%; --popover: 0 0% 100%;
--popover-foreground: 222.2 84% 4.9%; --popover-foreground: 240 10% 3.9%;
--primary: 240 5.9% 10%;
--primary: 222.2 47.4% 11.2%; --primary-foreground: 0 0% 98%;
--primary-foreground: 210 40% 98%; --secondary: 240 4.8% 95.9%;
--secondary-foreground: 240 5.9% 10%;
--secondary: 210 40% 96.1%; --muted: 240 4.8% 95.9%;
--secondary-foreground: 222.2 47.4% 11.2%; --muted-foreground: 240 3.8% 46.1%;
--accent: 240 4.8% 95.9%;
--muted: 210 40% 96.1%; --accent-foreground: 240 5.9% 10%;
--muted-foreground: 215.4 16.3% 46.9%;
--accent: 210 40% 96.1%;
--accent-foreground: 222.2 47.4% 11.2%;
--destructive: 0 84.2% 60.2%; --destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%; --destructive-foreground: 0 0% 98%;
--border: 240 5.9% 90%;
--border: 214.3 31.8% 91.4%; --input: 240 5.9% 90%;
--input: 214.3 31.8% 91.4%; --ring: 240 5.9% 10%;
--ring: 222.2 84% 4.9%;
--radius: 0.5rem; --radius: 0.5rem;
} }
.dark { .dark {
--background: 222.2 84% 4.9%; --background: 240 10% 3.9%;
--foreground: 210 40% 98%; --foreground: 0 0% 98%;
--card: 240 10% 3.9%;
--card: 222.2 84% 4.9%; --card-foreground: 0 0% 98%;
--card-foreground: 210 40% 98%; --popover: 240 10% 3.9%;
--popover-foreground: 0 0% 98%;
--popover: 222.2 84% 4.9%; --primary: 0 0% 98%;
--popover-foreground: 210 40% 98%; --primary-foreground: 240 5.9% 10%;
--secondary: 240 3.7% 15.9%;
--primary: 210 40% 98%; --secondary-foreground: 0 0% 98%;
--primary-foreground: 222.2 47.4% 11.2%; --muted: 240 3.7% 15.9%;
--muted-foreground: 240 5% 64.9%;
--secondary: 217.2 32.6% 17.5%; --accent: 240 3.7% 15.9%;
--secondary-foreground: 210 40% 98%; --accent-foreground: 0 0% 98%;
--muted: 217.2 32.6% 17.5%;
--muted-foreground: 215 20.2% 65.1%;
--accent: 217.2 32.6% 17.5%;
--accent-foreground: 210 40% 98%;
--destructive: 0 62.8% 30.6%; --destructive: 0 62.8% 30.6%;
--destructive-foreground: 210 40% 98%; --destructive-foreground: 0 0% 98%;
--border: 240 3.7% 15.9%;
--input: 240 3.7% 15.9%;
--ring: 240 4.9% 83.9%;
}
}
--border: 217.2 32.6% 17.5%;
--input: 217.2 32.6% 17.5%;
--ring: 212.7 26.8% 83.9%;
}
}
@layer base { @layer base {
* { * {

View File

@ -1,11 +1,14 @@
import "./globals.css";
import type { Metadata } from "next"; import type { Metadata } from "next";
import Image from 'next/image' import Image from 'next/image'
import React from 'react';
import { Inter } from "next/font/google"; import { Inter } from "next/font/google";
import "./globals.css";
import { ThemeProvider } from "./components/theme-provider"; import { ThemeProvider } from "./components/theme-provider";
import Header from "@/components/ui/header"; import Header from '@/components/header'
import Footer from "@/components/ui/footer"; import HeaderMobile from '@/components/header-mobile'
import Footer from "@/components/footer";
import MarginWidthWrapper from '@/components/margin-width-wrapper';
import PageWrapper from '@/components/page-wrapper';
const inter = Inter({ subsets: ["latin"] }); const inter = Inter({ subsets: ["latin"] });
@ -36,9 +39,12 @@ export default function RootLayout({
fill fill
style={{ position: 'absolute' }} style={{ position: 'absolute' }}
/> />
<main className="max-w-5xl mx-auto px-4 z-10">
<Header /> <Header />
<main className="max-w-5xl mx-auto px-4 z-10">{children}</main> <HeaderMobile />
{children}
<Footer /> <Footer />
</main>
</div> </div>
</ThemeProvider> </ThemeProvider>
</body> </body>

View File

@ -1,10 +1,16 @@
import { Button } from "@/components/ui/button";
export default async function Home() { export default async function Home() {
return ( return (
<div>
<div className="grid grid-cols-1 md:grid-cols-1 mt-5 gap-5"> <div className="grid grid-cols-1 md:grid-cols-1 mt-5 gap-5">
This is my little corner of the internet to share my radio projects on things I&apos;m doing. Things I find and build that seem to not be documented anywhere. I have created pages for some of the projects I have done such as a communcations plan template. Also my go kit builds. This is my little corner of the internet to share my radio projects on things I&apos;m doing. Things I find and build that seem to not be documented anywhere. I have created pages for some of the projects I have done such as a communcations plan template. Also my go kit builds.
</div> </div>
<div className="grid grid-cols-1 md:grid-cols-1 mt-5 gap-5">
if there is anything you have for suggestions on projects you&apos;d like to see a writeup on email me at bluebulletrl@gmail.com. Still need to setup email for this domain.
</div>
<div className="grid grid-cols-1 md:grid-cols-1 mt-5 gap-5">
Coming soon will be an updated DexNet guide that will include Meshtastic Information. New document will be uploaded End of August.
</div>
</div>
); );
} }

118
components/drawer.tsx Normal file
View File

@ -0,0 +1,118 @@
"use client"
import * as React from "react"
import { Drawer as DrawerPrimitive } from "vaul"
import { cn } from "@/lib/utils"
const Drawer = ({
shouldScaleBackground = true,
...props
}: React.ComponentProps<typeof DrawerPrimitive.Root>) => (
<DrawerPrimitive.Root
shouldScaleBackground={shouldScaleBackground}
{...props}
/>
)
Drawer.displayName = "Drawer"
const DrawerTrigger = DrawerPrimitive.Trigger
const DrawerPortal = DrawerPrimitive.Portal
const DrawerClose = DrawerPrimitive.Close
const DrawerOverlay = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Overlay
ref={ref}
className={cn("fixed inset-0 z-50 bg-black/80", className)}
{...props}
/>
))
DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName
const DrawerContent = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<DrawerPortal>
<DrawerOverlay />
<DrawerPrimitive.Content
ref={ref}
className={cn(
"fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border bg-background",
className
)}
{...props}
>
<div className="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" />
{children}
</DrawerPrimitive.Content>
</DrawerPortal>
))
DrawerContent.displayName = "DrawerContent"
const DrawerHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn("grid gap-1.5 p-4 text-center sm:text-left", className)}
{...props}
/>
)
DrawerHeader.displayName = "DrawerHeader"
const DrawerFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn("mt-auto flex flex-col gap-2 p-4", className)}
{...props}
/>
)
DrawerFooter.displayName = "DrawerFooter"
const DrawerTitle = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Title>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Title
ref={ref}
className={cn(
"text-lg font-semibold leading-none tracking-tight",
className
)}
{...props}
/>
))
DrawerTitle.displayName = DrawerPrimitive.Title.displayName
const DrawerDescription = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Description>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
))
DrawerDescription.displayName = DrawerPrimitive.Description.displayName
export {
Drawer,
DrawerPortal,
DrawerOverlay,
DrawerTrigger,
DrawerClose,
DrawerContent,
DrawerHeader,
DrawerFooter,
DrawerTitle,
DrawerDescription,
}

View File

@ -0,0 +1,240 @@
'use client';
import React, { ReactNode, useEffect, useRef, useState } from 'react';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import { NAV_ITEMS } from '@/components/nav';
import { NavItem } from '@/components/types';
import { Icon } from '@iconify/react';
import { motion, useCycle } from 'framer-motion';
type MenuItemWithSubMenuProps = {
item: NavItem;
toggleOpen: () => void;
};
const sidebar = {
open: (height = 1000) => ({
clipPath: `circle(${height * 2 + 200}px at 100% 0)`,
transition: {
type: 'spring',
stiffness: 20,
restDelta: 2,
},
}),
closed: {
clipPath: 'circle(0px at 100% 0)',
transition: {
type: 'spring',
stiffness: 400,
damping: 40,
},
},
};
const HeaderMobile = () => {
const pathname = usePathname();
const containerRef = useRef(null);
const { height } = useDimensions(containerRef);
const [isOpen, toggleOpen] = useCycle(false, true);
return (
<motion.nav
initial={false}
animate={isOpen ? 'open' : 'closed'}
custom={height}
className={`fixed inset-0 z-50 w-full md:hidden ${
isOpen ? '' : 'pointer-events-none'
}`}
ref={containerRef}
>
<motion.div
className="absolute inset-0 right-0 w-full bg-black"
variants={sidebar}
/>
<motion.ul
variants={variants}
className="absolute grid w-full gap-3 px-10 py-16 max-h-screen overflow-y-auto"
>
{NAV_ITEMS.map((item, idx) => {
const isLastItem = idx === NAV_ITEMS.length - 1; // Check if it's the last item
return (
<div key={idx}>
{item.submenu ? (
<MenuItemWithSubMenu item={item} toggleOpen={toggleOpen} />
) : (
<MenuItem>
<Link
href={item.path}
onClick={() => toggleOpen()}
className={`flex w-full text-2xl ${
item.path === pathname ? 'font-bold' : ''
}`}
>
{item.title}
</Link>
</MenuItem>
)}
{!isLastItem && (
<MenuItem className="my-3 h-px w-full bg-gray-300" />
)}
</div>
);
})}
</motion.ul>
<MenuToggle toggle={toggleOpen} />
</motion.nav>
);
};
export default HeaderMobile;
const MenuToggle = ({ toggle }: { toggle: any }) => (
<button
onClick={toggle}
className="pointer-events-auto absolute right-4 top-[14px] z-30 p-7"
>
<svg width="60" height="60" viewBox="0 0 23 23">
<Path
variants={{
closed: { d: 'M 2 2.5 L 20 2.5' },
open: { d: 'M 3 16.5 L 17 2.5' },
}}
/>
<Path
d="M 2 9.423 L 20 9.423"
variants={{
closed: { opacity: 1 },
open: { opacity: 0 },
}}
transition={{ duration: 0.1 }}
/>
<Path
variants={{
closed: { d: 'M 2 16.346 L 20 16.346' },
open: { d: 'M 3 2.5 L 17 16.346' },
}}
/>
</svg>
</button>
);
const Path = (props: any) => (
<motion.path
fill="transparent"
strokeWidth="2"
stroke="hsl(0, 0%, 100%)"
strokeLinecap="round"
{...props}
/>
);
const MenuItem = ({
className,
children,
}: {
className?: string;
children?: ReactNode;
}) => {
return (
<motion.li variants={MenuItemVariants} className={className}>
{children}
</motion.li>
);
};
const MenuItemWithSubMenu: React.FC<MenuItemWithSubMenuProps> = ({
item,
toggleOpen,
}) => {
const pathname = usePathname();
const [subMenuOpen, setSubMenuOpen] = useState(false);
return (
<>
<MenuItem>
<button
className="flex w-full text-2xl"
onClick={() => setSubMenuOpen(!subMenuOpen)}
>
<div className="flex flex-row justify-between w-full items-center">
<span
className={`${pathname.includes(item.path) ? 'font-bold' : ''}`}
>
{item.title}
</span>
<div className={`${subMenuOpen && 'rotate-180'}`}>
<Icon icon="lucide:chevron-down" width="24" height="24" />
</div>
</div>
</button>
</MenuItem>
<div className="mt-2 ml-2 flex flex-col space-y-2">
{subMenuOpen && (
<>
{item.subMenuItems?.map((subItem, subIdx) => {
return (
<MenuItem key={subIdx}>
<Link
href={subItem.path}
onClick={() => toggleOpen()}
className={` ${
subItem.path === pathname ? 'font-bold' : ''
}`}
>
{subItem.title}
</Link>
</MenuItem>
);
})}
</>
)}
</div>
</>
);
};
const MenuItemVariants = {
open: {
y: 0,
opacity: 1,
transition: {
y: { stiffness: 1000, velocity: -100 },
},
},
closed: {
y: 50,
opacity: 0,
transition: {
y: { stiffness: 1000 },
duration: 0.02,
},
},
};
const variants = {
open: {
transition: { staggerChildren: 0.02, delayChildren: 0.15 },
},
closed: {
transition: { staggerChildren: 0.01, staggerDirection: -1 },
},
};
const useDimensions = (ref: any) => {
const dimensions = useRef({ width: 0, height: 0 });
useEffect(() => {
if (ref.current) {
dimensions.current.width = ref.current.offsetWidth;
dimensions.current.height = ref.current.offsetHeight;
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [ref]);
return dimensions.current;
};

65
components/header.tsx Normal file
View File

@ -0,0 +1,65 @@
'use client';
import React from 'react';
import Image from 'next/image';
import { useSelectedLayoutSegment } from 'next/navigation';
import logo from '@/public/images/kx3dex_radio_logo.png'
import useScroll from '@/hooks/use-scroll';
import { cn } from '@/lib/utils';
import {
NavigationMenu,
NavigationMenuContent,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
NavigationMenuTrigger,
} from "@/components/navigation-menu"
const Header = () => {
const scrolled = useScroll(5);
const selectedLayout = useSelectedLayoutSegment();
return (
<div
className={cn(
`sticky inset-x-0 top-0 z-30 w-full transition-all border-b border-gray-200`,
{
'border-b border-gray-200 backdrop-blur-lg': scrolled,
'border-b border-gray-200 mb-5': selectedLayout,
},
)}
>
<div className="flex items-center justify-between p-4">
<div className="flex items-center space-x-4">
<Image
src={logo}
width={100}
height={100}
alt="Logo Image"
priority
className="rounded-lg border"
/>
</div>
<div className="hidden md:block">
<NavigationMenu>
<NavigationMenuLink href="/" className="font-bold text-3xl pr-5">Home</NavigationMenuLink>
<NavigationMenuLink href="/dexnet" className="font-bold text-3xl pr-5">DexNet</NavigationMenuLink>
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuTrigger className="font-bold text-3xl pr-5">Go Kits</NavigationMenuTrigger>
<NavigationMenuContent className="flex flex-col min-w-[300px] p-2 absolute right-0">
<NavigationMenuLink href="/projects/go-kit-command-center" className="font-bold">Go Kit (Command Center)</NavigationMenuLink>
</NavigationMenuContent>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
</div>
</div>
</div>
);
};
export default Header;

View File

@ -0,0 +1,13 @@
import { ReactNode } from 'react';
export default function MarginWidthWrapper({
children,
}: {
children: ReactNode;
}) {
return (
<div className="flex flex-col md:ml-60 sm:border-r sm:border-zinc-700 min-h-screen">
{children}
</div>
);
}

22
components/nav.tsx Normal file
View File

@ -0,0 +1,22 @@
import { Icon } from '@iconify/react';
import { NavItem } from '@/components/types';
export const NAV_ITEMS: NavItem[] = [
{
title: 'Home',
path: '/',
},
{
title: 'DexNet',
path: '/dexnet',
},
{
title: 'Go Kits',
path: '',
submenu: true,
subMenuItems: [
{ title: 'Go Kit Command Center', path: '/projects/go-kit-command-center' },
],
}
];

View File

@ -41,7 +41,7 @@ NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName
const NavigationMenuItem = NavigationMenuPrimitive.Item const NavigationMenuItem = NavigationMenuPrimitive.Item
const navigationMenuTriggerStyle = cva( const navigationMenuTriggerStyle = cva(
"group inline-flex h-10 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50" "group inline-flex h-10 w-max items-center justify-center rounded-md yarnpy-2 text-sm font-medium transition-colors focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50"
) )
const NavigationMenuTrigger = React.forwardRef< const NavigationMenuTrigger = React.forwardRef<
@ -83,10 +83,10 @@ const NavigationMenuViewport = React.forwardRef<
React.ElementRef<typeof NavigationMenuPrimitive.Viewport>, React.ElementRef<typeof NavigationMenuPrimitive.Viewport>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Viewport> React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Viewport>
>(({ className, ...props }, ref) => ( >(({ className, ...props }, ref) => (
<div className={cn("absolute left-0 top-full flex justify-center")}> <div className={cn("absolute right-0 top-full flex ")}>
<NavigationMenuPrimitive.Viewport <NavigationMenuPrimitive.Viewport
className={cn( className={cn(
"origin-top-center relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 md:w-[var(--radix-navigation-menu-viewport-width)]", "origin-top-left relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 md:w-[var(--radix-navigation-menu-viewport-width)]",
className className
)} )}
ref={ref} ref={ref}

View File

@ -0,0 +1,9 @@
import { ReactNode } from 'react';
export default function PageWrapper({ children }: { children: ReactNode }) {
return (
<div className="flex flex-col pt-2 px-4 space-y-2 bg-zinc-100 flex-grow pb-4">
{children}
</div>
);
}

7
components/types.tsx Normal file
View File

@ -0,0 +1,7 @@
export type NavItem = {
title: string;
path: string;
icon?: JSX.Element;
submenu?: boolean;
subMenuItems?: NavItem[];
};

View File

@ -1,47 +0,0 @@
'use client'
import Link from 'next/link'
import Image from 'next/image'
import logo from '@/public/images/kx3dex_radio_logo.png'
import {
NavigationMenu,
NavigationMenuContent,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
NavigationMenuTrigger,
} from "@/components/ui/navigation-menu"
export default function Header() {
return (
<nav className="w-full relative flex items-center max-w-5xl mx-auto px-4 py-5">
<Image
src={logo}
width={100}
height={100}
alt="Logo Image"
priority
className="rounded-lg border"
/>
<Link href="/" className="font-bold text-3xl pl-10 pr-5">
Home
</Link>
<Link href="/dexnet" className="font-bold text-3xl ">
DexNet
</Link>
<NavigationMenu>
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuTrigger className="font-bold text-3xl pr-5">Go Kits</NavigationMenuTrigger>
<NavigationMenuContent className="flex flex-col min-w-[300px] p-2">
<NavigationMenuLink href="/projects/go-kit-command-center" className="font-bold">Go Kit (Command Center)</NavigationMenuLink>
</NavigationMenuContent>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
</nav>
)
}

21
hooks/use-scroll.tsx Normal file
View File

@ -0,0 +1,21 @@
import { useCallback, useEffect, useState } from 'react';
export default function useScroll(threshold: number) {
const [scrolled, setScrolled] = useState(false);
const onScroll = useCallback(() => {
setScrolled(window.scrollY > threshold);
}, [threshold]);
useEffect(() => {
window.addEventListener('scroll', onScroll);
return () => window.removeEventListener('scroll', onScroll);
}, [onScroll]);
// also check on first load
useEffect(() => {
onScroll();
}, [onScroll]);
return scrolled;
}

106
package-lock.json generated
View File

@ -8,20 +8,25 @@
"name": "kx3dex_radio", "name": "kx3dex_radio",
"version": "1.0.0", "version": "1.0.0",
"dependencies": { "dependencies": {
"@iconify/react": "^4.1.1",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-navigation-menu": "^1.1.4", "@radix-ui/react-navigation-menu": "^1.1.4",
"class-variance-authority": "^0.7.0", "class-variance-authority": "^0.7.0",
"clsx": "^2.1.0", "clsx": "^2.1.0",
"framer-motion": "^11.0.27",
"lucide-react": "^0.363.0", "lucide-react": "^0.363.0",
"next": "14.1.4", "next": "14.1.4",
"next-themes": "^0.3.0", "next-themes": "^0.3.0",
"react": "^18", "react": "^18",
"react-dom": "^18", "react-dom": "^18",
"react-icons": "^5.0.1",
"sharp": "^0.33.3", "sharp": "^0.33.3",
"swiper": "^11.1.0", "swiper": "^11.1.0",
"tailwind-merge": "^2.2.2", "tailwind-merge": "^2.2.2",
"tailwindcss-animate": "^1.0.7" "tailwindcss-animate": "^1.0.7",
"vaul": "^0.9.0"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^20", "@types/node": "^20",
@ -198,6 +203,25 @@
"integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==",
"dev": true "dev": true
}, },
"node_modules/@iconify/react": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/@iconify/react/-/react-4.1.1.tgz",
"integrity": "sha512-jed14EjvKjee8mc0eoscGxlg7mSQRkwQG3iX3cPBCO7UlOjz0DtlvTqxqEcHUJGh+z1VJ31Yhu5B9PxfO0zbdg==",
"dependencies": {
"@iconify/types": "^2.0.0"
},
"funding": {
"url": "https://github.com/sponsors/cyberalien"
},
"peerDependencies": {
"react": ">=16"
}
},
"node_modules/@iconify/types": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz",
"integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="
},
"node_modules/@img/sharp-darwin-arm64": { "node_modules/@img/sharp-darwin-arm64": {
"version": "0.33.3", "version": "0.33.3",
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.3.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.3.tgz",
@ -994,6 +1018,42 @@
} }
} }
}, },
"node_modules/@radix-ui/react-dialog": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.0.5.tgz",
"integrity": "sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.1",
"@radix-ui/react-compose-refs": "1.0.1",
"@radix-ui/react-context": "1.0.1",
"@radix-ui/react-dismissable-layer": "1.0.5",
"@radix-ui/react-focus-guards": "1.0.1",
"@radix-ui/react-focus-scope": "1.0.4",
"@radix-ui/react-id": "1.0.1",
"@radix-ui/react-portal": "1.0.4",
"@radix-ui/react-presence": "1.0.1",
"@radix-ui/react-primitive": "1.0.3",
"@radix-ui/react-slot": "1.0.2",
"@radix-ui/react-use-controllable-state": "1.0.1",
"aria-hidden": "^1.1.1",
"react-remove-scroll": "2.5.5"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-direction": { "node_modules/@radix-ui/react-direction": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.0.1.tgz", "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.0.1.tgz",
@ -3290,6 +3350,30 @@
"url": "https://github.com/sponsors/rawify" "url": "https://github.com/sponsors/rawify"
} }
}, },
"node_modules/framer-motion": {
"version": "11.0.27",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.0.27.tgz",
"integrity": "sha512-OmY1hnBXxUfvQTuoPqumAiXYPEt8jY31Fqbmihf/NR29XUL9BkRPHrqVqtJS7TLKriwRt+0pbwiO9tnziZTJzA==",
"dependencies": {
"tslib": "^2.4.0"
},
"peerDependencies": {
"@emotion/is-prop-valid": "*",
"react": "^18.0.0",
"react-dom": "^18.0.0"
},
"peerDependenciesMeta": {
"@emotion/is-prop-valid": {
"optional": true
},
"react": {
"optional": true
},
"react-dom": {
"optional": true
}
}
},
"node_modules/fs.realpath": { "node_modules/fs.realpath": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@ -4957,6 +5041,14 @@
"react": "^18.2.0" "react": "^18.2.0"
} }
}, },
"node_modules/react-icons": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.0.1.tgz",
"integrity": "sha512-WqLZJ4bLzlhmsvme6iFdgO8gfZP17rfjYEJ2m9RsZjZ+cc4k1hTzknEz63YS1MeT50kVzoa1Nz36f4BEx+Wigw==",
"peerDependencies": {
"react": "*"
}
},
"node_modules/react-is": { "node_modules/react-is": {
"version": "16.13.1", "version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
@ -6027,6 +6119,18 @@
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
}, },
"node_modules/vaul": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/vaul/-/vaul-0.9.0.tgz",
"integrity": "sha512-bZSySGbAHiTXmZychprnX/dE0EsSige88xtyyL3/MCRbrFotRPQZo7UdydGXZWw+CKbNOw5Ow8gwAo93/nB/Cg==",
"dependencies": {
"@radix-ui/react-dialog": "^1.0.4"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/which": { "node_modules/which": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",

View File

@ -1,6 +1,6 @@
{ {
"name": "kx3dex_radio", "name": "kx3dex_radio",
"version": "1.0.0", "version": "1.3.5",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev",
@ -9,20 +9,25 @@
"lint": "next lint" "lint": "next lint"
}, },
"dependencies": { "dependencies": {
"@iconify/react": "^4.1.1",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-navigation-menu": "^1.1.4", "@radix-ui/react-navigation-menu": "^1.1.4",
"class-variance-authority": "^0.7.0", "class-variance-authority": "^0.7.0",
"clsx": "^2.1.0", "clsx": "^2.1.0",
"framer-motion": "^11.0.27",
"lucide-react": "^0.363.0", "lucide-react": "^0.363.0",
"next": "14.1.4", "next": "14.1.4",
"next-themes": "^0.3.0", "next-themes": "^0.3.0",
"react": "^18", "react": "^18",
"react-dom": "^18", "react-dom": "^18",
"react-icons": "^5.0.1",
"sharp": "^0.33.3", "sharp": "^0.33.3",
"swiper": "^11.1.0", "swiper": "^11.1.0",
"tailwind-merge": "^2.2.2", "tailwind-merge": "^2.2.2",
"tailwindcss-animate": "^1.0.7" "tailwindcss-animate": "^1.0.7",
"vaul": "^0.9.0"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^20", "@types/node": "^20",

BIN
public/KX3DEX_DexNet_v1.pdf Normal file

Binary file not shown.

135
yarn.lock
View File

@ -29,11 +29,11 @@ __metadata:
linkType: hard linkType: hard
"@emnapi/runtime@npm:^1.1.0": "@emnapi/runtime@npm:^1.1.0":
version: 1.1.0 version: 1.1.1
resolution: "@emnapi/runtime@npm:1.1.0" resolution: "@emnapi/runtime@npm:1.1.1"
dependencies: dependencies:
tslib: ^2.4.0 tslib: ^2.4.0
checksum: a29917ac2ab20276c416244a0866b4628e50cb7bb9219a1bd51f48c5328d3565a78f5aa97cc81fa8fad8d06356b5274c551744da94184b2495be6b081da829c3 checksum: db5ec075a8fa71d7dbbba8592c8edfed073dfe5181a87bde56f92693985c548be5be3a66c6bd656e41b7f23d0af20d59e55684a81aecc5d2977f74ed24cbe3fe
languageName: node languageName: node
linkType: hard linkType: hard
@ -142,6 +142,24 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@iconify/react@npm:^4.1.1":
version: 4.1.1
resolution: "@iconify/react@npm:4.1.1"
dependencies:
"@iconify/types": ^2.0.0
peerDependencies:
react: ">=16"
checksum: 43b71a0eb4312cf0fa7412b568369e75b8a327b8b7d9fc3dce42b2d047326e39dd17541a8d915fb80b87b20a56eba1a9b52304410624b5814fdf3ad17da9196a
languageName: node
linkType: hard
"@iconify/types@npm:^2.0.0":
version: 2.0.0
resolution: "@iconify/types@npm:2.0.0"
checksum: 029f58542c160e9d4a746869cf2e475b603424d3adf3994c5cc8d0406c47e6e04a3b898b2707840c1c5b9bd5563a1660a34b110d89fce43923baca5222f4e597
languageName: node
linkType: hard
"@img/sharp-darwin-arm64@npm:0.33.3": "@img/sharp-darwin-arm64@npm:0.33.3":
version: 0.33.3 version: 0.33.3
resolution: "@img/sharp-darwin-arm64@npm:0.33.3" resolution: "@img/sharp-darwin-arm64@npm:0.33.3"
@ -480,15 +498,15 @@ __metadata:
linkType: hard linkType: hard
"@npmcli/agent@npm:^2.0.0": "@npmcli/agent@npm:^2.0.0":
version: 2.2.1 version: 2.2.2
resolution: "@npmcli/agent@npm:2.2.1" resolution: "@npmcli/agent@npm:2.2.2"
dependencies: dependencies:
agent-base: ^7.1.0 agent-base: ^7.1.0
http-proxy-agent: ^7.0.0 http-proxy-agent: ^7.0.0
https-proxy-agent: ^7.0.1 https-proxy-agent: ^7.0.1
lru-cache: ^10.0.1 lru-cache: ^10.0.1
socks-proxy-agent: ^8.0.1 socks-proxy-agent: ^8.0.3
checksum: c69aca42dbba393f517bc5777ee872d38dc98ea0e5e93c1f6d62b82b8fecdc177a57ea045f07dda1a770c592384b2dd92a5e79e21e2a7cf51c9159466a8f9c9b checksum: 67de7b88cc627a79743c88bab35e023e23daf13831a8aa4e15f998b92f5507b644d8ffc3788afc8e64423c612e0785a6a92b74782ce368f49a6746084b50d874
languageName: node languageName: node
linkType: hard linkType: hard
@ -590,6 +608,39 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@radix-ui/react-dialog@npm:^1.0.4, @radix-ui/react-dialog@npm:^1.0.5":
version: 1.0.5
resolution: "@radix-ui/react-dialog@npm:1.0.5"
dependencies:
"@babel/runtime": ^7.13.10
"@radix-ui/primitive": 1.0.1
"@radix-ui/react-compose-refs": 1.0.1
"@radix-ui/react-context": 1.0.1
"@radix-ui/react-dismissable-layer": 1.0.5
"@radix-ui/react-focus-guards": 1.0.1
"@radix-ui/react-focus-scope": 1.0.4
"@radix-ui/react-id": 1.0.1
"@radix-ui/react-portal": 1.0.4
"@radix-ui/react-presence": 1.0.1
"@radix-ui/react-primitive": 1.0.3
"@radix-ui/react-slot": 1.0.2
"@radix-ui/react-use-controllable-state": 1.0.1
aria-hidden: ^1.1.1
react-remove-scroll: 2.5.5
peerDependencies:
"@types/react": "*"
"@types/react-dom": "*"
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
peerDependenciesMeta:
"@types/react":
optional: true
"@types/react-dom":
optional: true
checksum: 3d11ca31afb794a6dd286005ab7894cb0ce7bc2de5481de98900470b11d495256401306763de030f5e35aa545ff90d34632ffd54a1b29bf55afba813be4bb84a
languageName: node
linkType: hard
"@radix-ui/react-direction@npm:1.0.1": "@radix-ui/react-direction@npm:1.0.1":
version: 1.0.1 version: 1.0.1
resolution: "@radix-ui/react-direction@npm:1.0.1" resolution: "@radix-ui/react-direction@npm:1.0.1"
@ -1213,12 +1264,12 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"agent-base@npm:^7.0.2, agent-base@npm:^7.1.0": "agent-base@npm:^7.0.2, agent-base@npm:^7.1.0, agent-base@npm:^7.1.1":
version: 7.1.0 version: 7.1.1
resolution: "agent-base@npm:7.1.0" resolution: "agent-base@npm:7.1.1"
dependencies: dependencies:
debug: ^4.3.4 debug: ^4.3.4
checksum: f7828f991470a0cc22cb579c86a18cbae83d8a3cbed39992ab34fc7217c4d126017f1c74d0ab66be87f71455318a8ea3e757d6a37881b8d0f2a2c6aa55e5418f checksum: 51c158769c5c051482f9ca2e6e1ec085ac72b5a418a9b31b4e82fe6c0a6699adb94c1c42d246699a587b3335215037091c79e0de512c516f73b6ea844202f037
languageName: node languageName: node
linkType: hard linkType: hard
@ -2509,6 +2560,26 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"framer-motion@npm:^11.0.27":
version: 11.0.27
resolution: "framer-motion@npm:11.0.27"
dependencies:
tslib: ^2.4.0
peerDependencies:
"@emotion/is-prop-valid": "*"
react: ^18.0.0
react-dom: ^18.0.0
peerDependenciesMeta:
"@emotion/is-prop-valid":
optional: true
react:
optional: true
react-dom:
optional: true
checksum: 07809e386288350547bd9193143d9e33e6ab2d1357152b4d90acf50a445437b59ddb1653dcedde75579d3af8c7904c158fdfa6ad97d65786855eb002634bb38b
languageName: node
linkType: hard
"fs-minipass@npm:^2.0.0": "fs-minipass@npm:^2.0.0":
version: 2.1.0 version: 2.1.0
resolution: "fs-minipass@npm:2.1.0" resolution: "fs-minipass@npm:2.1.0"
@ -3295,6 +3366,8 @@ __metadata:
version: 0.0.0-use.local version: 0.0.0-use.local
resolution: "kx3dex_radio@workspace:." resolution: "kx3dex_radio@workspace:."
dependencies: dependencies:
"@iconify/react": ^4.1.1
"@radix-ui/react-dialog": ^1.0.5
"@radix-ui/react-dropdown-menu": ^2.0.6 "@radix-ui/react-dropdown-menu": ^2.0.6
"@radix-ui/react-icons": ^1.3.0 "@radix-ui/react-icons": ^1.3.0
"@radix-ui/react-navigation-menu": ^1.1.4 "@radix-ui/react-navigation-menu": ^1.1.4
@ -3306,18 +3379,21 @@ __metadata:
clsx: ^2.1.0 clsx: ^2.1.0
eslint: ^8 eslint: ^8
eslint-config-next: 14.1.4 eslint-config-next: 14.1.4
framer-motion: ^11.0.27
lucide-react: ^0.363.0 lucide-react: ^0.363.0
next: 14.1.4 next: 14.1.4
next-themes: ^0.3.0 next-themes: ^0.3.0
postcss: ^8 postcss: ^8
react: ^18 react: ^18
react-dom: ^18 react-dom: ^18
react-icons: ^5.0.1
sharp: ^0.33.3 sharp: ^0.33.3
swiper: ^11.1.0 swiper: ^11.1.0
tailwind-merge: ^2.2.2 tailwind-merge: ^2.2.2
tailwindcss: ^3.4.1 tailwindcss: ^3.4.1
tailwindcss-animate: ^1.0.7 tailwindcss-animate: ^1.0.7
typescript: ^5 typescript: ^5
vaul: ^0.9.0
languageName: unknown languageName: unknown
linkType: soft linkType: soft
@ -4120,6 +4196,15 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"react-icons@npm:^5.0.1":
version: 5.0.1
resolution: "react-icons@npm:5.0.1"
peerDependencies:
react: "*"
checksum: e5df9c5e3bcdb8d68bd4c5e41650c26d2a3ceda61ded0e2abf7caa0e54c9fb712badcd06f0c240cfc645a5dd15a5dc1eb5dd55f60123d86860f516b1fc456474
languageName: node
linkType: hard
"react-is@npm:^16.13.1": "react-is@npm:^16.13.1":
version: 16.13.1 version: 16.13.1
resolution: "react-is@npm:16.13.1" resolution: "react-is@npm:16.13.1"
@ -4552,24 +4637,24 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"socks-proxy-agent@npm:^8.0.1": "socks-proxy-agent@npm:^8.0.3":
version: 8.0.2 version: 8.0.3
resolution: "socks-proxy-agent@npm:8.0.2" resolution: "socks-proxy-agent@npm:8.0.3"
dependencies: dependencies:
agent-base: ^7.0.2 agent-base: ^7.1.1
debug: ^4.3.4 debug: ^4.3.4
socks: ^2.7.1 socks: ^2.7.1
checksum: 4fb165df08f1f380881dcd887b3cdfdc1aba3797c76c1e9f51d29048be6e494c5b06d68e7aea2e23df4572428f27a3ec22b3d7c75c570c5346507433899a4b6d checksum: 8fab38821c327c190c28f1658087bc520eb065d55bc07b4a0fdf8d1e0e7ad5d115abbb22a95f94f944723ea969dd771ad6416b1e3cde9060c4c71f705c8b85c5
languageName: node languageName: node
linkType: hard linkType: hard
"socks@npm:^2.7.1": "socks@npm:^2.7.1":
version: 2.8.1 version: 2.8.3
resolution: "socks@npm:2.8.1" resolution: "socks@npm:2.8.3"
dependencies: dependencies:
ip-address: ^9.0.5 ip-address: ^9.0.5
smart-buffer: ^4.2.0 smart-buffer: ^4.2.0
checksum: 29586d42e9c36c5016632b2bcb6595e3adfbcb694b3a652c51bc8741b079c5ec37bdd5675a1a89a1620078c8137208294991fabb50786f92d47759a725b2b62e checksum: 7a6b7f6eedf7482b9e4597d9a20e09505824208006ea8f2c49b71657427f3c137ca2ae662089baa73e1971c62322d535d9d0cf1c9235cf6f55e315c18203eadd
languageName: node languageName: node
linkType: hard linkType: hard
@ -5095,6 +5180,18 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"vaul@npm:^0.9.0":
version: 0.9.0
resolution: "vaul@npm:0.9.0"
dependencies:
"@radix-ui/react-dialog": ^1.0.4
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
checksum: 12c4ced1a91400abe8d20c0c2108f2ffe7d81172eb08c3d7a24e9f813a034e00a9ddb43bb30a7ec312e71292d7b15b13d0fd9e866646b35e13b6d8bc61974198
languageName: node
linkType: hard
"which-boxed-primitive@npm:^1.0.2": "which-boxed-primitive@npm:^1.0.2":
version: 1.0.2 version: 1.0.2
resolution: "which-boxed-primitive@npm:1.0.2" resolution: "which-boxed-primitive@npm:1.0.2"