Skip to content

Commit 521a2d3

Browse files
committed
feat: add internet page
1 parent 6b1f1b5 commit 521a2d3

10 files changed

Lines changed: 689 additions & 43 deletions

File tree

.devcontainer/devcontainer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424
"extensions": [
2525
"esbenp.prettier-vscode",
2626
"GitHub.copilot-labs",
27-
"GitHub.copilot"
27+
"GitHub.copilot",
28+
"bradlc.vscode-tailwindcss"
2829
]
2930
}
3031
}

.storybook/componentCode.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,8 @@ export const ComponentCode = ({ of }) => {
4747
// resolvedOf.story.originalStoryFn(resolvedOf.story, resolvedOf) as React.ReactNode,
4848
// )
4949
}
50-
clientOrServer = resolvedOf.story.tags.includes('server') ? '/server' : '/client'
5150
}
52-
const path = `import { ${componentNames.join(', ')} } from '@/components/components${clientOrServer}'`
51+
const path = `import { ${componentNames.join(', ')} } from 'cortex-react-components'`
5352

5453
switch (resolvedOf.type) {
5554
case 'story': {

.storybook/main.ts

Lines changed: 29 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
/** @type { import('@storybook/react-webpack5').StorybookConfig } */
1+
import { StorybookConfig } from '@storybook/nextjs';
22
const path = require('path')
33

4-
const config = {
4+
const config: StorybookConfig = {
55
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
66
addons: [
77
// "@storybook/addon-webpack5-compiler-swc",
@@ -45,33 +45,32 @@ const config = {
4545
options: {},
4646
},
4747
staticDirs: ['./public', './msw', '../src/images'],
48-
webpackFinal: async (config) => {
49-
config.resolve.alias = {
50-
...config.resolve.alias,
51-
'@/components': path.resolve(__dirname, '../src/components'),
52-
'@/lib/utils': path.resolve(__dirname, '../src/utils'),
53-
'@/lib/utils/*': path.resolve(__dirname, '../src/utils/*'),
54-
'@/styles': path.resolve(__dirname, '../src/styles'),
55-
'@/payload-types': path.resolve(__dirname, '../src/payload-types'),
56-
}
57-
// Remove any existing rule handling SVG files
58-
config.module.rules = config.module.rules.filter(
59-
(rule) => !rule.test || !rule.test.test('.svg'),
60-
)
61-
// Add SVG support
62-
config.module.rules.push({
63-
test: /\.svg$/,
64-
use: ['@svgr/webpack'],
65-
})
66-
// add image support
67-
// config.module?.rules?.push({
68-
// test: /\.(png|jpe?g|gif|svg)$/i,
69-
// type: 'asset/resource',
70-
// generator: {
71-
// filename: 'static/media/[name].[hash][ext]',
72-
// },
73-
// })
74-
return config
75-
}, // No need for webpackFinal if you're using the addon-styling-webpack
48+
// webpackFinal: async (config) => {
49+
// config.resolve.alias.push({
50+
// '@/components': path.resolve(__dirname, '../src/components'),
51+
// '@/lib/utils': path.resolve(__dirname, '../src/utils'),
52+
// '@/lib/utils/*': path.resolve(__dirname, '../src/utils/*'),
53+
// '@/styles': path.resolve(__dirname, '../src/styles'),
54+
// '@/payload-types': path.resolve(__dirname, '../src/payload-types'),
55+
// })
56+
// // Remove any existing rule handling SVG files
57+
// config.module.rules = config.module.rules.filter(
58+
// (rule) => !rule.test || !rule.test.test('.svg'),
59+
// )
60+
// // Add SVG support
61+
// config.module.rules.push({
62+
// test: /\.svg$/,
63+
// use: ['@svgr/webpack'],
64+
// })
65+
// // add image support
66+
// // config.module?.rules?.push({
67+
// // test: /\.(png|jpe?g|gif|svg)$/i,
68+
// // type: 'asset/resource',
69+
// // generator: {
70+
// // filename: 'static/media/[name].[hash][ext]',
71+
// // },
72+
// // })
73+
// return config
74+
// }, // No need for webpackFinal if you're using the addon-styling-webpack
7675
}
7776
export default config

src/components/HeaderFooter/HeaderDesktop.tsx

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,32 @@ import { Container } from '@/components/Other/Container'
55
import { BrandLogo } from './BrandLogo'
66
import logoLight from '../../images/cortex-reply-light.png'
77
import logoDark from '../../images/cortex-reply-dark.png'
8+
import { Moon, Sun } from 'lucide-react'
89

910
interface HeaderProps {
1011
isMenuOpen: boolean
1112
setIsMenuOpen?: (isOpen: boolean) => void
1213
}
1314

1415
export function HeaderDesktop({ isMenuOpen, setIsMenuOpen }: HeaderProps) {
15-
const [isScrolled, setIsScrolled] = useState(false)
16+
const [isScrolled , setIsScrolled] = useState(false)
17+
const [currentTheme, setCurrentTheme] = useState('light')
18+
const themes = ['light', 'dark']
19+
20+
useEffect(() => {
21+
// Load theme from local storage or set to default 'light'
22+
const storedTheme = localStorage.getItem('theme') || 'light'
23+
console.log('storedTheme', storedTheme)
24+
setCurrentTheme(storedTheme)
25+
document.documentElement.setAttribute('class', storedTheme)
26+
}, [])
27+
28+
const toggleTheme = () => {
29+
const nextTheme = themes[(themes.indexOf(currentTheme) + 1) % themes.length]
30+
setCurrentTheme(nextTheme)
31+
document.documentElement.setAttribute('class', nextTheme)
32+
localStorage.setItem('theme', nextTheme) // Save theme to local storage
33+
}
1634

1735
useEffect(() => {
1836
const handleScroll = () => {
@@ -42,46 +60,59 @@ export function HeaderDesktop({ isMenuOpen, setIsMenuOpen }: HeaderProps) {
4260
>
4361
<Container>
4462
<nav className="backdrop-blur-sm text-white p-0 rounded-b-xl">
45-
<div className="flex items-center justify-between bg-primary px-9 py-0 dark:bg-[#212124] [&_.logo-light]:[filter:brightness(0)_invert(1)] rounded-b-xl">
63+
<div className="flex items-center justify-between bg-accent px-9 py-0 dark:bg-[#212124] [&_.logo-light]:[filter:brightness(0)_invert(1)] rounded-b-xl dark:border dark:border-accent">
4664
<BrandLogo logoDark={logoDark} logoLight={logoLight}/>
4765
<ul className="flex items-center justify-center flex-grow space-x-8 text-md">
4866
<li>
4967
<a href="/services" className="relative transition-colors group">
5068
Services
51-
<span className="absolute -bottom-1 left-1/2 w-1/2 h-0.5 bg-white dark:bg-primary transform -translate-x-1/2 scale-x-0 transition-transform duration-300 ease-in-out group-hover:scale-x-100"></span>
69+
<span className="absolute -bottom-1 left-1/2 w-1/2 h-0.5 bg-white dark:bg-accent transform -translate-x-1/2 scale-x-0 transition-transform duration-300 ease-in-out group-hover:scale-x-100"></span>
5270
</a>
5371
</li>
5472
<li>
5573
<a href="/insights" className="relative transition-colors group">
5674
Insights
57-
<span className="absolute -bottom-1 left-1/2 w-1/2 h-0.5 bg-white dark:bg-primary transform -translate-x-1/2 scale-x-0 transition-transform duration-300 ease-in-out group-hover:scale-x-100"></span>
75+
<span className="absolute -bottom-1 left-1/2 w-1/2 h-0.5 bg-white dark:bg-accent transform -translate-x-1/2 scale-x-0 transition-transform duration-300 ease-in-out group-hover:scale-x-100"></span>
5876
</a>
5977
</li>
6078
<li>
6179
<a href="/about" className="relative transition-colors group">
6280
About Us
63-
<span className="absolute -bottom-1 left-1/2 w-1/2 h-0.5 bg-white dark:bg-primary transform -translate-x-1/2 scale-x-0 transition-transform duration-300 ease-in-out group-hover:scale-x-100"></span>
81+
<span className="absolute -bottom-1 left-1/2 w-1/2 h-0.5 bg-white dark:bg-accent transform -translate-x-1/2 scale-x-0 transition-transform duration-300 ease-in-out group-hover:scale-x-100"></span>
6482
</a>
6583
</li>
6684
<li>
6785
<a href="/contact" className="relative transition-colors group">
6886
Contact
69-
<span className="absolute -bottom-1 left-1/2 w-1/2 h-0.5 bg-white dark:bg-primary transform -translate-x-1/2 scale-x-0 transition-transform duration-300 ease-in-out group-hover:scale-x-100"></span>
87+
<span className="absolute -bottom-1 left-1/2 w-1/2 h-0.5 bg-white dark:bg-accent transform -translate-x-1/2 scale-x-0 transition-transform duration-300 ease-in-out group-hover:scale-x-100"></span>
7088
</a>
7189
</li>
7290
</ul>
91+
<div className='flex items-center space-x-4'>
92+
<button
93+
className="fixed right-16 z-[60] p-2 rounded-full bg-white/10 backdrop-blur-sm transition-all duration-300 hover:bg-white/20 text-white dark:hover:text-accent"
94+
onClick={toggleTheme}
95+
>
96+
<div className="relative">
97+
98+
<Sun className="absolute h-6 w-6 rotate-0 scale-100 transition-transform dark:-rotate-90 dark:scale-0" />
99+
<Moon className="absoulte h-6 w-6 rotate-0 scale-0 transition-transform dark:rotate-0 dark:scale-100" />
100+
{/* <X className="w-6 h-6 text-white" /> */}
101+
</div>
102+
</button>
73103
{!isScrolled && setIsMenuOpen && (
74104
<button
75-
className="fixed right-4 z-[60] p-2 rounded-full bg-white/10 backdrop-blur-sm transition-all duration-300 hover:bg-white/20"
105+
className="fixed right-4 z-[60] p-2 rounded-full bg-white/10 backdrop-blur-sm transition-all duration-300 hover:bg-white/20 text-white dark:hover:text-accent"
76106
onClick={toggleMenu}
77107
>
78108
{isMenuOpen ? (
79-
<X className="w-6 h-6 text-white" />
109+
<X className="w-6 h-6" />
80110
) : (
81-
<Menu className="w-6 h-6 text-white" />
111+
<Menu className="w-6 h-6 " />
82112
)}
83113
</button>
84114
)}
115+
</div>
85116
</div>
86117
</nav>
87118
</Container>

src/components/HeaderFooter/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ export * from './SimpleHeader'
33
export * from "./HeaderMenu"
44
export * from "./HeaderMenuItem"
55
export * from "./VideoHeader"
6+
export * from "./HeaderDesktop"
67

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import type { Meta, StoryFn } from '@storybook/react'
2+
import { AnimatedBorder } from './AnimatedBorder'
3+
import * as React from 'react'
4+
5+
const meta: Meta<typeof AnimatedBorder> = {
6+
title: 'Animation/AnimatedBorder',
7+
component: AnimatedBorder,
8+
tags: ['autodocs'],
9+
argTypes: {
10+
color: { control: 'color' },
11+
duration: { control: { type: 'range', min: 1, max: 10, step: 0.5 } },
12+
strokeWidth: { control: { type: 'range', min: 1, max: 10, step: 1 } },
13+
},
14+
decorators: [
15+
(Story) => (
16+
<div style={{ padding: '3rem' }}>
17+
<Story />
18+
</div>
19+
),
20+
],
21+
}
22+
23+
export default meta
24+
25+
const Template: StoryFn<typeof AnimatedBorder> = (args) => <AnimatedBorder {...args} />;
26+
27+
export const Default = Template.bind({});
28+
Default.args = {
29+
children: <div className="p-4 bg-white">Animated border on visibility</div>,
30+
};
31+
32+
export const RoundedBottom = Template.bind({});
33+
RoundedBottom.args = {
34+
children: <div className="p-4 rounded-b-xl bg-primary text-primary-foreground">Animated border on visibility</div>,
35+
borderRadius: '8',
36+
color: '#10B981', // Green color
37+
};
38+
39+
40+
41+
42+
export const CustomColor = Template.bind({});
43+
CustomColor.args = {
44+
children: <div className="p-4 bg-primary text-primary-foreground rounded-xl">Custom color border</div>,
45+
borderRadius: '8',
46+
color: '#10B981', // Green color
47+
topEdgeIncluded: false,
48+
};
49+
50+
export const SlowAnimation = Template.bind({});
51+
SlowAnimation.args = {
52+
children: <div className="p-4 bg-white">Slow animation</div>,
53+
duration: 5,
54+
};
55+
56+
export const ThickBorder = Template.bind({});
57+
ThickBorder.args = {
58+
children: <div className="p-4 bg-white">Thick border</div>,
59+
strokeWidth: 4,
60+
};
61+
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
'use client'
2+
3+
import React, { useEffect, useRef, useState } from 'react'
4+
import { motion, useAnimation } from 'framer-motion'
5+
6+
interface AnimatedBorderProps {
7+
children: React.ReactNode
8+
color?: string
9+
duration?: number
10+
strokeWidth?: number
11+
borderRadius?: number // Border radius as a number (e.g., 8 for `rounded-lg`)
12+
}
13+
14+
export const AnimatedBorder: React.FC<AnimatedBorderProps> = ({
15+
children,
16+
color = 'hsl(var(--primary))',
17+
duration = 2,
18+
strokeWidth = 2,
19+
borderRadius = 8, // Default to `rounded-lg` equivalent
20+
}) => {
21+
const containerRef = useRef<HTMLDivElement>(null)
22+
const [dimensions, setDimensions] = useState({ width: 0, height: 0 })
23+
const controls = useAnimation()
24+
25+
useEffect(() => {
26+
if (containerRef.current) {
27+
const resizeObserver = new ResizeObserver((entries) => {
28+
for (let entry of entries) {
29+
setDimensions({
30+
width: entry.contentRect.width,
31+
height: entry.contentRect.height,
32+
})
33+
}
34+
})
35+
36+
resizeObserver.observe(containerRef.current)
37+
38+
return () => {
39+
resizeObserver.disconnect()
40+
}
41+
}
42+
}, [])
43+
44+
useEffect(() => {
45+
controls.start({
46+
pathLength: [0, 1],
47+
transition: { duration, ease: 'easeInOut' },
48+
})
49+
}, [controls, duration])
50+
51+
return (
52+
<div
53+
ref={containerRef}
54+
className="relative inline-block"
55+
style={{ borderRadius }}
56+
>
57+
{children}
58+
<svg
59+
className="absolute inset-0 w-full h-full pointer-events-none"
60+
xmlns="http://www.w3.org/2000/svg"
61+
width={dimensions.width}
62+
height={dimensions.height}
63+
>
64+
<motion.rect
65+
x={strokeWidth / 2}
66+
y={strokeWidth / 2}
67+
width={dimensions.width - strokeWidth}
68+
height={dimensions.height - strokeWidth}
69+
rx={borderRadius} // Apply consistent rounding
70+
ry={borderRadius}
71+
fill="none"
72+
stroke={color}
73+
strokeWidth={strokeWidth}
74+
initial={{ pathLength: 0 }}
75+
animate={controls}
76+
/>
77+
</svg>
78+
</div>
79+
)
80+
}

src/components/Pages/Page.stories.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ export const HighImpactHero = {
345345
...Default.args,
346346
hero: {
347347
type: 'highImpact',
348-
children: <h1 className="text-4xl font-bold">Low Impact Hero</h1>,
348+
children: <h1 className="text-4xl font-bold">High Impact Hero</h1>,
349349
},
350350
heroBackgroundImage: 'stock1.jpg?height=400&width=800',
351351
},

0 commit comments

Comments
 (0)