diff --git a/apps/web/app/global.css b/apps/web/app/global.css
deleted file mode 100644
index 1b8feb48..00000000
--- a/apps/web/app/global.css
+++ /dev/null
@@ -1,17 +0,0 @@
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
-
-* {
- margin: 0;
- padding: 0;
-}
-
-.unselectable {
- user-drag: none;
- user-select: none;
- -moz-user-select: none;
- -webkit-user-drag: none;
- -webkit-user-select: none;
- -ms-user-select: none;
-}
\ No newline at end of file
diff --git a/apps/web/app/page.tsx b/apps/web/app/page.tsx
deleted file mode 100644
index dab394e7..00000000
--- a/apps/web/app/page.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-import { Poppins } from 'next/font/google'
-import Links from '../components/links'
-import Killers from '../components/killers'
-import { Logo, Grid, Stars } from '../public'
-
-const poppins = Poppins({
- subsets: ['latin'],
- weight: ['400', '500', '600', '700']
-})
-
-function Index(): React.JSX.Element {
- return (
-
-
-
-
-
-
-
-
-
-
-
-
- keyshade.xyz
-
-
-
-
- Manage all your secrets securely with public key encryption and
- realtime based tools, that seamlessly fits into your codebase
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- )
-}
-
-export default Index
diff --git a/apps/web/components/killers.tsx b/apps/web/components/killers.tsx
deleted file mode 100644
index a2b77c60..00000000
--- a/apps/web/components/killers.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-import Image from 'next/image'
-import { Inter } from 'next/font/google'
-import React from 'react'
-
-const inter = Inter({ subsets: ['latin'] })
-
-interface KillersProps {
- image: string
- twitterUserName: string
-}
-function Killers({ image, twitterUserName }: KillersProps): React.JSX.Element {
- return (
-
- )
-}
-
-export default Killers
diff --git a/apps/web/package.json b/apps/web/package.json
index 3f96fb40..aeb7a99d 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -9,9 +9,14 @@
"lint": "next lint --fix"
},
"dependencies": {
+ "clsx": "^2.1.0",
+ "framer-motion": "^11.0.8",
+ "jsonp": "^0.2.1",
"next": "^13.5.6",
"react": "^18.2.0",
- "react-dom": "^18.2.0"
+ "react-dom": "^18.2.0",
+ "sonner": "^1.4.3",
+ "tailwind-merge": "^2.2.1"
},
"devDependencies": {
"@next/eslint-plugin-next": "^13.4.19",
diff --git a/apps/web/public/XSVG.svg b/apps/web/public/XSVG.svg
new file mode 100644
index 00000000..8544187d
--- /dev/null
+++ b/apps/web/public/XSVG.svg
@@ -0,0 +1,3 @@
+
diff --git a/apps/web/public/discordSVG.svg b/apps/web/public/discordSVG.svg
new file mode 100644
index 00000000..9284e6b1
--- /dev/null
+++ b/apps/web/public/discordSVG.svg
@@ -0,0 +1,3 @@
+
diff --git a/apps/web/public/index.ts b/apps/web/public/index.ts
index 04b8b91e..9f2abce8 100644
--- a/apps/web/public/index.ts
+++ b/apps/web/public/index.ts
@@ -3,3 +3,7 @@ export { default as Grid } from './grid.svg'
export { default as Logo } from './logo.svg'
export { default as XSvg } from './x_svg.svg'
export { default as Stars } from './stars.svg'
+
+export {default as XSVG} from "./XSVG.svg"
+export {default as LinkdinSVG} from "./linkdinSVG (1).svg"
+export {default as DiscordSVG} from "./discordSVG.svg"
diff --git a/apps/web/public/linkdinSVG (1).svg b/apps/web/public/linkdinSVG (1).svg
new file mode 100644
index 00000000..aac8deab
--- /dev/null
+++ b/apps/web/public/linkdinSVG (1).svg
@@ -0,0 +1,10 @@
+
diff --git a/apps/web/src/app/global.css b/apps/web/src/app/global.css
new file mode 100644
index 00000000..2a8abb88
--- /dev/null
+++ b/apps/web/src/app/global.css
@@ -0,0 +1,7 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+body {
+ background: #03080B;
+}
\ No newline at end of file
diff --git a/apps/web/app/layout.tsx b/apps/web/src/app/layout.tsx
similarity index 100%
rename from apps/web/app/layout.tsx
rename to apps/web/src/app/layout.tsx
diff --git a/apps/web/src/app/page.tsx b/apps/web/src/app/page.tsx
new file mode 100644
index 00000000..03598f0f
--- /dev/null
+++ b/apps/web/src/app/page.tsx
@@ -0,0 +1,152 @@
+'use client'
+
+import { Poppins } from 'next/font/google'
+import { useState } from 'react'
+import { Toaster, toast } from 'sonner'
+import { InputBorderSpotlight } from '@/components/ui/input-spotlight'
+import EncryptButton from '@/components/ui/encrypt-btn'
+import Links from '../components/links'
+import Killers from '../components/killers'
+import { Logo, Grid, Stars, DiscordSVG, XSVG, LinkdinSVG } from '../../public'
+
+const poppins = Poppins({
+ subsets: ['latin'],
+ weight: ['400', '500', '600', '700']
+})
+
+function Index(): React.JSX.Element {
+ const [email, setEmail] = useState('')
+
+ // eslint-disable-next-line no-console -- chill
+ console.log(email)
+
+ const onSubmit = (e: React.FormEvent): void => {
+ e.preventDefault()
+
+ if (email === '') {
+ toast.custom(() => (
+
+
Pleasse enter an email address
+
+ ))
+ return
+ }
+
+ const url =
+ 'https://xyz.us18.list-manage.com/subscribe/post?u=2e44b940cafe6e54d8b9e0790&id=bd382dd7c5&f_id=00e5c2e1f0'
+
+ async function fetchData(): Promise {
+ toast.custom((_t) => (
+
+
Welcome to Keyshade 🎉
+
+ You have been added to the waitlist. We will notify you once we
+ launch
+
+ {/*
*/}
+
+ ))
+ try {
+ await fetch(`${url}&EMAIL=${email}`, {
+ mode: 'no-cors'
+ })
+ } catch (error) {
+ // eslint-disable-next-line no-console -- chill
+ console.error(error)
+ }
+ }
+ void fetchData()
+ }
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ keyshade.xyz
+
+
+
+
+ Manage all your secrets securely with public key encryption
+ and realtime based tools, that seamlessly fits into your
+ codebase
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ )
+}
+
+export default Index
diff --git a/apps/web/src/components/killers.tsx b/apps/web/src/components/killers.tsx
new file mode 100644
index 00000000..7f3cef5f
--- /dev/null
+++ b/apps/web/src/components/killers.tsx
@@ -0,0 +1,16 @@
+import React from 'react'
+
+interface KillersProps {
+ children: React.ReactNode
+}
+function Killers({ children }: KillersProps): React.JSX.Element {
+ return (
+
+ )
+}
+
+export default Killers
diff --git a/apps/web/components/links.tsx b/apps/web/src/components/links.tsx
similarity index 100%
rename from apps/web/components/links.tsx
rename to apps/web/src/components/links.tsx
diff --git a/apps/web/src/components/ui/encrypt-btn.tsx b/apps/web/src/components/ui/encrypt-btn.tsx
new file mode 100644
index 00000000..875e8db0
--- /dev/null
+++ b/apps/web/src/components/ui/encrypt-btn.tsx
@@ -0,0 +1,104 @@
+'use client'
+import React, { useRef, useState } from 'react'
+import { motion } from 'framer-motion'
+
+interface EncryptButtonProps extends React.HTMLProps {
+ TARGET_TEXT: string
+}
+
+function EncryptButton({ TARGET_TEXT }: EncryptButtonProps): React.JSX.Element {
+ // const TARGET_TEXT = 'Join Waitlist'
+ const CYCLES_PER_LETTER = 2
+ const SHUFFLE_TIME = 50
+
+ const CHARS = '!@#$%^&*():{};|,.<>/?'
+
+ const intervalRef = useRef | null>(null)
+
+ const [text, setText] = useState(TARGET_TEXT)
+
+ const scramble = (): void => {
+ let pos = 0
+
+ intervalRef.current = setInterval(() => {
+ const scrambled = TARGET_TEXT.split('')
+ .map((char, index) => {
+ if (pos / CYCLES_PER_LETTER > index) {
+ return char
+ }
+
+ const randomCharIndex = Math.floor(Math.random() * CHARS.length)
+ const randomChar = CHARS[randomCharIndex]
+
+ return randomChar
+ })
+ .join('')
+
+ setText(scrambled)
+ pos++
+
+ if (pos >= TARGET_TEXT.length * CYCLES_PER_LETTER) {
+ stopScramble()
+ }
+ }, SHUFFLE_TIME)
+ }
+
+ const stopScramble = (): void => {
+ clearInterval(intervalRef.current || undefined)
+
+ setText(TARGET_TEXT)
+ }
+
+ return (
+
+
+
+ {text}{' '}
+
+
+
+
+
+ )
+}
+
+export default EncryptButton
diff --git a/apps/web/src/components/ui/input-spotlight.tsx b/apps/web/src/components/ui/input-spotlight.tsx
new file mode 100644
index 00000000..af95d42a
--- /dev/null
+++ b/apps/web/src/components/ui/input-spotlight.tsx
@@ -0,0 +1,77 @@
+'use client'
+import type { Dispatch, SetStateAction } from 'react'
+import React, { useRef, useState } from 'react'
+
+interface InputBorderSpotlightProps {
+ setEmail: Dispatch>
+}
+
+export function InputBorderSpotlight({
+ setEmail
+}: InputBorderSpotlightProps): React.JSX.Element {
+ const divRef = useRef(null)
+ const [isFocused, setIsFocused] = useState(false)
+ const [position, setPosition] = useState({ x: 0, y: 0 })
+ const [opacity, setOpacity] = useState(0)
+
+ const handleMouseMove = (e: React.MouseEvent): void => {
+ if (!divRef.current || isFocused) return
+
+ const div = divRef.current
+ const rect = div.getBoundingClientRect()
+
+ setPosition({ x: e.clientX - rect.left, y: e.clientY - rect.top })
+ }
+
+ const handleFocus = (): void => {
+ setIsFocused(true)
+ setOpacity(1)
+ }
+
+ const handleBlur = (): void => {
+ setIsFocused(false)
+ setOpacity(0)
+ }
+
+ const handleMouseEnter = (): void => {
+ setOpacity(1)
+ }
+
+ const handleMouseLeave = (): void => {
+ setOpacity(0)
+ }
+
+ return (
+
+ {
+ setEmail(e.target.value)
+ }}
+ onFocus={handleFocus}
+ onMouseEnter={handleMouseEnter}
+ onMouseLeave={handleMouseLeave}
+ onMouseMove={handleMouseMove}
+ placeholder="Enter your email address"
+ size={25}
+ type="email"
+ />
+
+
+ )
+}
diff --git a/apps/web/src/components/ui/moving-border.tsx b/apps/web/src/components/ui/moving-border.tsx
new file mode 100644
index 00000000..575a76a4
--- /dev/null
+++ b/apps/web/src/components/ui/moving-border.tsx
@@ -0,0 +1,149 @@
+/* eslint-disable @typescript-eslint/no-unsafe-assignment -- chill */
+/* eslint-disable @typescript-eslint/no-unsafe-member-access -- chill */
+'use client'
+import { useRef } from 'react'
+import {
+ motion,
+ useAnimationFrame,
+ useMotionTemplate,
+ useMotionValue,
+ useTransform
+} from 'framer-motion'
+import { cn } from '@/utils/cn'
+
+export function Button({
+ borderRadius = '9999px',
+ children,
+ as: Component = 'button',
+ containerClassName,
+ borderClassName,
+ duration,
+ className,
+ ...otherProps
+}: {
+ borderRadius?: string
+ children: React.ReactNode
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- it's okey
+ as?: any
+ containerClassName?: string
+ borderClassName?: string
+ duration?: number
+ className?: string
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- it's okey
+ [key: string]: any
+}): React.JSX.Element {
+ return (
+
+
+
+
+
+ )
+}
+
+export function MovingBorder({
+ children,
+ duration = 2000,
+ rx,
+ ry,
+ ...otherProps
+}: {
+ children: React.ReactNode
+ duration?: number
+ rx?: string
+ ry?: string
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- it's
+ [key: string]: any
+}): React.JSX.Element {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- ok
+ const pathRef = useRef()
+ const progress = useMotionValue(0)
+
+ useAnimationFrame((time) => {
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call -- chill
+ const length = pathRef.current?.getTotalLength()
+ if (length) {
+ const pxPerMillisecond = length / duration
+ progress.set((time * pxPerMillisecond) % length)
+ }
+ })
+
+ const x = useTransform(
+ progress,
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call -- ignore
+ (val) => pathRef.current?.getPointAtLength(val).x
+ )
+ const y = useTransform(
+ progress,
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call -- ignore
+ (val) => pathRef.current?.getPointAtLength(val).y
+ )
+
+ const transform = useMotionTemplate`translateX(${x}px) translateY(${y}px) translateX(-50%) translateY(-50%)`
+
+ return (
+ <>
+
+
+ {children}
+
+ >
+ )
+}
diff --git a/apps/web/src/utils/cn.ts b/apps/web/src/utils/cn.ts
new file mode 100644
index 00000000..8b400cb8
--- /dev/null
+++ b/apps/web/src/utils/cn.ts
@@ -0,0 +1,7 @@
+import type { ClassValue } from 'clsx'
+import { clsx } from 'clsx'
+import { twMerge } from 'tailwind-merge'
+
+export function cn(...inputs: ClassValue[]): string {
+ return twMerge(clsx(inputs))
+}
diff --git a/apps/web/tailwind.config.js b/apps/web/tailwind.config.js
index d0b89854..b61c2997 100644
--- a/apps/web/tailwind.config.js
+++ b/apps/web/tailwind.config.js
@@ -1,60 +1,34 @@
-const plugin = require('tailwindcss/plugin')
-
-const radialGradientPlugin = plugin(
- function ({ matchUtilities, theme }) {
- matchUtilities(
- {
- // map to bg-radient-[*]
- 'bg-radient': (value) => ({
- 'background-image': `radial-gradient(${value},var(--tw-gradient-stops))`
- })
- },
- { values: theme('radialGradients') }
- )
- },
- {
- theme: {
- radialGradients: _presets()
- }
- }
-)
-
-/**
- * utility class presets
- */
-function _presets() {
- const shapes = ['circle', 'ellipse']
- const pos = {
- c: 'center',
- t: 'top',
- b: 'bottom',
- l: 'left',
- r: 'right',
- tl: 'top left',
- tr: 'top right',
- bl: 'bottom left',
- br: 'bottom right'
- }
- let result = {}
- for (const shape of shapes)
- for (const [posName, posValue] of Object.entries(pos))
- result[`${shape}-${posName}`] = `${shape} at ${posValue}`
-
- return result
-}
+const defaultTheme = require('tailwindcss/defaultTheme')
+const colors = require('tailwindcss/colors')
+const {
+ default: flattenColorPalette
+} = require('tailwindcss/lib/util/flattenColorPalette')
/** @type {import('tailwindcss').Config} */
module.exports = {
- content: [
- './app/**/*.{js,ts,jsx,tsx,mdx}',
- './pages/**/*.{js,ts,jsx,tsx,mdx}',
- './components/**/*.{js,ts,jsx,tsx,mdx}',
-
- // Or if using `src` directory:
- './src/**/*.{js,ts,jsx,tsx,mdx}'
- ],
+ content: ['./src/**/*.{ts,tsx}'],
+ darkMode: 'class',
theme: {
- extend: {}
+ extend: {
+ colors: {
+ brandBlue: '#CAECF1'
+ }
+ }
},
- plugins: [radialGradientPlugin]
+ plugins: [
+ // rest of the code
+ addVariablesForColors
+ ]
+}
+
+// This plugin adds each Tailwind color as a global CSS variable, e.g. var(--gray-200).
+function addVariablesForColors({ addBase, theme }) {
+ let allColors = flattenColorPalette(theme('colors'))
+ let newVars = Object.fromEntries(
+ Object.entries(allColors).map(([key, val]) => [`--${key}`, val])
+ )
+
+ addBase({
+ ':root': newVars
+ })
}