confirm build

This commit is contained in:
Developers Digest
2025-09-10 10:12:06 -04:00
parent 8687860a47
commit 13a4c5e1de
42 changed files with 6151 additions and 439 deletions
+1 -1
View File
@@ -43,7 +43,7 @@ export default function HeroInput({
} else {
setShowTiles(false);
}
}, [value, isFocused]);
}, [value, isFocused, showSearchFeatures]);
const handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {
if (e.key === "Enter" && !e.shiftKey) {
@@ -54,7 +54,8 @@ export default function ControlPanel({
analysisData,
onReset,
}: ControlPanelProps) {
// const [showAIAnalysis, setShowAIAnalysis] = useState(false); // Reserved for AI analysis feature
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [showAIAnalysis, setShowAIAnalysis] = useState(false); // Reserved for AI analysis feature
const [aiInsights, setAiInsights] = useState<CheckItem[]>([]);
const [isAnalyzingAI, setIsAnalyzingAI] = useState(false);
const [combinedChecks, setCombinedChecks] = useState<CheckItem[]>([]);
@@ -268,7 +269,7 @@ export default function ControlPanel({
}
}
})
.catch(error => {
.catch((error: any) => {
console.error('AI analysis error:', error);
// Remove loading tiles on error
setCombinedChecks(prev => prev.filter(c => !(c as any).isLoading));
@@ -1,4 +1,3 @@
/* eslint-disable @stylistic/array-element-newline */
"use client";
import initCanvas from "@/utils/init-canvas";
@@ -1,4 +1,3 @@
/* eslint-disable @stylistic/array-element-newline */
"use client";
import { animate } from "motion";
@@ -1,4 +1,3 @@
//@ts-nocheck
import { animate, AnimatePresence, cubicBezier, motion } from "motion/react";
import { useEffect, useRef, useState } from "react";
@@ -13,7 +12,7 @@ export default function HeroInputTabsMobile(props: {
}) {
// Filter tabs based on allowedModes if provided
const visibleTabs = props.allowedModes
? tabs.filter((tab) => props.allowedModes.includes(tab.value))
? tabs.filter((tab) => props.allowedModes!.includes(tab.value))
: tabs;
const activeTab = visibleTabs.find((tab) => tab.value === props.tab)!;
@@ -129,7 +129,7 @@ const tickAscii: Ticker = async ({ app, canvas }) => {
let i = 0;
//@ts-ignore
//@ts-expect-error - safeAdd method exists on extended ticker
app.ticker.safeAdd(() => {
i++;
if (i >= sprites.length) i = 0;
@@ -1,4 +1,3 @@
//@ts-nocheck
import { AnimationOptions, cubicBezier } from "motion";
import { Application, Container, Graphics, Sprite } from "pixi.js";
@@ -94,11 +93,11 @@ export default function AnimatedRect(props: Props) {
},
render,
animate: (renderProps: Partial<Props>, settings?: AnimationOptions) =>
props.app.animate(p, renderProps, {
(props.app as any).animate(p, renderProps, {
...p.animationConfig,
...settings,
onUpdate: render,
}),
reset: () => props.app.animate(p, props, { onUpdate: render }),
reset: () => (props.app as any).animate(p, props, { onUpdate: render }),
};
}
@@ -1,4 +1,3 @@
//@ts-nocheck
import { Application, Graphics } from "pixi.js";
@@ -58,22 +57,22 @@ export default function BlinkingContainer({
animatedRect.animate({ scale: 1 });
},
blink: ({ delay = 0 }: { delay?: number } = {}) => {
app
(app as any)
.animate(0, 0.32, {
repeatType: "reverse",
repeat: 2,
delay,
duration: 0.065,
ease: "linear",
onUpdate: (value) => {
onUpdate: (value: any) => {
blinkLayer.alpha = value as number;
},
})
.then(() => {
app.animate(0.32, 0, {
(app as any).animate(0.32, 0, {
duration: 0.065,
ease: "linear",
onUpdate: (value) => {
onUpdate: (value: any) => {
blinkLayer.alpha = value as number;
},
});
+9 -10
View File
@@ -1,8 +1,7 @@
"use client";
import { useState } from "react";
import Globe from "@/components/app/(home)/sections/hero-input/_svg/Globe";
import HeroInputSubmitButton from "@/components/app/(home)/sections/hero-input/Button/Button";
import Link from "next/link";
interface SidebarInputProps {
onSubmit: (url: string, style: string, model: string, instructions?: string) => void;
@@ -16,12 +15,12 @@ export default function SidebarInput({ onSubmit, disabled = false }: SidebarInpu
const [additionalInstructions, setAdditionalInstructions] = useState<string>("");
const [isValidUrl, setIsValidUrl] = useState<boolean>(false);
// Simple URL validation
const validateUrl = (urlString: string) => {
if (!urlString) return false;
const urlPattern = /^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/;
return urlPattern.test(urlString.toLowerCase());
};
// Simple URL validation - currently unused but keeping for future use
// const validateUrl = (urlString: string) => {
// if (!urlString) return false;
// const urlPattern = /^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/;
// return urlPattern.test(urlString.toLowerCase());
// };
const styles = [
{ id: "1", name: "Glassmorphism", description: "Frosted glass effect" },
@@ -58,11 +57,11 @@ export default function SidebarInput({ onSubmit, disabled = false }: SidebarInpu
<div >
<div className="p-4 border-b border-gray-100">
{/* link to home page with button */}
<a href="/">
<Link href="/">
<button className="w-full px-3 py-2 text-xs font-medium text-gray-700 bg-white rounded border border-gray-200 focus:border-orange-500 focus:outline-none focus:ring-1 focus:ring-orange-500">
Generate a new website
</button>
</a>
</Link>
</div>
{/* Options Section - Show when valid URL */}
+2 -4
View File
@@ -90,10 +90,9 @@ export const SlateButton = React.forwardRef<
(React.isValidElement(Icon) ? (
Icon
) : (
//@ts-ignore
//@ts-expect-error - Icon component type allows JSX element
<Icon
className={cn(iconSizes[size], "flex-shrink-0")}
// @ts-ignore - Some icons support isHovered and isOpen
isHovered={isHovered}
isOpen={isOpen}
/>
@@ -104,10 +103,9 @@ export const SlateButton = React.forwardRef<
(React.isValidElement(Icon) ? (
Icon
) : (
//@ts-ignore
//@ts-expect-error - Icon component type allows JSX element
<Icon
className={cn(iconSizes[size], "flex-shrink-0")}
// @ts-ignore - Some icons support isHovered and isOpen
isHovered={isHovered}
isOpen={isOpen}
/>
@@ -1,4 +1,3 @@
// @ts-nocheck
"use client";
import { AnimatePresence, cubicBezier, motion } from "motion/react";
+1 -1
View File
@@ -70,7 +70,7 @@ interface HeroFlameProps {
export function HeroFlame({ className, size = "medium" }: HeroFlameProps) {
const [frameIndex, setFrameIndex] = useState(0);
const intervalRef = useRef<NodeJS.Timeout>();
const intervalRef = useRef<NodeJS.Timeout | null>(null);
useEffect(() => {
intervalRef.current = setInterval(() => {
+6 -2
View File
@@ -39,7 +39,7 @@ const pathVariants: Variants = {
// Higher-order component for icon animation
const withIconAnimation = (IconComponent: React.ComponentType<any>) => {
return ({
const AnimatedIcon = ({
isHovered = false,
className,
...props
@@ -63,11 +63,13 @@ const withIconAnimation = (IconComponent: React.ComponentType<any>) => {
</div>
);
};
AnimatedIcon.displayName = `Animated${IconComponent.displayName || IconComponent.name || 'Icon'}`;
return AnimatedIcon;
};
// Higher-order component for icon animation
const withChartIconAnimation = (IconComponent: React.ComponentType<any>) => {
return ({
const AnimatedChartIcon = ({
isHovered = false,
className,
...props
@@ -113,6 +115,8 @@ const withChartIconAnimation = (IconComponent: React.ComponentType<any>) => {
</div>
);
};
AnimatedChartIcon.displayName = `AnimatedChart${IconComponent.displayName || IconComponent.name || 'Icon'}`;
return AnimatedChartIcon;
};
// Base icon components
@@ -14,10 +14,10 @@ export default function LivePreviewFrame({
const imgRef = useRef<HTMLImageElement>(null);
const containerRef = useRef<HTMLDivElement>(null);
const wsRef = useRef<WebSocket | null>(null);
const reconnectTimeoutRef = useRef<NodeJS.Timeout>();
const reconnectTimeoutRef = useRef<NodeJS.Timeout | null>(null);
const initialPositionSetRef = useRef(false);
const idleStartTimerRef = useRef<NodeJS.Timeout>();
const idleMoveTimerRef = useRef<NodeJS.Timeout>();
const idleStartTimerRef = useRef<NodeJS.Timeout | null>(null);
const idleMoveTimerRef = useRef<NodeJS.Timeout | null>(null);
const [imageLoaded, setImageLoaded] = useState(false);
const [isConnecting, setIsConnecting] = useState(true);
const [cursorPosition, setCursorPosition] = useState<{
@@ -83,7 +83,7 @@ export default function LivePreviewFrame({
// Only start the idle timer if not already idle and no timer is running
idleStartTimerRef.current = setTimeout(() => {
setIsIdle(true);
idleStartTimerRef.current = undefined; // Clear ref after timer runs
idleStartTimerRef.current = null; // Clear ref after timer runs
}, 5000);
}
if (animationFrameId) {
@@ -96,7 +96,7 @@ export default function LivePreviewFrame({
// If we were waiting to go idle, cancel it because we're moving again
if (idleStartTimerRef.current) {
clearTimeout(idleStartTimerRef.current);
idleStartTimerRef.current = undefined;
idleStartTimerRef.current = null;
}
// Ensure idle state is false if we are moving significantly
if (isIdle) setIsIdle(false);
@@ -127,7 +127,7 @@ export default function LivePreviewFrame({
const cleanupConnection = () => {
if (reconnectTimeoutRef.current) {
clearTimeout(reconnectTimeoutRef.current);
reconnectTimeoutRef.current = undefined;
reconnectTimeoutRef.current = null;
}
if (wsRef.current) {
wsRef.current.close();
@@ -171,7 +171,7 @@ export default function LivePreviewFrame({
// Clear any pending reconnection attempts
if (reconnectTimeoutRef.current) {
clearTimeout(reconnectTimeoutRef.current);
reconnectTimeoutRef.current = undefined;
reconnectTimeoutRef.current = null;
}
});
@@ -197,7 +197,7 @@ export default function LivePreviewFrame({
// --- Interrupt Idle State ---
if (idleStartTimerRef.current) {
clearTimeout(idleStartTimerRef.current);
idleStartTimerRef.current = undefined;
idleStartTimerRef.current = null;
}
if (isIdle) {
setIsIdle(false);
+17
View File
@@ -0,0 +1,17 @@
import React from 'react';
interface CodeProps {
code: string;
language?: string;
className?: string;
}
export default function Code({ code, language = 'json', className = '' }: CodeProps) {
return (
<pre className={`overflow-auto ${className}`}>
<code className={`language-${language}`}>
{code}
</code>
</pre>
);
}
+48
View File
@@ -0,0 +1,48 @@
import React, { useEffect, useState } from 'react';
interface ScrambleTextProps {
text: string;
className?: string;
duration?: number;
delay?: number;
isInView?: boolean;
}
export default function ScrambleText({ text, className = '', duration = 1, delay = 0, isInView = true }: ScrambleTextProps) {
const [displayText, setDisplayText] = useState(text);
const [isScrambling, setIsScrambling] = useState(false);
useEffect(() => {
if (isScrambling) {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
const durationMs = duration * 1000; // Convert seconds to milliseconds
const interval = setInterval(() => {
setDisplayText(
text
.split('')
.map((char) => (Math.random() > 0.5 ? chars[Math.floor(Math.random() * chars.length)] : char))
.join('')
);
}, 50);
setTimeout(() => {
clearInterval(interval);
setDisplayText(text);
setIsScrambling(false);
}, durationMs);
return () => clearInterval(interval);
}
}, [text, isScrambling, duration]);
useEffect(() => {
if (isInView) {
const timeout = setTimeout(() => {
setIsScrambling(true);
}, delay);
return () => clearTimeout(timeout);
}
}, [text, delay, isInView]);
return <span className={className}>{displayText}</span>;
}
+3 -3
View File
@@ -4,7 +4,7 @@ import * as React from "react";
import * as SwitchPrimitives from "@radix-ui/react-switch";
import { cva, type VariantProps } from "class-variance-authority";
import { cx } from "@/lib/app/utils";
import { cn } from "@/utils/cn";
const switchVariants = cva(
"peer inline-flex shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-muted-foreground data-[state=unchecked]:bg-input",
@@ -46,11 +46,11 @@ const Switch = React.forwardRef<
SwitchProps
>(({ className, size, ...props }, ref) => (
<SwitchPrimitives.Root
className={cx(switchVariants({ size, className }))}
className={cn(switchVariants({ size, className }))}
{...props}
ref={ref}
>
<SwitchPrimitives.Thumb className={cx(thumbVariants({ size }))} />
<SwitchPrimitives.Thumb className={cn(thumbVariants({ size }))} />
</SwitchPrimitives.Root>
));
Switch.displayName = SwitchPrimitives.Root.displayName;
+48
View File
@@ -0,0 +1,48 @@
import React from 'react';
interface SpinnerProps {
className?: string;
size?: 'sm' | 'md' | 'lg';
finished?: boolean;
}
export default function Spinner({ className = '', size = 'md', finished = false }: SpinnerProps) {
if (finished) {
// Return a checkmark or completed state
return (
<div className={`${className}`}>
</div>
);
}
const sizeClasses = {
sm: 'h-4 w-4',
md: 'h-6 w-6',
lg: 'h-8 w-8'
};
return (
<div className={`${sizeClasses[size]} ${className}`}>
<svg
className="animate-spin"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle
className="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="4"
/>
<path
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
/>
</svg>
</div>
);
}