Compare commits
18
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f394bacf1 | ||
|
|
d4bd7f4e1a | ||
|
|
1b6b442078 | ||
|
|
f9191708f4 | ||
|
|
10da7d0a16 | ||
|
|
c07c75f23b | ||
|
|
e9622234fe | ||
|
|
aedc2b5dfb | ||
|
|
5b1b700ccb | ||
|
|
0478d12ffc | ||
|
|
5929c5a667 | ||
|
|
206a426120 | ||
|
|
b4708ab2aa | ||
|
|
53b069f242 | ||
|
|
c2a50a86bd | ||
|
|
edec847eee | ||
|
|
9182440ab3 | ||
|
|
259262a1ef |
@@ -1,12 +0,0 @@
|
||||
import playwright from 'eslint-plugin-playwright';
|
||||
import baseConfig from '../../eslint.config.mjs';
|
||||
|
||||
export default [
|
||||
playwright.configs['flat/recommended'],
|
||||
...baseConfig,
|
||||
{
|
||||
files: ['**/*.ts', '**/*.js'],
|
||||
// Override or add rules here
|
||||
rules: {},
|
||||
},
|
||||
];
|
||||
@@ -1,68 +0,0 @@
|
||||
import { defineConfig, devices } from '@playwright/test';
|
||||
import { nxE2EPreset } from '@nx/playwright/preset';
|
||||
import { workspaceRoot } from '@nx/devkit';
|
||||
|
||||
// For CI, you may want to set BASE_URL to the deployed application.
|
||||
const baseURL = process.env['BASE_URL'] || 'http://localhost:3000';
|
||||
|
||||
/**
|
||||
* Read environment variables from file.
|
||||
* https://github.com/motdotla/dotenv
|
||||
*/
|
||||
// require('dotenv').config();
|
||||
|
||||
/**
|
||||
* See https://playwright.dev/docs/test-configuration.
|
||||
*/
|
||||
export default defineConfig({
|
||||
...nxE2EPreset(__filename, { testDir: './src' }),
|
||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||
use: {
|
||||
baseURL,
|
||||
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||
trace: 'on-first-retry',
|
||||
},
|
||||
/* Run your local dev server before starting the tests */
|
||||
webServer: {
|
||||
command: 'npx nx run landing:start',
|
||||
url: 'http://localhost:3000',
|
||||
reuseExistingServer: !process.env.CI,
|
||||
cwd: workspaceRoot,
|
||||
},
|
||||
projects: [
|
||||
{
|
||||
name: 'chromium',
|
||||
use: { ...devices['Desktop Chrome'] },
|
||||
},
|
||||
|
||||
{
|
||||
name: 'firefox',
|
||||
use: { ...devices['Desktop Firefox'] },
|
||||
},
|
||||
|
||||
{
|
||||
name: 'webkit',
|
||||
use: { ...devices['Desktop Safari'] },
|
||||
},
|
||||
|
||||
// Uncomment for mobile browsers support
|
||||
/* {
|
||||
name: 'Mobile Chrome',
|
||||
use: { ...devices['Pixel 5'] },
|
||||
},
|
||||
{
|
||||
name: 'Mobile Safari',
|
||||
use: { ...devices['iPhone 12'] },
|
||||
}, */
|
||||
|
||||
// Uncomment for branded browsers
|
||||
/* {
|
||||
name: 'Microsoft Edge',
|
||||
use: { ...devices['Desktop Edge'], channel: 'msedge' },
|
||||
},
|
||||
{
|
||||
name: 'Google Chrome',
|
||||
use: { ...devices['Desktop Chrome'], channel: 'chrome' },
|
||||
} */
|
||||
],
|
||||
});
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"name": "landing-e2e",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"projectType": "application",
|
||||
"sourceRoot": "apps/landing-e2e/src",
|
||||
"tags": [],
|
||||
"implicitDependencies": ["landing"],
|
||||
"// targets": "to see all targets run: nx show project landing-e2e --web",
|
||||
"targets": {}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test('has title', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
// Expect h1 to contain a substring.
|
||||
expect(await page.locator('h1').innerText()).toContain('Welcome');
|
||||
});
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"sourceMap": false,
|
||||
"module": "commonjs"
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts",
|
||||
"**/*.js",
|
||||
"playwright.config.ts",
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.spec.js",
|
||||
"src/**/*.test.ts",
|
||||
"src/**/*.test.js",
|
||||
"src/**/*.d.ts"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
const config = {
|
||||
plugins: {
|
||||
'@tailwindcss/postcss': {},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -5,5 +5,20 @@
|
||||
"projectType": "application",
|
||||
"tags": [],
|
||||
"// targets": "to see all targets run: nx show project landing --web",
|
||||
"targets": {}
|
||||
"targets": {
|
||||
"serve": {
|
||||
"executor": "@nx/next:server",
|
||||
"options": {
|
||||
"buildTarget": "landing:build",
|
||||
"dev": true
|
||||
}
|
||||
},
|
||||
"build": {
|
||||
"executor": "@nx/next:build",
|
||||
"outputs": ["{options.outputPath}"],
|
||||
"options": {
|
||||
"outputPath": "dist/apps/landing"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 87 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 159 KiB |
@@ -0,0 +1,66 @@
|
||||
'use client';
|
||||
|
||||
import { Button } from '@imphnen-frontend-service/shadcn-ui/atoms';
|
||||
import { motion, useInView } from 'framer-motion';
|
||||
import { useRef } from 'react';
|
||||
|
||||
export function CallToAction() {
|
||||
const ref = useRef(null);
|
||||
const isInView = useInView(ref, { once: true, amount: 0.2 });
|
||||
|
||||
return (
|
||||
<section className="w-full py-20 md:py-32 relative overflow-hidden">
|
||||
{/* Background Elements */}
|
||||
<div className="absolute inset-0 -z-10">
|
||||
<div className="absolute inset-0 bg-gradient-to-b from-background to-primary/20" />
|
||||
<div className="absolute inset-0 bg-[radial-gradient(circle_at_center,rgba(59,130,246,0.2),transparent_70%)]" />
|
||||
</div>
|
||||
|
||||
<div className="container px-4 md:px-6" ref={ref}>
|
||||
<motion.div
|
||||
className="max-w-4xl mx-auto rounded-2xl overflow-hidden border shadow-lg"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
>
|
||||
<div className="relative p-8 md:p-12 lg:p-16 bg-background">
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-primary/5 via-transparent to-blue-400/5" />
|
||||
|
||||
<div className="relative z-10 text-center">
|
||||
<h2 className="text-3xl md:text-4xl lg:text-5xl font-bold mb-6">
|
||||
Siap Menjadi{' '}
|
||||
<span className="bg-clip-text text-transparent bg-gradient-to-r from-primary to-blue-400">
|
||||
Programmer Handal?
|
||||
</span>
|
||||
</h2>
|
||||
<p className="text-lg text-muted-foreground mb-8 max-w-2xl mx-auto">
|
||||
Bergabunglah dengan komunitas IMPHNEN sekarang dan mulai
|
||||
perjalanan programming mu dengan cara yang menyenangkan!
|
||||
</p>
|
||||
|
||||
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
||||
<Button
|
||||
size="lg"
|
||||
className="bg-gradient-to-r from-primary to-blue-400 hover:from-primary/90 hover:to-blue-400/90"
|
||||
>
|
||||
Gabung Discord
|
||||
</Button>
|
||||
<Button
|
||||
size="lg"
|
||||
variant="outline"
|
||||
className="border-primary hover:bg-primary/10"
|
||||
>
|
||||
Join Facebook Group
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Decorative Elements */}
|
||||
<div className="absolute -top-12 -left-12 w-24 h-24 rounded-full bg-primary/10 blur-2xl" />
|
||||
<div className="absolute -bottom-12 -right-12 w-24 h-24 rounded-full bg-blue-400/10 blur-2xl" />
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
'use client';
|
||||
|
||||
import {
|
||||
Button,
|
||||
FacebookIcon,
|
||||
InstagramIcon,
|
||||
MessageCircleIcon,
|
||||
} from '@imphnen-frontend-service/shadcn-ui/atoms';
|
||||
import { motion, useInView } from 'framer-motion';
|
||||
import { useRef } from 'react';
|
||||
|
||||
export function Community() {
|
||||
const ref = useRef(null);
|
||||
const isInView = useInView(ref, { once: true, amount: 0.2 });
|
||||
|
||||
const communities = [
|
||||
{
|
||||
icon: (
|
||||
<FacebookIcon className="h-6 w-6 text-blue-600 dark:text-blue-400" />
|
||||
),
|
||||
iconBg: 'bg-blue-100 dark:bg-blue-900',
|
||||
title: 'Facebook Group',
|
||||
description:
|
||||
'Bergabunglah dengan grup Facebook kami untuk diskusi santai dan berbagi artikel menarik.',
|
||||
buttonText: 'Gabung Sekarang',
|
||||
buttonLink: '#',
|
||||
},
|
||||
{
|
||||
icon: (
|
||||
<InstagramIcon className="h-6 w-6 text-blue-600 dark:text-blue-400" />
|
||||
),
|
||||
iconBg: 'bg-blue-100 dark:bg-blue-900',
|
||||
title: 'Instagram',
|
||||
description:
|
||||
'Ikuti kami di Instagram untuk tips programming, konten inspiratif, dan info event terbaru.',
|
||||
buttonText: 'Follow Kami',
|
||||
buttonLink: '#',
|
||||
},
|
||||
{
|
||||
icon: (
|
||||
<MessageCircleIcon className="h-6 w-6 text-blue-600 dark:text-blue-400" />
|
||||
),
|
||||
iconBg: 'bg-blue-100 dark:bg-blue-900',
|
||||
title: 'Discord Server',
|
||||
description:
|
||||
'Diskusikan langsung dengan sesama programmer dan dapatkan bantuan langsung dari para ahli.',
|
||||
buttonText: 'Join Server',
|
||||
buttonLink: '#',
|
||||
},
|
||||
];
|
||||
|
||||
const containerVariants = {
|
||||
hidden: { opacity: 0 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
transition: {
|
||||
staggerChildren: 0.1,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const itemVariants = {
|
||||
hidden: { y: 20, opacity: 0 },
|
||||
visible: {
|
||||
y: 0,
|
||||
opacity: 1,
|
||||
transition: { duration: 0.5 },
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<section
|
||||
id="komunitas"
|
||||
className="w-full py-20 md:py-32 bg-muted relative overflow-hidden"
|
||||
>
|
||||
{/* Background Elements */}
|
||||
<div className="absolute inset-0 -z-10">
|
||||
<div className="absolute inset-0 bg-[radial-gradient(circle_at_center,rgba(59,130,246,0.1),transparent_70%)]" />
|
||||
<div className="absolute inset-0 bg-[linear-gradient(to_right,rgba(59,130,246,0.01)_1px,transparent_1px),linear-gradient(to_bottom,rgba(59,130,246,0.01)_1px,transparent_1px)] bg-[size:14px_14px]" />
|
||||
</div>
|
||||
|
||||
<div className="container px-4 md:px-6" ref={ref}>
|
||||
<div className="flex flex-col items-center justify-center space-y-4 text-center mb-16">
|
||||
<motion.div
|
||||
className="space-y-2"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
>
|
||||
<h2 className="text-3xl font-bold tracking-tighter md:text-4xl/tight lg:text-5xl">
|
||||
Komunitas{' '}
|
||||
<span className="bg-clip-text text-transparent bg-gradient-to-r from-primary to-blue-400">
|
||||
Kami
|
||||
</span>
|
||||
</h2>
|
||||
<p className="max-w-[800px] mx-auto text-muted-foreground md:text-lg">
|
||||
Bergabunglah dengan ribuan programmer Indonesia yang saling
|
||||
membantu dan berbagi pengalaman.
|
||||
</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div
|
||||
className="grid gap-8 md:grid-cols-3"
|
||||
variants={containerVariants}
|
||||
initial="hidden"
|
||||
animate={isInView ? 'visible' : 'hidden'}
|
||||
>
|
||||
{communities.map((community, index) => (
|
||||
<motion.div
|
||||
key={index}
|
||||
className="group relative overflow-hidden rounded-xl border bg-background p-6 transition-all hover:shadow-xl"
|
||||
variants={itemVariants}
|
||||
>
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-primary/5 via-transparent to-blue-400/5 opacity-0 group-hover:opacity-100 transition-opacity duration-500" />
|
||||
|
||||
<div className="relative z-10">
|
||||
<div
|
||||
className={`mb-4 inline-flex h-12 w-12 items-center justify-center rounded-full ${community.iconBg}`}
|
||||
>
|
||||
{community.icon}
|
||||
</div>
|
||||
<h3 className="mb-2 text-xl font-bold">{community.title}</h3>
|
||||
<p className="mb-6 text-muted-foreground">
|
||||
{community.description}
|
||||
</p>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="w-full group-hover:bg-primary group-hover:text-primary-foreground transition-colors duration-300"
|
||||
>
|
||||
{community.buttonText}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="absolute -bottom-1 -right-1 w-20 h-20 bg-gradient-to-tl from-primary/20 to-transparent rounded-tl-full opacity-0 group-hover:opacity-100 transition-opacity duration-500" />
|
||||
</motion.div>
|
||||
))}
|
||||
</motion.div>
|
||||
|
||||
{/* Community Stats */}
|
||||
<motion.div
|
||||
className="mt-20 grid grid-cols-2 md:grid-cols-4 gap-8 text-center"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
|
||||
transition={{ duration: 0.5, delay: 0.3 }}
|
||||
>
|
||||
<div className="space-y-2">
|
||||
<div className="text-4xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-primary to-blue-400">
|
||||
10K+
|
||||
</div>
|
||||
<div className="text-sm text-muted-foreground">Member Aktif</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<div className="text-4xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-primary to-blue-400">
|
||||
50+
|
||||
</div>
|
||||
<div className="text-sm text-muted-foreground">Event Bulanan</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<div className="text-4xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-primary to-blue-400">
|
||||
100+
|
||||
</div>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
Mentor Profesional
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<div className="text-4xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-primary to-blue-400">
|
||||
5K+
|
||||
</div>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
Diskusi Mingguan
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
'use client';
|
||||
|
||||
import {
|
||||
BookOpenIcon,
|
||||
CodeIcon,
|
||||
LaptopIcon,
|
||||
UsersIcon,
|
||||
} from '@imphnen-frontend-service/shadcn-ui/atoms';
|
||||
import { motion, useInView } from 'framer-motion';
|
||||
import { useRef } from 'react';
|
||||
|
||||
export function Features() {
|
||||
const ref = useRef(null);
|
||||
const isInView = useInView(ref, { once: true, amount: 0.2 });
|
||||
|
||||
const features = [
|
||||
{
|
||||
icon: <LaptopIcon className="h-6 w-6 text-primary" />,
|
||||
title: 'Belajar Tanpa Koding',
|
||||
description:
|
||||
'Pelajari konsep programming dengan cara yang mudah dipahami tanpa harus menulis kode yang rumit.',
|
||||
},
|
||||
{
|
||||
icon: <UsersIcon className="h-6 w-6 text-primary" />,
|
||||
title: 'Komunitas Supportif',
|
||||
description:
|
||||
'Bergabunglah dengan komunitas programmer Indonesia yang siap membantu dan berbagi pengalaman.',
|
||||
},
|
||||
{
|
||||
icon: <BookOpenIcon className="h-6 w-6 text-primary" />,
|
||||
title: 'Tutorial Interaktif',
|
||||
description:
|
||||
'Akses tutorial interaktif yang membuat konsep programming lebih mudah untuk dipahami.',
|
||||
},
|
||||
{
|
||||
icon: <CodeIcon className="h-6 w-6 text-primary" />,
|
||||
title: 'Proyek Praktis',
|
||||
description:
|
||||
'Terapkan pengetahuan Anda dalam proyek nyata dengan panduan langkah demi langkah.',
|
||||
},
|
||||
];
|
||||
|
||||
const containerVariants = {
|
||||
hidden: { opacity: 0 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
transition: {
|
||||
staggerChildren: 0.1,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const itemVariants = {
|
||||
hidden: { y: 20, opacity: 0 },
|
||||
visible: {
|
||||
y: 0,
|
||||
opacity: 1,
|
||||
transition: { duration: 0.5 },
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<section
|
||||
id="fitur"
|
||||
className="w-full py-20 md:py-32 relative overflow-hidden"
|
||||
>
|
||||
{/* Background Elements */}
|
||||
<div className="absolute inset-0 -z-10">
|
||||
<div className="absolute inset-0 bg-gradient-to-b from-background via-background to-muted/50" />
|
||||
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[800px] h-[800px] rounded-full bg-gradient-to-tr from-primary/5 to-blue-400/5 blur-3xl" />
|
||||
</div>
|
||||
|
||||
<div className="container px-4 md:px-6" ref={ref}>
|
||||
<div className="flex flex-col items-center justify-center space-y-4 text-center mb-16">
|
||||
<motion.div
|
||||
className="space-y-2"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
>
|
||||
<div className="inline-block rounded-full bg-primary/10 px-4 py-1.5 text-sm font-medium text-primary">
|
||||
Fitur Unggulan
|
||||
</div>
|
||||
<h2 className="text-3xl font-bold tracking-tighter md:text-4xl/tight lg:text-5xl">
|
||||
Belajar programming dengan{' '}
|
||||
<span className="bg-clip-text text-transparent bg-gradient-to-r from-primary to-blue-400">
|
||||
cara yang lebih baik
|
||||
</span>
|
||||
</h2>
|
||||
<p className="max-w-[800px] mx-auto text-muted-foreground md:text-lg">
|
||||
IMPHNEN hadir dengan berbagai fitur untuk membantu kamu menjadi
|
||||
programmer handal tanpa harus pusing dengan coding.
|
||||
</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div
|
||||
className="grid gap-8 md:grid-cols-2 lg:grid-cols-4"
|
||||
variants={containerVariants}
|
||||
initial="hidden"
|
||||
animate={isInView ? 'visible' : 'hidden'}
|
||||
>
|
||||
{features.map((feature, index) => (
|
||||
<motion.div
|
||||
key={index}
|
||||
className="group relative overflow-hidden rounded-xl border bg-background/50 backdrop-blur-sm p-6 transition-all hover:shadow-md hover:shadow-primary/5 hover:border-primary/50"
|
||||
variants={itemVariants}
|
||||
>
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-primary/5 via-transparent to-blue-400/5 opacity-0 group-hover:opacity-100 transition-opacity duration-500" />
|
||||
|
||||
<div className="relative z-10">
|
||||
<div className="mb-4 inline-flex h-12 w-12 items-center justify-center rounded-full bg-primary/10 group-hover:bg-primary/20 transition-colors">
|
||||
{feature.icon}
|
||||
</div>
|
||||
<h3 className="mb-2 text-xl font-bold">{feature.title}</h3>
|
||||
<p className="text-muted-foreground">{feature.description}</p>
|
||||
</div>
|
||||
|
||||
<div className="absolute bottom-0 left-0 h-1 w-0 bg-gradient-to-r from-primary to-blue-400 group-hover:w-full transition-all duration-300" />
|
||||
</motion.div>
|
||||
))}
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,145 @@
|
||||
'use client';
|
||||
|
||||
import {
|
||||
Button,
|
||||
MenuIcon,
|
||||
XIcon,
|
||||
} from '@imphnen-frontend-service/shadcn-ui/atoms';
|
||||
import { cn } from '@imphnen-frontend-service/utils';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { SimpleThemeToggle } from './simple-theme-toggle';
|
||||
|
||||
export function Header() {
|
||||
const [isScrolled, setIsScrolled] = useState(false);
|
||||
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const handleScroll = () => {
|
||||
setIsScrolled(window.scrollY > 10);
|
||||
};
|
||||
window.addEventListener('scroll', handleScroll);
|
||||
return () => window.removeEventListener('scroll', handleScroll);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<header
|
||||
className={cn(
|
||||
'sticky top-0 z-50 w-full transition-all duration-300',
|
||||
isScrolled
|
||||
? 'bg-background/80 backdrop-blur-md border-b shadow-sm'
|
||||
: 'bg-transparent'
|
||||
)}
|
||||
>
|
||||
<div className="container flex h-16 items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="relative overflow-hidden rounded">
|
||||
<Image
|
||||
src="/logo.png"
|
||||
alt="IMPHNEN Logo"
|
||||
width={64}
|
||||
height={64}
|
||||
className="object-cover"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Desktop Navigation */}
|
||||
<nav className="hidden md:flex items-center gap-8">
|
||||
<Link href="#fitur" className="text-sm font-medium relative group">
|
||||
<span className="transition-colors hover:text-primary">Fitur</span>
|
||||
<span className="absolute -bottom-1 left-0 w-0 h-0.5 bg-primary transition-all duration-300 group-hover:w-full"></span>
|
||||
</Link>
|
||||
<Link
|
||||
href="#komunitas"
|
||||
className="text-sm font-medium relative group"
|
||||
>
|
||||
<span className="transition-colors hover:text-primary">
|
||||
Komunitas
|
||||
</span>
|
||||
<span className="absolute -bottom-1 left-0 w-0 h-0.5 bg-primary transition-all duration-300 group-hover:w-full"></span>
|
||||
</Link>
|
||||
<Link
|
||||
href="#sumber-belajar"
|
||||
className="text-sm font-medium relative group"
|
||||
>
|
||||
<span className="transition-colors hover:text-primary">
|
||||
Sumber Belajar
|
||||
</span>
|
||||
<span className="absolute -bottom-1 left-0 w-0 h-0.5 bg-primary transition-all duration-300 group-hover:w-full"></span>
|
||||
</Link>
|
||||
<Link
|
||||
href="#testimoni"
|
||||
className="text-sm font-medium relative group"
|
||||
>
|
||||
<span className="transition-colors hover:text-primary">
|
||||
Testimoni
|
||||
</span>
|
||||
<span className="absolute -bottom-1 left-0 w-0 h-0.5 bg-primary transition-all duration-300 group-hover:w-full"></span>
|
||||
</Link>
|
||||
</nav>
|
||||
|
||||
<div className="flex items-center gap-4">
|
||||
<SimpleThemeToggle />
|
||||
<Button className="hidden md:flex bg-gradient-to-r from-primary to-blue-400 hover:from-primary/90 hover:to-blue-400/90 transition-all duration-300">
|
||||
Gabung Discord
|
||||
</Button>
|
||||
|
||||
{/* Mobile Menu Button */}
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="md:hidden"
|
||||
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
|
||||
>
|
||||
{mobileMenuOpen ? (
|
||||
<XIcon className="h-6 w-6" />
|
||||
) : (
|
||||
<MenuIcon className="h-6 w-6" />
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Mobile Menu */}
|
||||
{mobileMenuOpen && (
|
||||
<div className="md:hidden border-t bg-background/95 backdrop-blur-md">
|
||||
<nav className="container flex flex-col py-4 text-center">
|
||||
<Link
|
||||
href="#fitur"
|
||||
className="py-3 text-sm font-medium border-b border-border/50"
|
||||
onClick={() => setMobileMenuOpen(false)}
|
||||
>
|
||||
Fitur
|
||||
</Link>
|
||||
<Link
|
||||
href="#komunitas"
|
||||
className="py-3 text-sm font-medium border-b border-border/50"
|
||||
onClick={() => setMobileMenuOpen(false)}
|
||||
>
|
||||
Komunitas
|
||||
</Link>
|
||||
<Link
|
||||
href="#sumber-belajar"
|
||||
className="py-3 text-sm font-medium border-b border-border/50"
|
||||
onClick={() => setMobileMenuOpen(false)}
|
||||
>
|
||||
Sumber Belajar
|
||||
</Link>
|
||||
<Link
|
||||
href="#testimoni"
|
||||
className="py-3 text-sm font-medium"
|
||||
onClick={() => setMobileMenuOpen(false)}
|
||||
>
|
||||
Testimoni
|
||||
</Link>
|
||||
<Button className="mt-4 bg-gradient-to-r from-primary to-blue-400 hover:from-primary/90 hover:to-blue-400/90">
|
||||
Gabung Discord
|
||||
</Button>
|
||||
</nav>
|
||||
</div>
|
||||
)}
|
||||
</header>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
'use client';
|
||||
|
||||
import {
|
||||
Button,
|
||||
CodeIcon,
|
||||
SparklesIcon,
|
||||
UsersIcon,
|
||||
} from '@imphnen-frontend-service/shadcn-ui/atoms';
|
||||
import { motion } from 'framer-motion';
|
||||
import Image from 'next/image';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
export function Hero() {
|
||||
const [scrollY, setScrollY] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const handleScroll = () => {
|
||||
setScrollY(window.scrollY);
|
||||
};
|
||||
|
||||
window.addEventListener('scroll', handleScroll);
|
||||
return () => window.removeEventListener('scroll', handleScroll);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<section className="relative w-full py-20 md:py-32 lg:py-40 overflow-hidden">
|
||||
{/* Background Elements */}
|
||||
<div className="absolute inset-0 -z-10 overflow-hidden">
|
||||
<div className="absolute top-0 left-0 w-full h-full bg-gradient-to-b from-background to-background/50" />
|
||||
|
||||
{/* Animated Gradient Orbs */}
|
||||
<div
|
||||
className="absolute top-1/4 -left-20 w-80 h-80 rounded-full bg-gradient-to-r from-primary/20 to-blue-400/20 blur-3xl"
|
||||
style={{
|
||||
transform: `translate(${scrollY * 0.1}px, ${scrollY * -0.05}px)`,
|
||||
opacity: Math.max(0.2, 1 - scrollY * 0.001),
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
className="absolute bottom-1/3 -right-20 w-80 h-80 rounded-full bg-gradient-to-r from-blue-400/20 to-primary/20 blur-3xl"
|
||||
style={{
|
||||
transform: `translate(${scrollY * -0.1}px, ${scrollY * 0.05}px)`,
|
||||
opacity: Math.max(0.2, 1 - scrollY * 0.001),
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Grid Pattern */}
|
||||
<div className="absolute inset-0 bg-[linear-gradient(rgba(59,130,246,0.05)_1px,transparent_1px),linear-gradient(to_right,rgba(59,130,246,0.05)_1px,transparent_1px)] bg-[size:40px_40px]" />
|
||||
</div>
|
||||
|
||||
<div className="container px-4 md:px-6 relative">
|
||||
<div className="grid gap-6 lg:grid-cols-2 lg:gap-12 items-center">
|
||||
<motion.div
|
||||
className="flex flex-col justify-center space-y-8"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
>
|
||||
<div className="inline-flex items-center rounded-full border px-3 py-1 text-sm">
|
||||
<SparklesIcon className="mr-1 h-3.5 w-3.5 text-primary" />
|
||||
<span>Komunitas Programmer Indonesia</span>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<h1 className="text-4xl font-bold tracking-tighter sm:text-5xl md:text-6xl lg:text-7xl bg-clip-text text-transparent bg-gradient-to-r from-foreground via-foreground to-foreground/70">
|
||||
Programmer Handal, <br />
|
||||
<span className="bg-clip-text text-transparent bg-gradient-to-r from-primary to-blue-400">
|
||||
Tanpa Ribet
|
||||
</span>
|
||||
</h1>
|
||||
<p className="max-w-[600px] text-muted-foreground md:text-xl">
|
||||
Temukan potensi programming Anda bersama komunitas yang
|
||||
mendukung, tutorial interaktif, dan sumber daya berkualitas
|
||||
tinggi.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col sm:flex-row gap-4">
|
||||
<a href="https://facebook.com">
|
||||
<Button
|
||||
size="lg"
|
||||
className="bg-gradient-to-r from-primary to-blue-400 hover:from-primary/90 hover:to-blue-400/90 transition-all duration-300"
|
||||
>
|
||||
Mulai Belajar
|
||||
</Button>
|
||||
</a>
|
||||
<Button
|
||||
size="lg"
|
||||
variant="outline"
|
||||
className="group relative overflow-hidden border-primary"
|
||||
>
|
||||
<span className="absolute inset-0 bg-gradient-to-r from-primary/10 to-blue-400/10 translate-y-full group-hover:translate-y-0 transition-transform duration-300"></span>
|
||||
<span className="relative">Gabung Discord</span>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-8">
|
||||
<div className="flex flex-col items-center">
|
||||
<div className="text-2xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-primary to-blue-400">
|
||||
100K+
|
||||
</div>
|
||||
<div className="text-xs text-muted-foreground">Member</div>
|
||||
</div>
|
||||
<div className="h-10 border-r border-border"></div>
|
||||
<div className="flex flex-col items-center">
|
||||
<div className="text-2xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-primary to-blue-400">
|
||||
500+
|
||||
</div>
|
||||
<div className="text-xs text-muted-foreground">Tutorial</div>
|
||||
</div>
|
||||
<div className="h-10 border-r border-border"></div>
|
||||
<div className="flex flex-col items-center">
|
||||
<div className="text-2xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-primary to-blue-400">
|
||||
24/7
|
||||
</div>
|
||||
<div className="text-xs text-muted-foreground">Yapping</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
className="relative mx-auto lg:ml-auto"
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 0.5, delay: 0.2 }}
|
||||
>
|
||||
<div className="relative">
|
||||
{/* Decorative Elements */}
|
||||
<div className="absolute -top-6 -left-6 w-12 h-12 rounded-lg border border-primary/30 bg-background/50 backdrop-blur-sm flex items-center justify-center">
|
||||
<CodeIcon className="h-6 w-6 text-primary" />
|
||||
</div>
|
||||
<div className="absolute -bottom-6 -right-6 w-12 h-12 rounded-lg border border-blue-400/30 bg-background/50 backdrop-blur-sm flex items-center justify-center">
|
||||
<UsersIcon className="h-6 w-6 text-blue-400" />
|
||||
</div>
|
||||
|
||||
{/* Main Image */}
|
||||
<div className="relative z-10 rounded-2xl overflow-hidden border shadow-2xl">
|
||||
<div className="absolute inset-0 bg-gradient-to-tr from-primary/10 to-blue-400/10" />
|
||||
<Image
|
||||
src="/hero.jpeg"
|
||||
width={600}
|
||||
height={500}
|
||||
alt="IMPHNEN Programming Community"
|
||||
className="w-full h-auto object-cover"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
'use client';
|
||||
|
||||
import {
|
||||
BookOpenIcon,
|
||||
Button,
|
||||
CodeIcon,
|
||||
Share2Icon,
|
||||
VideoIcon,
|
||||
} from '@imphnen-frontend-service/shadcn-ui/atoms';
|
||||
import { motion, useInView } from 'framer-motion';
|
||||
|
||||
import { useRef } from 'react';
|
||||
|
||||
export function LearningResources() {
|
||||
const ref = useRef(null);
|
||||
const isInView = useInView(ref, { once: true, amount: 0.2 });
|
||||
|
||||
const resources = [
|
||||
{
|
||||
icon: <VideoIcon className="h-6 w-6 text-blue-600 dark:text-blue-400" />,
|
||||
iconBg: 'bg-blue-100 dark:bg-blue-900',
|
||||
title: 'Video Tutorial',
|
||||
description:
|
||||
'Belajar melalui tutorial video dari langkah awal hingga mahir.',
|
||||
buttonText: 'Lihat Semua Video',
|
||||
buttonLink: '#',
|
||||
color: 'from-blue-500 to-blue-700',
|
||||
},
|
||||
{
|
||||
icon: (
|
||||
<BookOpenIcon className="h-6 w-6 text-blue-600 dark:text-blue-400" />
|
||||
),
|
||||
iconBg: 'bg-blue-100 dark:bg-blue-900',
|
||||
title: 'Artikel & Tutorial',
|
||||
description:
|
||||
'Pelajari konsep programming melalui artikel yang disusun secara terstruktur.',
|
||||
buttonText: 'Baca Artikel',
|
||||
buttonLink: '#',
|
||||
color: 'from-blue-500 to-blue-700',
|
||||
},
|
||||
{
|
||||
icon: <CodeIcon className="h-6 w-6 text-blue-600 dark:text-blue-400" />,
|
||||
iconBg: 'bg-blue-100 dark:bg-blue-900',
|
||||
title: 'Tantangan Koding',
|
||||
description:
|
||||
'Uji kemampuan koding kamu dengan tantangan yang menyenangkan dan menantang.',
|
||||
buttonText: 'Mulai Tantangan',
|
||||
buttonLink: '#',
|
||||
color: 'from-blue-500 to-blue-700',
|
||||
},
|
||||
{
|
||||
icon: <Share2Icon className="h-6 w-6 text-blue-600 dark:text-blue-400" />,
|
||||
iconBg: 'bg-blue-100 dark:bg-blue-900',
|
||||
title: 'Sharing Session',
|
||||
description:
|
||||
'Ikuti sesi berbagi pengalaman dari programmer berpengalaman dan belajar dari pengalaman mereka.',
|
||||
buttonText: 'Jadwal Session',
|
||||
buttonLink: '#',
|
||||
color: 'from-blue-500 to-blue-700',
|
||||
},
|
||||
];
|
||||
|
||||
const containerVariants = {
|
||||
hidden: { opacity: 0 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
transition: {
|
||||
staggerChildren: 0.1,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const itemVariants = {
|
||||
hidden: { y: 20, opacity: 0 },
|
||||
visible: {
|
||||
y: 0,
|
||||
opacity: 1,
|
||||
transition: { duration: 0.5 },
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<section
|
||||
id="sumber-belajar"
|
||||
className="w-full py-20 md:py-32 relative overflow-hidden"
|
||||
>
|
||||
{/* Background Elements */}
|
||||
<div className="absolute inset-0 -z-10">
|
||||
<div className="absolute inset-0 bg-gradient-to-b from-background via-background to-background" />
|
||||
<div className="absolute top-0 right-0 w-1/2 h-1/2 bg-gradient-to-bl from-primary/5 to-transparent blur-3xl" />
|
||||
<div className="absolute bottom-0 left-0 w-1/2 h-1/2 bg-gradient-to-tr from-blue-400/5 to-transparent blur-3xl" />
|
||||
</div>
|
||||
|
||||
<div className="container px-4 md:px-6" ref={ref}>
|
||||
<div className="flex flex-col items-center justify-center space-y-4 text-center mb-16">
|
||||
<motion.div
|
||||
className="space-y-2"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
>
|
||||
<h2 className="text-3xl font-bold tracking-tighter md:text-4xl/tight lg:text-5xl">
|
||||
Sumber{' '}
|
||||
<span className="bg-clip-text text-transparent bg-gradient-to-r from-primary to-blue-400">
|
||||
Belajar
|
||||
</span>
|
||||
</h2>
|
||||
<p className="max-w-[800px] mx-auto text-muted-foreground md:text-lg">
|
||||
Akses berbagai materi belajar yang akan membantu kamu menguasai
|
||||
konsep programming dengan cara yang menyenangkan.
|
||||
</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div
|
||||
className="grid gap-8 md:grid-cols-2 lg:grid-cols-4"
|
||||
variants={containerVariants}
|
||||
initial="hidden"
|
||||
animate={isInView ? 'visible' : 'hidden'}
|
||||
>
|
||||
{resources.map((resource, index) => (
|
||||
<motion.div
|
||||
key={index}
|
||||
className="group relative overflow-hidden rounded-xl border bg-background p-6 transition-all hover:shadow-lg"
|
||||
variants={itemVariants}
|
||||
>
|
||||
<div className="absolute top-0 left-0 h-1 w-full bg-gradient-to-r from-primary/50 to-blue-400/50 opacity-0 group-hover:opacity-100 transition-opacity duration-300" />
|
||||
|
||||
<div className="relative z-10">
|
||||
<div
|
||||
className={`mb-4 inline-flex h-12 w-12 items-center justify-center rounded-full ${resource.iconBg}`}
|
||||
>
|
||||
{resource.icon}
|
||||
</div>
|
||||
<h3 className="mb-2 text-xl font-bold">{resource.title}</h3>
|
||||
<p className="mb-6 text-muted-foreground">
|
||||
{resource.description}
|
||||
</p>
|
||||
<Button
|
||||
variant="link"
|
||||
className="p-0 h-auto font-medium text-primary hover:text-primary/80"
|
||||
>
|
||||
{resource.buttonText} →
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="absolute -bottom-32 -right-32 w-64 h-64 bg-gradient-to-tl from-primary/10 to-transparent rounded-full opacity-0 group-hover:opacity-100 transition-all duration-500 group-hover:-translate-y-10 group-hover:-translate-x-10" />
|
||||
</motion.div>
|
||||
))}
|
||||
</motion.div>
|
||||
|
||||
{/* Featured Resource */}
|
||||
<motion.div
|
||||
className="mt-20 rounded-xl overflow-hidden border bg-background/50 backdrop-blur-sm"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
|
||||
transition={{ duration: 0.5, delay: 0.3 }}
|
||||
>
|
||||
<div className="grid md:grid-cols-2 gap-0">
|
||||
<div className="p-8 md:p-12 flex flex-col justify-center">
|
||||
<div className="inline-block rounded-full bg-primary/10 px-4 py-1.5 text-sm font-medium text-primary mb-4">
|
||||
Rekomendasi Terbaik
|
||||
</div>
|
||||
<h3 className="text-2xl md:text-3xl font-bold mb-4">
|
||||
Kursus Lengkap Web Development
|
||||
</h3>
|
||||
<p className="text-muted-foreground mb-6">
|
||||
Pelajari HTML, CSS, JavaScript, React, dan Node.js dalam satu
|
||||
kursus komprehensif yang dirancang untuk pemula hingga tingkat
|
||||
menengah.
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-4">
|
||||
<Button className="bg-gradient-to-r from-primary to-blue-400 hover:from-primary/90 hover:to-blue-400/90">
|
||||
Mulai Kursus
|
||||
</Button>
|
||||
<Button variant="outline">Lihat Silabus</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative h-64 md:h-auto">
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-primary/20 to-blue-400/20" />
|
||||
<div className="absolute inset-0 flex items-center justify-center">
|
||||
<div className="w-16 h-16 rounded-full bg-background/80 backdrop-blur-sm flex items-center justify-center cursor-pointer hover:bg-background transition-colors">
|
||||
<div className="w-0 h-0 border-t-8 border-t-transparent border-l-12 border-l-primary border-b-8 border-b-transparent ml-1" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
'use client';
|
||||
|
||||
import {
|
||||
Button,
|
||||
MoonIcon,
|
||||
SunIcon,
|
||||
} from '@imphnen-frontend-service/shadcn-ui/atoms';
|
||||
import { useTheme } from 'next-themes';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
export function SimpleThemeToggle() {
|
||||
const { theme, setTheme } = useTheme();
|
||||
const [mounted, setMounted] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setMounted(true);
|
||||
}, []);
|
||||
|
||||
if (!mounted) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const toggleTheme = () => {
|
||||
setTheme(theme === 'dark' ? 'light' : 'dark');
|
||||
};
|
||||
|
||||
return (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={toggleTheme}
|
||||
className="focus-visible:ring-0"
|
||||
>
|
||||
{theme === 'dark' ? (
|
||||
<SunIcon className="h-[1.2rem] w-[1.2rem]" />
|
||||
) : (
|
||||
<MoonIcon className="h-[1.2rem] w-[1.2rem]" />
|
||||
)}
|
||||
<span className="sr-only">Toggle theme</span>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
'use client';
|
||||
|
||||
import { QuoteIcon } from '@imphnen-frontend-service/shadcn-ui/atoms';
|
||||
import { motion, useInView } from 'framer-motion';
|
||||
import Image from 'next/image';
|
||||
import { useRef } from 'react';
|
||||
|
||||
export function Testimonials() {
|
||||
const ref = useRef(null);
|
||||
const isInView = useInView(ref, { once: true, amount: 0.2 });
|
||||
|
||||
const testimonials = [
|
||||
{
|
||||
quote:
|
||||
'Saya yang tadinya tidak mengerti apa-apa tentang programming, sekarang bisa membuat website sendiri dengan mudah. Terima kasih IMPHNEN!',
|
||||
name: 'Budi Santoso',
|
||||
role: 'Web Developer Pemula',
|
||||
avatar: '/placeholder.svg?height=64&width=64',
|
||||
},
|
||||
{
|
||||
quote:
|
||||
'Komunitas yang sangat supportif! Setiap pertanyaan selalu dijawab dengan cepat dan jelas. Diskusi programnya mudah dipahami.',
|
||||
name: 'Anita Ratna',
|
||||
role: 'Mobile App Developer',
|
||||
avatar: '/placeholder.svg?height=64&width=64',
|
||||
},
|
||||
{
|
||||
quote:
|
||||
'Server Discord IMPHNEN adalah tempat belajar terbaik untuk programmer pemula seperti saya. Materinya lengkap dan komunitasnya sangat membantu!',
|
||||
name: 'Dedi Permana',
|
||||
role: 'Data Scientist',
|
||||
avatar: '/placeholder.svg?height=64&width=64',
|
||||
},
|
||||
];
|
||||
|
||||
const containerVariants = {
|
||||
hidden: { opacity: 0 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
transition: {
|
||||
staggerChildren: 0.1,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const itemVariants = {
|
||||
hidden: { y: 20, opacity: 0 },
|
||||
visible: {
|
||||
y: 0,
|
||||
opacity: 1,
|
||||
transition: { duration: 0.5 },
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<section
|
||||
id="testimoni"
|
||||
className="w-full py-20 md:py-32 bg-muted relative overflow-hidden"
|
||||
>
|
||||
{/* Background Elements */}
|
||||
<div className="absolute inset-0 -z-10">
|
||||
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_top,rgba(59,130,246,0.1),transparent_50%)]" />
|
||||
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_bottom,rgba(96,165,250,0.1),transparent_50%)]" />
|
||||
</div>
|
||||
|
||||
<div className="container px-4 md:px-6" ref={ref}>
|
||||
<div className="flex flex-col items-center justify-center space-y-4 text-center mb-16">
|
||||
<motion.div
|
||||
className="space-y-2"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
>
|
||||
<h2 className="text-3xl font-bold tracking-tighter md:text-4xl/tight lg:text-5xl">
|
||||
Testimoni{' '}
|
||||
<span className="bg-clip-text text-transparent bg-gradient-to-r from-primary to-blue-400">
|
||||
Member
|
||||
</span>
|
||||
</h2>
|
||||
<p className="max-w-[800px] mx-auto text-muted-foreground md:text-lg">
|
||||
Apa kata mereka yang telah bergabung dengan komunitas IMPHNEN?
|
||||
</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div
|
||||
className="grid gap-8 md:grid-cols-3"
|
||||
variants={containerVariants}
|
||||
initial="hidden"
|
||||
animate={isInView ? 'visible' : 'hidden'}
|
||||
>
|
||||
{testimonials.map((testimonial, index) => (
|
||||
<motion.div
|
||||
key={index}
|
||||
className="group relative overflow-hidden rounded-xl border bg-background p-6 transition-all hover:shadow-lg"
|
||||
variants={itemVariants}
|
||||
>
|
||||
<div className="absolute top-6 right-6 text-primary/20 group-hover:text-primary/40 transition-colors">
|
||||
<QuoteIcon className="h-8 w-8" />
|
||||
</div>
|
||||
|
||||
<div className="relative z-10">
|
||||
<p className="mb-6 text-muted-foreground italic">
|
||||
"{testimonial.quote}"
|
||||
</p>
|
||||
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="relative h-12 w-12 overflow-hidden rounded-full border-2 border-primary/20">
|
||||
<Image
|
||||
src={testimonial.avatar || '/placeholder.svg'}
|
||||
alt={testimonial.name}
|
||||
width={48}
|
||||
height={48}
|
||||
className="object-cover"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-bold">{testimonial.name}</h4>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{testimonial.role}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="absolute -bottom-1 -left-1 w-20 h-20 bg-gradient-to-tr from-primary/10 to-transparent rounded-tr-full opacity-0 group-hover:opacity-100 transition-opacity duration-500" />
|
||||
</motion.div>
|
||||
))}
|
||||
</motion.div>
|
||||
|
||||
{/* Testimonial Stats */}
|
||||
<motion.div
|
||||
className="mt-20 rounded-xl overflow-hidden border bg-background/50 backdrop-blur-sm p-8 md:p-12"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
|
||||
transition={{ duration: 0.5, delay: 0.3 }}
|
||||
>
|
||||
<div className="grid md:grid-cols-2 gap-8 items-center">
|
||||
<div>
|
||||
<h3 className="text-2xl md:text-3xl font-bold mb-4">
|
||||
Bergabunglah dengan{' '}
|
||||
<span className="bg-clip-text text-transparent bg-gradient-to-r from-primary to-blue-400">
|
||||
10,000+
|
||||
</span>{' '}
|
||||
programmer Indonesia lainnya
|
||||
</h3>
|
||||
<p className="text-muted-foreground">
|
||||
Komunitas kami terus berkembang dengan programmer dari berbagai
|
||||
latar belakang dan tingkat keahlian. Bersama-sama, kita belajar,
|
||||
berbagi, dan tumbuh sebagai profesional.
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="rounded-lg border p-4 text-center">
|
||||
<div className="text-3xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-primary to-blue-400">
|
||||
98%
|
||||
</div>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
Tingkat Kemalasan
|
||||
</div>
|
||||
</div>
|
||||
<div className="rounded-lg border p-4 text-center">
|
||||
<div className="text-3xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-primary to-blue-400">
|
||||
4.9/5
|
||||
</div>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
Rating Drama
|
||||
</div>
|
||||
</div>
|
||||
<div className="rounded-lg border p-4 text-center">
|
||||
<div className="text-3xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-primary to-blue-400">
|
||||
85%
|
||||
</div>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
Mendapat Pekerjaan
|
||||
</div>
|
||||
</div>
|
||||
<div className="rounded-lg border p-4 text-center">
|
||||
<div className="text-3xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-primary to-blue-400">
|
||||
24/7
|
||||
</div>
|
||||
<div className="text-sm text-muted-foreground">Yapping</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
'use client';
|
||||
|
||||
import type { ThemeProviderProps } from 'next-themes';
|
||||
import { ThemeProvider as NextThemesProvider } from 'next-themes';
|
||||
|
||||
export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
|
||||
return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
export async function GET(request: Request) {
|
||||
return new Response('Hello, from API!');
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
@import 'tailwindcss';
|
||||
@source './pages/**/*.{ts,tsx}';
|
||||
@source './components/**/*.{ts,tsx}';
|
||||
@source './app/**/*.{ts,tsx}';
|
||||
@source './src/**/*.{ts,tsx}';
|
||||
@source '*.{js,ts,jsx,tsx,mdx}';
|
||||
|
||||
@theme {
|
||||
--border: hsl(var(--border));
|
||||
--input: hsl(var(--input));
|
||||
--ring: hsl(var(--ring));
|
||||
--background: hsl(var(--background));
|
||||
--foreground: hsl(var(--foreground));
|
||||
|
||||
--primary: hsl(var(--primary));
|
||||
--primary-foreground: hsl(var(--primary-foreground));
|
||||
|
||||
--secondary: hsl(var(--secondary));
|
||||
--secondary-foreground: hsl(var(--secondary-foreground));
|
||||
|
||||
--destructive: hsl(var(--destructive));
|
||||
--destructive-foreground: hsl(var(--destructive-foreground));
|
||||
|
||||
--muted: hsl(var(--muted));
|
||||
--muted-foreground: hsl(var(--muted-foreground));
|
||||
|
||||
--accent: hsl(var(--accent));
|
||||
--accent-foreground: hsl(var(--accent-foreground));
|
||||
|
||||
--popover: hsl(var(--popover));
|
||||
--popover-foreground: hsl(var(--popover-foreground));
|
||||
|
||||
--card: hsl(var(--card));
|
||||
--card-foreground: hsl(var(--card-foreground));
|
||||
|
||||
--radius-lg: var(--radius);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
}
|
||||
|
||||
@layer base {
|
||||
html {
|
||||
/* Optional kalau mau style dasar */
|
||||
}
|
||||
|
||||
/* Accordion animation (keyframes dan animation) */
|
||||
@keyframes accordion-down {
|
||||
from {
|
||||
height: 0;
|
||||
}
|
||||
to {
|
||||
height: var(--radix-accordion-content-height);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes accordion-up {
|
||||
from {
|
||||
height: var(--radix-accordion-content-height);
|
||||
}
|
||||
to {
|
||||
height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.accordion-down {
|
||||
animation: accordion-down 0.2s ease-out;
|
||||
}
|
||||
|
||||
.accordion-up {
|
||||
animation: accordion-up 0.2s ease-out;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,13 @@
|
||||
import './global.css';
|
||||
import { type Metadata } from 'next';
|
||||
import { Inter } from 'next/font/google';
|
||||
import '../styles/globals.css';
|
||||
import { ThemeProvider } from './_components/theme-provider';
|
||||
|
||||
export const metadata = {
|
||||
title: 'Welcome to landing',
|
||||
description: 'Generated by create-nx-workspace',
|
||||
const inter = Inter({ subsets: ['latin'] });
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'IMPHNEN - Ingin Menjadi Programmer Handal?',
|
||||
description: 'Komunitas belajar programming untuk semua level',
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
@@ -11,8 +16,17 @@ export default function RootLayout({
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>{children}</body>
|
||||
<html lang="id" suppressHydrationWarning>
|
||||
<body className={inter.className}>
|
||||
<ThemeProvider
|
||||
attribute="class"
|
||||
defaultTheme="system"
|
||||
enableSystem
|
||||
disableTransitionOnChange
|
||||
>
|
||||
{children}
|
||||
</ThemeProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
|
||||
+21
-463
File diff suppressed because one or more lines are too long
@@ -0,0 +1,3 @@
|
||||
@import 'tailwindcss';
|
||||
@import "../../../../libs/shadcn-ui/src/index.css";
|
||||
@source "../../../../libs/shadcn-ui/src/atoms/**/*.{ts,tsx}";
|
||||
@@ -2,7 +2,6 @@
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"jsx": "preserve",
|
||||
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"emitDeclarationOnly": false,
|
||||
@@ -11,23 +10,35 @@
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"incremental": true,
|
||||
"plugins": [{ "name": "next" }]
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
"**/*.js",
|
||||
"**/*.jsx",
|
||||
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
"../../apps/landing/.next/types/**/*.ts",
|
||||
"../../dist/apps/landing/.next/types/**/*.ts",
|
||||
|
||||
"next-env.d.ts"
|
||||
"next-env.d.ts",
|
||||
".next/types/**/*.ts"
|
||||
],
|
||||
"exclude": ["node_modules", "jest.config.ts", "**/*.spec.ts", "**/*.test.ts"]
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"jest.config.ts",
|
||||
"**/*.spec.ts",
|
||||
"**/*.test.ts"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"presets": [
|
||||
[
|
||||
"@nx/react/babel",
|
||||
{
|
||||
"runtime": "automatic",
|
||||
"useBuiltIns": "usage"
|
||||
}
|
||||
]
|
||||
],
|
||||
"plugins": []
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
# shadcn-ui
|
||||
|
||||
This library was generated with [Nx](https://nx.dev).
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `nx test shadcn-ui` to execute the unit tests via [Vitest](https://vitest.dev/).
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema.json",
|
||||
"style": "new-york",
|
||||
"rsc": false,
|
||||
"tsx": true,
|
||||
"tailwind": {
|
||||
"config": "",
|
||||
"css": "src/index.css",
|
||||
"baseColor": "zinc",
|
||||
"cssVariables": true,
|
||||
"prefix": ""
|
||||
},
|
||||
"aliases": {
|
||||
"components": "@imphnen-frontend-service/service/components",
|
||||
"utils": "@imphnen-frontend-service/service/lib/utils",
|
||||
"ui": "@imphnen-frontend-service/service/components/ui",
|
||||
"lib": "@imphnen-frontend-service/service/lib",
|
||||
"hooks": "@imphnen-frontend-service/service/hooks"
|
||||
},
|
||||
"iconLibrary": "lucide"
|
||||
}
|
||||
Generated
+1654
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "@imphnen-frontend-service/shadcn-ui",
|
||||
"version": "0.0.1",
|
||||
"main": "./index.js",
|
||||
"types": "./index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./index.mjs",
|
||||
"require": "./index.js"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@radix-ui/react-slot": "^1.2.0",
|
||||
"@tailwindcss/vite": "^4.1.4",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"lucide-react": "^0.503.0",
|
||||
"react-icons": "^5.5.0",
|
||||
"tailwind-merge": "^3.2.0",
|
||||
"tailwindcss": "^4.1.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"tw-animate-css": "^1.2.8"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "shadcn-ui",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "libs/shadcn-ui/src",
|
||||
"projectType": "library",
|
||||
"tags": [],
|
||||
"// targets": "to see all targets run: nx show project shadcn-ui --web",
|
||||
"targets": {}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
'use client';
|
||||
|
||||
import { cn } from '@imphnen-frontend-service/utils';
|
||||
import { Slot } from '@radix-ui/react-slot';
|
||||
import { cva, type VariantProps } from 'class-variance-authority';
|
||||
import * as React from 'react';
|
||||
|
||||
const buttonVariants = cva(
|
||||
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
'bg-primary text-primary-foreground shadow hover:bg-primary/90',
|
||||
destructive:
|
||||
'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90',
|
||||
outline:
|
||||
'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground',
|
||||
secondary:
|
||||
'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80',
|
||||
ghost: 'hover:bg-accent hover:text-accent-foreground',
|
||||
link: 'text-primary underline-offset-4 hover:underline',
|
||||
},
|
||||
size: {
|
||||
default: 'h-9 px-4 py-2',
|
||||
sm: 'h-8 rounded-md px-3 text-xs',
|
||||
lg: 'h-10 rounded-md px-8',
|
||||
icon: 'h-9 w-9',
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: 'default',
|
||||
size: 'default',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
export interface ButtonProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
VariantProps<typeof buttonVariants> {
|
||||
asChild?: boolean;
|
||||
}
|
||||
|
||||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ className, variant, size, asChild = false, ...props }, ref) => {
|
||||
const Comp = asChild ? Slot : 'button';
|
||||
return (
|
||||
<Comp
|
||||
className={cn(buttonVariants({ variant, size, className }))}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
Button.displayName = 'Button';
|
||||
|
||||
export { Button, buttonVariants };
|
||||
@@ -0,0 +1,37 @@
|
||||
import {
|
||||
LuArrowDown as ArrowDownIcon,
|
||||
LuBookOpen as BookOpenIcon,
|
||||
LuCode as CodeIcon,
|
||||
LuFacebook as FacebookIcon,
|
||||
LuInstagram as InstagramIcon,
|
||||
LuLaptop as LaptopIcon,
|
||||
LuMenu as MenuIcon,
|
||||
LuMessageCircle as MessageCircleIcon,
|
||||
LuMoon as MoonIcon,
|
||||
LuQuote as QuoteIcon,
|
||||
LuShare2 as Share2Icon,
|
||||
LuSparkles as SparklesIcon,
|
||||
LuSun as SunIcon,
|
||||
LuUsers as UsersIcon,
|
||||
LuVideo as VideoIcon,
|
||||
LuX as XIcon,
|
||||
} from 'react-icons/lu';
|
||||
|
||||
export {
|
||||
ArrowDownIcon,
|
||||
BookOpenIcon,
|
||||
CodeIcon,
|
||||
FacebookIcon,
|
||||
InstagramIcon,
|
||||
LaptopIcon,
|
||||
MenuIcon,
|
||||
MessageCircleIcon,
|
||||
MoonIcon,
|
||||
QuoteIcon,
|
||||
Share2Icon,
|
||||
SparklesIcon,
|
||||
SunIcon,
|
||||
UsersIcon,
|
||||
VideoIcon,
|
||||
XIcon,
|
||||
};
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './button';
|
||||
export * from './icons';
|
||||
@@ -0,0 +1,134 @@
|
||||
@import 'tailwindcss';
|
||||
@import "tw-animate-css";
|
||||
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
||||
@theme inline {
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-lg: var(--radius);
|
||||
--radius-xl: calc(var(--radius) + 4px);
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--color-card: var(--card);
|
||||
--color-card-foreground: var(--card-foreground);
|
||||
--color-popover: var(--popover);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
--color-primary: var(--primary);
|
||||
--color-primary-foreground: var(--primary-foreground);
|
||||
--color-secondary: var(--secondary);
|
||||
--color-secondary-foreground: var(--secondary-foreground);
|
||||
--color-muted: var(--muted);
|
||||
--color-muted-foreground: var(--muted-foreground);
|
||||
--color-accent: var(--accent);
|
||||
--color-accent-foreground: var(--accent-foreground);
|
||||
--color-destructive: var(--destructive);
|
||||
--color-border: var(--border);
|
||||
--color-input: var(--input);
|
||||
--color-ring: var(--ring);
|
||||
--color-chart-1: var(--chart-1);
|
||||
--color-chart-2: var(--chart-2);
|
||||
--color-chart-3: var(--chart-3);
|
||||
--color-chart-4: var(--chart-4);
|
||||
--color-chart-5: var(--chart-5);
|
||||
--color-sidebar: var(--sidebar);
|
||||
--color-sidebar-foreground: var(--sidebar-foreground);
|
||||
--color-sidebar-primary: var(--sidebar-primary);
|
||||
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
||||
--color-sidebar-accent: var(--sidebar-accent);
|
||||
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
||||
--color-sidebar-border: var(--sidebar-border);
|
||||
--color-sidebar-ring: var(--sidebar-ring);
|
||||
}
|
||||
|
||||
:root {
|
||||
--radius: 1rem;
|
||||
--background: oklch(1 0 0);
|
||||
--foreground: oklch(0.141 0.005 285.823);
|
||||
--card: oklch(1 0 0);
|
||||
--card-foreground: oklch(0.141 0.005 285.823);
|
||||
--popover: oklch(1 0 0);
|
||||
--popover-foreground: oklch(0.141 0.005 285.823);
|
||||
--primary: oklch(0.623 0.214 259.815);
|
||||
--primary-foreground: oklch(0.97 0.014 254.604);
|
||||
--secondary: oklch(0.967 0.001 286.375);
|
||||
--secondary-foreground: oklch(0.21 0.006 285.885);
|
||||
--muted: oklch(0.967 0.001 286.375);
|
||||
--muted-foreground: oklch(0.552 0.016 285.938);
|
||||
--accent: oklch(0.967 0.001 286.375);
|
||||
--accent-foreground: oklch(0.21 0.006 285.885);
|
||||
--destructive: oklch(0.577 0.245 27.325);
|
||||
--border: oklch(0.92 0.004 286.32);
|
||||
--input: oklch(0.92 0.004 286.32);
|
||||
--ring: oklch(0.623 0.214 259.815);
|
||||
--chart-1: oklch(0.646 0.222 41.116);
|
||||
--chart-2: oklch(0.6 0.118 184.704);
|
||||
--chart-3: oklch(0.398 0.07 227.392);
|
||||
--chart-4: oklch(0.828 0.189 84.429);
|
||||
--chart-5: oklch(0.769 0.188 70.08);
|
||||
--sidebar: oklch(0.985 0 0);
|
||||
--sidebar-foreground: oklch(0.141 0.005 285.823);
|
||||
--sidebar-primary: oklch(0.623 0.214 259.815);
|
||||
--sidebar-primary-foreground: oklch(0.97 0.014 254.604);
|
||||
--sidebar-accent: oklch(0.967 0.001 286.375);
|
||||
--sidebar-accent-foreground: oklch(0.21 0.006 285.885);
|
||||
--sidebar-border: oklch(0.92 0.004 286.32);
|
||||
--sidebar-ring: oklch(0.623 0.214 259.815);
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: oklch(0.141 0.005 285.823);
|
||||
--foreground: oklch(0.985 0 0);
|
||||
--card: oklch(0.21 0.006 285.885);
|
||||
--card-foreground: oklch(0.985 0 0);
|
||||
--popover: oklch(0.21 0.006 285.885);
|
||||
--popover-foreground: oklch(0.985 0 0);
|
||||
--primary: oklch(0.546 0.245 262.881);
|
||||
--primary-foreground: oklch(0.379 0.146 265.522);
|
||||
--secondary: oklch(0.274 0.006 286.033);
|
||||
--secondary-foreground: oklch(0.985 0 0);
|
||||
--muted: oklch(0.274 0.006 286.033);
|
||||
--muted-foreground: oklch(0.705 0.015 286.067);
|
||||
--accent: oklch(0.274 0.006 286.033);
|
||||
--accent-foreground: oklch(0.985 0 0);
|
||||
--destructive: oklch(0.704 0.191 22.216);
|
||||
--border: oklch(1 0 0 / 10%);
|
||||
--input: oklch(1 0 0 / 15%);
|
||||
--ring: oklch(0.488 0.243 264.376);
|
||||
--chart-1: oklch(0.488 0.243 264.376);
|
||||
--chart-2: oklch(0.696 0.17 162.48);
|
||||
--chart-3: oklch(0.769 0.188 70.08);
|
||||
--chart-4: oklch(0.627 0.265 303.9);
|
||||
--chart-5: oklch(0.645 0.246 16.439);
|
||||
--sidebar: oklch(0.21 0.006 285.885);
|
||||
--sidebar-foreground: oklch(0.985 0 0);
|
||||
--sidebar-primary: oklch(0.546 0.245 262.881);
|
||||
--sidebar-primary-foreground: oklch(0.379 0.146 265.522);
|
||||
--sidebar-accent: oklch(0.274 0.006 286.033);
|
||||
--sidebar-accent-foreground: oklch(0.985 0 0);
|
||||
--sidebar-border: oklch(1 0 0 / 10%);
|
||||
--sidebar-ring: oklch(0.488 0.243 264.376);
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border outline-ring/50;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
}
|
||||
|
||||
/* https://github.com/tailwindlabs/tailwindcss/issues/13129 */
|
||||
.container {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding-left: 2rem;
|
||||
padding-right: 2rem;
|
||||
width: 100%;
|
||||
}
|
||||
@media (min-width: 1536px) {
|
||||
.container {
|
||||
max-width: 1400px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './atoms/index';
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx",
|
||||
"allowJs": false,
|
||||
"esModuleInterop": false,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"types": ["vite/client"]
|
||||
},
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
}
|
||||
],
|
||||
"extends": "../../tsconfig.base.json"
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"types": [
|
||||
"node",
|
||||
"@nx/react/typings/cssmodule.d.ts",
|
||||
"@nx/react/typings/image.d.ts",
|
||||
"vite/client",
|
||||
"next",
|
||||
"@nx/next/typings/image.d.ts"
|
||||
]
|
||||
},
|
||||
"exclude": [
|
||||
"**/*.spec.ts",
|
||||
"**/*.test.ts",
|
||||
"**/*.spec.tsx",
|
||||
"**/*.test.tsx",
|
||||
"**/*.spec.js",
|
||||
"**/*.test.js",
|
||||
"**/*.spec.jsx",
|
||||
"**/*.test.jsx"
|
||||
],
|
||||
"include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"]
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/// <reference types='vitest' />
|
||||
import { defineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import dts from 'vite-plugin-dts';
|
||||
import * as path from 'path';
|
||||
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
||||
import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin';
|
||||
|
||||
export default defineConfig(() => ({
|
||||
root: __dirname,
|
||||
cacheDir: '../../node_modules/.vite/libs/shadcn-ui',
|
||||
plugins: [
|
||||
react(),
|
||||
nxViteTsPaths(),
|
||||
nxCopyAssetsPlugin(['*.md']),
|
||||
dts({
|
||||
entryRoot: 'src',
|
||||
tsconfigPath: path.join(__dirname, 'tsconfig.lib.json'),
|
||||
}),
|
||||
],
|
||||
// Uncomment this if you are using workers.
|
||||
// worker: {
|
||||
// plugins: [ nxViteTsPaths() ],
|
||||
// },
|
||||
// Configuration for building your library.
|
||||
// See: https://vitejs.dev/guide/build.html#library-mode
|
||||
build: {
|
||||
outDir: '../../dist/libs/shadcn-ui',
|
||||
emptyOutDir: true,
|
||||
reportCompressedSize: true,
|
||||
commonjsOptions: {
|
||||
transformMixedEsModules: true,
|
||||
},
|
||||
lib: {
|
||||
// Could also be a dictionary or array of multiple entry points.
|
||||
entry: 'src/index.ts',
|
||||
name: 'shadcn-ui',
|
||||
fileName: 'index',
|
||||
// Change this to the formats you want to support.
|
||||
// Don't forget to update your package.json as well.
|
||||
formats: ['es' as const],
|
||||
},
|
||||
rollupOptions: {
|
||||
// External packages that should not be bundled into your library.
|
||||
external: ['react', 'react-dom', 'react/jsx-runtime'],
|
||||
},
|
||||
},
|
||||
}));
|
||||
Generated
+270
-84
@@ -11,16 +11,21 @@
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^6.0.0",
|
||||
"@hookform/resolvers": "^5.0.1",
|
||||
"@radix-ui/react-slot": "^1.2.0",
|
||||
"@tanstack/react-query": "^5.74.4",
|
||||
"@tanstack/react-store": "^0.7.0",
|
||||
"@tanstack/react-table": "^8.21.2",
|
||||
"axios": "^1.8.3",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"framer-motion": "^12.9.2",
|
||||
"js-cookie": "^3.0.5",
|
||||
"next": "~15.2.4",
|
||||
"next-themes": "^0.4.6",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-hook-form": "^7.55.0",
|
||||
"react-icons": "^5.5.0",
|
||||
"react-router-dom": "^7.3.0",
|
||||
"sonner": "^2.0.3",
|
||||
"tailwind-merge": "^3.0.2",
|
||||
@@ -88,6 +93,7 @@
|
||||
"tailwindcss": "^4.0.13",
|
||||
"ts-node": "^10.9.2",
|
||||
"tslib": "^2.3.0",
|
||||
"tw-animate-css": "^1.2.8",
|
||||
"typescript": "^5.8.3",
|
||||
"typescript-eslint": "^8.19.0",
|
||||
"verdaccio": "^6.0.5",
|
||||
@@ -7509,7 +7515,7 @@
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.52.0.tgz",
|
||||
"integrity": "sha512-uh6W7sb55hl7D6vsAeA+V2p5JnlAqzhqFyF0VcJkKZXkgnFcVG9PziERRHQfPLfNGx1C292a4JqbWzhR8L4R1g==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright": "1.52.0"
|
||||
@@ -7528,6 +7534,39 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@radix-ui/react-compose-refs": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
|
||||
"integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-slot": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.0.tgz",
|
||||
"integrity": "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@rc-component/util": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@rc-component/util/-/util-1.2.1.tgz",
|
||||
@@ -10715,7 +10754,7 @@
|
||||
"version": "19.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.2.tgz",
|
||||
"integrity": "sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"csstype": "^3.0.2"
|
||||
@@ -14745,41 +14784,19 @@
|
||||
}
|
||||
},
|
||||
"node_modules/chokidar": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
|
||||
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
|
||||
"dev": true,
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
|
||||
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
"glob-parent": "~5.1.2",
|
||||
"is-binary-path": "~2.1.0",
|
||||
"is-glob": "~4.0.1",
|
||||
"normalize-path": "~3.0.0",
|
||||
"readdirp": "~3.6.0"
|
||||
"readdirp": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.10.0"
|
||||
"node": ">= 14.16.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/chokidar/node_modules/glob-parent": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"is-glob": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/chrome-trace-event": {
|
||||
@@ -14815,6 +14832,18 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/class-variance-authority": {
|
||||
"version": "0.7.1",
|
||||
"resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz",
|
||||
"integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"clsx": "^2.1.1"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://polar.sh/cva"
|
||||
}
|
||||
},
|
||||
"node_modules/classnames": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
|
||||
@@ -16040,7 +16069,7 @@
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cwd": {
|
||||
@@ -18924,6 +18953,31 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/fork-ts-checker-webpack-plugin/node_modules/chokidar": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
|
||||
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
"glob-parent": "~5.1.2",
|
||||
"is-binary-path": "~2.1.0",
|
||||
"is-glob": "~4.0.1",
|
||||
"normalize-path": "~3.0.0",
|
||||
"readdirp": "~3.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.10.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/fork-ts-checker-webpack-plugin/node_modules/cosmiconfig": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
|
||||
@@ -18956,6 +19010,45 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/fork-ts-checker-webpack-plugin/node_modules/glob-parent": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"is-glob": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/fork-ts-checker-webpack-plugin/node_modules/picomatch": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/fork-ts-checker-webpack-plugin/node_modules/readdirp": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"picomatch": "^2.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fork-ts-checker-webpack-plugin/node_modules/semver": {
|
||||
"version": "7.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
|
||||
@@ -19028,6 +19121,33 @@
|
||||
"url": "https://github.com/sponsors/rawify"
|
||||
}
|
||||
},
|
||||
"node_modules/framer-motion": {
|
||||
"version": "12.9.2",
|
||||
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.9.2.tgz",
|
||||
"integrity": "sha512-R0O3Jdqbfwywpm45obP+8sTgafmdEcUoShQTAV+rB5pi+Y1Px/FYL5qLLRe5tPtBdN1J4jos7M+xN2VV2oEAbQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"motion-dom": "^12.9.1",
|
||||
"motion-utils": "^12.8.3",
|
||||
"tslib": "^2.4.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@emotion/is-prop-valid": "*",
|
||||
"react": "^18.0.0 || ^19.0.0",
|
||||
"react-dom": "^18.0.0 || ^19.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@emotion/is-prop-valid": {
|
||||
"optional": true
|
||||
},
|
||||
"react": {
|
||||
"optional": true
|
||||
},
|
||||
"react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/fresh": {
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
|
||||
@@ -20182,7 +20302,7 @@
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.1.tgz",
|
||||
"integrity": "sha512-3jatXi9ObIsPGr3N5hGw/vWWcTkq6hUYhpQz4k0wLC+owqWi/LiugIw9x0EdNZ2yGedKN/HzePiBvaJRXa0Ujg==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/import-fresh": {
|
||||
@@ -24291,6 +24411,21 @@
|
||||
"pathe": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/motion-dom": {
|
||||
"version": "12.9.1",
|
||||
"resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.9.1.tgz",
|
||||
"integrity": "sha512-xqXEwRLDYDTzOgXobSoWtytRtGlf7zdkRfFbrrdP7eojaGQZ5Go4OOKtgnx7uF8sAkfr1ZjMvbCJSCIT2h6fkQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"motion-utils": "^12.8.3"
|
||||
}
|
||||
},
|
||||
"node_modules/motion-utils": {
|
||||
"version": "12.8.3",
|
||||
"resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.8.3.tgz",
|
||||
"integrity": "sha512-GYVauZEbca8/zOhEiYOY9/uJeedYQld6co/GJFKOy//0c/4lDqk0zB549sBYqqV2iMuX+uHrY1E5zd8A2L+1Lw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/mrmime": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz",
|
||||
@@ -24459,6 +24594,16 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/next-themes": {
|
||||
"version": "0.4.6",
|
||||
"resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz",
|
||||
"integrity": "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc"
|
||||
}
|
||||
},
|
||||
"node_modules/next/node_modules/@swc/helpers": {
|
||||
"version": "0.5.15",
|
||||
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
|
||||
@@ -26196,7 +26341,7 @@
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.52.0.tgz",
|
||||
"integrity": "sha512-JAwMNMBlxJ2oD1kce4KPtMkDeKGHQstdpFPcPH3maElAXon/QZeTvtsfXmTMRyO9TslfoYOXkSsvao2nE1ilTw==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright-core": "1.52.0"
|
||||
@@ -26215,7 +26360,7 @@
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.52.0.tgz",
|
||||
"integrity": "sha512-l2osTgLXSMeuLZOML9qYODUQoPPnUsKsb5/P6LJ2e6uPKXUdPK5WYhN4z03G+YNbWmGDY4YENauNu4ZKczreHg==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"playwright-core": "cli.js"
|
||||
@@ -27409,6 +27554,15 @@
|
||||
"react": "^16.8.0 || ^17 || ^18 || ^19"
|
||||
}
|
||||
},
|
||||
"node_modules/react-icons": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz",
|
||||
"integrity": "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-is": {
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
||||
@@ -27510,29 +27664,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/readdirp": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"picomatch": "^2.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/readdirp/node_modules/picomatch": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||
"dev": true,
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
|
||||
"integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
"node": ">= 14.18.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/real-require": {
|
||||
@@ -28191,7 +28333,7 @@
|
||||
"version": "1.87.0",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.87.0.tgz",
|
||||
"integrity": "sha512-d0NoFH4v6SjEK7BoX810Jsrhj7IQSYHAHLi/iSpgqKc7LaIDshFRlSg5LOymf9FqQhxEHs2W5ZQXlvy0KD45Uw==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chokidar": "^4.0.0",
|
||||
@@ -28650,36 +28792,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/sass/node_modules/chokidar": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
|
||||
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"readdirp": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.16.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/sass/node_modules/readdirp": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
|
||||
"integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 14.18.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/sax": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
|
||||
@@ -31210,6 +31322,16 @@
|
||||
"integrity": "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/tw-animate-css": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.2.8.tgz",
|
||||
"integrity": "sha512-AxSnYRvyFnAiZCUndS3zQZhNfV/B77ZhJ+O7d3K6wfg/jKJY+yv6ahuyXwnyaYA9UdLqnpCwhTRv9pPTBnPR2g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/Wombosvideo"
|
||||
}
|
||||
},
|
||||
"node_modules/tweetnacl": {
|
||||
"version": "0.14.5",
|
||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
|
||||
@@ -32755,6 +32877,31 @@
|
||||
"ajv": "^8.8.2"
|
||||
}
|
||||
},
|
||||
"node_modules/webpack-dev-server/node_modules/chokidar": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
|
||||
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
"glob-parent": "~5.1.2",
|
||||
"is-binary-path": "~2.1.0",
|
||||
"is-glob": "~4.0.1",
|
||||
"normalize-path": "~3.0.0",
|
||||
"readdirp": "~3.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.10.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/webpack-dev-server/node_modules/define-lazy-prop": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz",
|
||||
@@ -32768,6 +32915,19 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/webpack-dev-server/node_modules/glob-parent": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"is-glob": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/webpack-dev-server/node_modules/http-proxy-middleware": {
|
||||
"version": "2.0.9",
|
||||
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz",
|
||||
@@ -32858,6 +33018,32 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/webpack-dev-server/node_modules/picomatch": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/webpack-dev-server/node_modules/readdirp": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"picomatch": "^2.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/webpack-dev-server/node_modules/schema-utils": {
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz",
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
"dimentorin:prod": "serve ./dist/apps/dimentorin",
|
||||
"landing:dev": "nx serve landing",
|
||||
"landing:build": "nx build landing",
|
||||
"landing:prod": "cd ./dist/apps/landing && npx next start",
|
||||
"ui:test": "nx test ui",
|
||||
"ui:build": "nx build ui",
|
||||
"ui:storybook": "nx storybook ui"
|
||||
@@ -25,16 +26,21 @@
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^6.0.0",
|
||||
"@hookform/resolvers": "^5.0.1",
|
||||
"@radix-ui/react-slot": "^1.2.0",
|
||||
"@tanstack/react-query": "^5.74.4",
|
||||
"@tanstack/react-store": "^0.7.0",
|
||||
"@tanstack/react-table": "^8.21.2",
|
||||
"axios": "^1.8.3",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"framer-motion": "^12.9.2",
|
||||
"js-cookie": "^3.0.5",
|
||||
"next": "~15.2.4",
|
||||
"next-themes": "^0.4.6",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-hook-form": "^7.55.0",
|
||||
"react-icons": "^5.5.0",
|
||||
"react-router-dom": "^7.3.0",
|
||||
"sonner": "^2.0.3",
|
||||
"tailwind-merge": "^3.0.2",
|
||||
@@ -102,6 +108,7 @@
|
||||
"tailwindcss": "^4.0.13",
|
||||
"ts-node": "^10.9.2",
|
||||
"tslib": "^2.3.0",
|
||||
"tw-animate-css": "^1.2.8",
|
||||
"typescript": "^5.8.3",
|
||||
"typescript-eslint": "^8.19.0",
|
||||
"verdaccio": "^6.0.5",
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@imphnen-frontend-service/service": ["libs/service/src/index.ts"],
|
||||
"@imphnen-frontend-service/shadcn-ui/atoms": ["libs/shadcn-ui/src/atoms/index.ts"],
|
||||
"@imphnen-frontend-service/ui/atoms": ["libs/ui/src/atoms/index.ts"],
|
||||
"@imphnen-frontend-service/ui/molecules": [
|
||||
"libs/ui/src/molecules/index.ts"
|
||||
|
||||
Reference in New Issue
Block a user