Merge branch 'main' of github.com:MkSaaSHQ/mksaas-template
This commit is contained in:
commit
50d6e2b069
@ -124,3 +124,10 @@ NEXT_PUBLIC_SELINE_TOKEN=""
|
||||
# -----------------------------------------------------------------------------
|
||||
NEXT_PUBLIC_DATAFAST_ANALYTICS_ID=""
|
||||
NEXT_PUBLIC_DATAFAST_ANALYTICS_DOMAIN=""
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Discord
|
||||
# -----------------------------------------------------------------------------
|
||||
NEXT_PUBLIC_DISCORD_WIDGET_SERVER_ID=""
|
||||
NEXT_PUBLIC_DISCORD_WIDGET_CHANNEL_ID=""
|
||||
|
@ -71,6 +71,7 @@
|
||||
"@types/canvas-confetti": "^1.9.0",
|
||||
"@vercel/analytics": "^1.5.0",
|
||||
"@vercel/speed-insights": "^1.2.0",
|
||||
"@widgetbot/react-embed": "^1.9.0",
|
||||
"ai": "^4.1.45",
|
||||
"better-auth": "^1.1.19",
|
||||
"canvas-confetti": "^1.9.3",
|
||||
|
48
pnpm-lock.yaml
generated
48
pnpm-lock.yaml
generated
@ -170,6 +170,9 @@ importers:
|
||||
'@vercel/speed-insights':
|
||||
specifier: ^1.2.0
|
||||
version: 1.2.0(next@15.2.1(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)
|
||||
'@widgetbot/react-embed':
|
||||
specifier: ^1.9.0
|
||||
version: 1.9.0(react@19.0.0)
|
||||
ai:
|
||||
specifier: ^4.1.45
|
||||
version: 4.1.45(react@19.0.0)(zod@3.24.2)
|
||||
@ -3278,6 +3281,14 @@ packages:
|
||||
vue-router:
|
||||
optional: true
|
||||
|
||||
'@widgetbot/embed-api@1.2.17':
|
||||
resolution: {integrity: sha512-qoiFLMak+mBG64pgKN5xFv3amPHcG2qcurPefAbof4DI/eip5OU59pbM+ak4d9d9OIkwA1QhoDzo9KWD/cOn0w==}
|
||||
|
||||
'@widgetbot/react-embed@1.9.0':
|
||||
resolution: {integrity: sha512-+Qgqy7lwLy++lIiHmSsgxUjwcX80iFIHR0QJpKq4W82ePUmq4bTuxvUbxcE+VQH5IjNrWaydGNR8zROV5vUQsA==}
|
||||
peerDependencies:
|
||||
react: '>= 15'
|
||||
|
||||
accepts@1.3.8:
|
||||
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
|
||||
engines: {node: '>= 0.6'}
|
||||
@ -3509,6 +3520,12 @@ packages:
|
||||
resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
|
||||
engines: {node: '>= 0.10'}
|
||||
|
||||
cross-domain-safe-weakmap@1.0.29:
|
||||
resolution: {integrity: sha512-VLoUgf2SXnf3+na8NfeUFV59TRZkIJqCIATaMdbhccgtnTlSnHXkyTRwokngEGYdQXx8JbHT9GDYitgR2sdjuA==}
|
||||
|
||||
cross-domain-utils@2.0.38:
|
||||
resolution: {integrity: sha512-zZfi3+2EIR9l4chrEiXI2xFleyacsJf8YMLR1eJ0Veb5FTMXeJ3DpxDjZkto2FhL/g717WSELqbptNSo85UJDw==}
|
||||
|
||||
cross-spawn@7.0.6:
|
||||
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
|
||||
engines: {node: '>= 8'}
|
||||
@ -4822,6 +4839,9 @@ packages:
|
||||
resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
post-robot@8.0.32:
|
||||
resolution: {integrity: sha512-PMOdDAt3pyuKUxZcTzdcXXFxLqkdeLpRlcCQl7QAJpI+e7J1YHH+PfC7KAbcL8hRVQ1LknQYGoirbA1/eO/a1g==}
|
||||
|
||||
postcss-selector-parser@7.1.0:
|
||||
resolution: {integrity: sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==}
|
||||
engines: {node: '>=4'}
|
||||
@ -5601,6 +5621,9 @@ packages:
|
||||
resolution: {integrity: sha512-qJNAmSF77lWjfRVwCZK3PcKYWrr+55RUQTiXDxXHGbxzf8WuuRgftIB3hqZ5fykjOF/MC62cazsG/2ZDBedOnQ==}
|
||||
engines: {node: '>=14.16'}
|
||||
|
||||
zalgo-promise@1.0.48:
|
||||
resolution: {integrity: sha512-LLHANmdm53+MucY9aOFIggzYtUdkSBFxUsy4glTTQYNyK6B3uCPWTbfiGvSrEvLojw0mSzyFJ1/RRLv+QMNdzQ==}
|
||||
|
||||
zod-to-json-schema@3.24.2:
|
||||
resolution: {integrity: sha512-pNUqrcSxuuB3/+jBbU8qKUbTbDqYUaG1vf5cXFjbhGgoUuA1amO/y4Q8lzfOhHU8HNPK6VFJ18lBDKj3OHyDsg==}
|
||||
peerDependencies:
|
||||
@ -8607,6 +8630,15 @@ snapshots:
|
||||
next: 15.2.1(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
react: 19.0.0
|
||||
|
||||
'@widgetbot/embed-api@1.2.17':
|
||||
dependencies:
|
||||
post-robot: 8.0.32
|
||||
|
||||
'@widgetbot/react-embed@1.9.0(react@19.0.0)':
|
||||
dependencies:
|
||||
'@widgetbot/embed-api': 1.2.17
|
||||
react: 19.0.0
|
||||
|
||||
accepts@1.3.8:
|
||||
dependencies:
|
||||
mime-types: 2.1.35
|
||||
@ -8843,6 +8875,14 @@ snapshots:
|
||||
object-assign: 4.1.1
|
||||
vary: 1.1.2
|
||||
|
||||
cross-domain-safe-weakmap@1.0.29:
|
||||
dependencies:
|
||||
cross-domain-utils: 2.0.38
|
||||
|
||||
cross-domain-utils@2.0.38:
|
||||
dependencies:
|
||||
zalgo-promise: 1.0.48
|
||||
|
||||
cross-spawn@7.0.6:
|
||||
dependencies:
|
||||
path-key: 3.1.1
|
||||
@ -10531,6 +10571,12 @@ snapshots:
|
||||
|
||||
pluralize@8.0.0: {}
|
||||
|
||||
post-robot@8.0.32:
|
||||
dependencies:
|
||||
cross-domain-safe-weakmap: 1.0.29
|
||||
cross-domain-utils: 2.0.38
|
||||
zalgo-promise: 1.0.48
|
||||
|
||||
postcss-selector-parser@7.1.0:
|
||||
dependencies:
|
||||
cssesc: 3.0.0
|
||||
@ -11472,6 +11518,8 @@ snapshots:
|
||||
|
||||
yoctocolors@1.0.0: {}
|
||||
|
||||
zalgo-promise@1.0.48: {}
|
||||
|
||||
zod-to-json-schema@3.24.2(zod@3.24.2):
|
||||
dependencies:
|
||||
zod: 3.24.2
|
||||
|
@ -15,7 +15,7 @@ import { Providers } from './providers';
|
||||
import '@/styles/globals.css';
|
||||
import { Analytics } from '@/analytics/analytics';
|
||||
import { TailwindIndicator } from '@/components/layout/tailwind-indicator';
|
||||
|
||||
import DiscordWidget from '@/components/shared/discord-widget';
|
||||
interface LocaleLayoutProps {
|
||||
children: ReactNode;
|
||||
params: Promise<{ locale: Locale }>;
|
||||
@ -56,6 +56,7 @@ export default async function LocaleLayout({
|
||||
{children}
|
||||
|
||||
<Toaster richColors position="top-right" offset={64} />
|
||||
<DiscordWidget />
|
||||
<TailwindIndicator />
|
||||
<Analytics />
|
||||
</Providers>
|
||||
|
@ -1,3 +1,6 @@
|
||||
/**
|
||||
* Tailwind Indicator, shows the current tailwind breakpoint
|
||||
*/
|
||||
export function TailwindIndicator() {
|
||||
if (process.env.NODE_ENV === 'production') return null;
|
||||
|
||||
|
70
src/components/shared/discord-widget.tsx
Normal file
70
src/components/shared/discord-widget.tsx
Normal file
@ -0,0 +1,70 @@
|
||||
'use client';
|
||||
|
||||
import { DiscordIcon } from '@/components/icons/discord';
|
||||
import WidgetBot from '@widgetbot/react-embed';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
|
||||
const WIDGET_WIDTH = 800;
|
||||
const WIDGET_HEIGHT = 600;
|
||||
const ICON_SIZE = 48;
|
||||
|
||||
/**
|
||||
* Discord Widget, shows the channels and messages in the discord server
|
||||
*/
|
||||
export default function DiscordWidget() {
|
||||
const serverId = process.env.NEXT_PUBLIC_DISCORD_WIDGET_SERVER_ID as string;
|
||||
const channelId = process.env.NEXT_PUBLIC_DISCORD_WIDGET_CHANNEL_ID as string;
|
||||
if (!serverId || !channelId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const widgetRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
function handleClick(e: MouseEvent) {
|
||||
if (widgetRef.current && !widgetRef.current.contains(e.target as Node)) {
|
||||
setOpen(false);
|
||||
}
|
||||
}
|
||||
document.addEventListener('mousedown', handleClick);
|
||||
return () => document.removeEventListener('mousedown', handleClick);
|
||||
}, [open]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* discord icon button, show in bottom right corner */}
|
||||
{!open && (
|
||||
<button
|
||||
aria-label="Open Discord Widget"
|
||||
className="fixed bottom-[84px] right-10 z-50 cursor-pointer flex items-center justify-center rounded-full bg-[#5865F2] shadow-lg
|
||||
hover:scale-110 transition-transform duration-150"
|
||||
style={{ width: ICON_SIZE, height: ICON_SIZE }}
|
||||
onClick={() => setOpen(true)}
|
||||
type="button"
|
||||
>
|
||||
<DiscordIcon width={32} height={32} className="text-white" />
|
||||
</button>
|
||||
)}
|
||||
|
||||
{/* discord widget expand layer */}
|
||||
{open && (
|
||||
<div
|
||||
ref={widgetRef}
|
||||
className="fixed bottom-[84px] right-10 z-50 flex flex-col items-end"
|
||||
style={{ width: WIDGET_WIDTH, height: WIDGET_HEIGHT }}
|
||||
>
|
||||
<div className="rounded-lg overflow-hidden shadow-2xl border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-900">
|
||||
<WidgetBot
|
||||
server={serverId}
|
||||
channel={channelId}
|
||||
width={WIDGET_WIDTH}
|
||||
height={WIDGET_HEIGHT}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
Loading…
Reference in New Issue
Block a user