Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 59 additions & 2 deletions src/elements/components/carousel/comparison.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const ImageComparison = ({ image }: ImageComparisonProps) => {
scale: 1,
});
const prevTransformStateRef = useRef(transformState);
const imagesLoadedRef = useRef({ lr: false, sr: false });

useEffect(() => {
const prevTransformState = prevTransformStateRef.current;
Expand All @@ -38,11 +39,66 @@ export const ImageComparison = ({ image }: ImageComparisonProps) => {
}, [transformState]);

useEffect(() => {
lrRef.current?.centerView(1, 0);
srRef.current?.centerView(1, 0);
// Reset transform state when image changes
setTransformState({
positionX: 0,
positionY: 0,
scale: 1,
});
// Reset image load tracking
imagesLoadedRef.current = { lr: false, sr: false };
setHandlePosition(50);
}, [image]);

// Track image loading and center images once loaded
useEffect(() => {
// Center images function
const centerImages = () => {
if (lrRef.current && srRef.current) {
// Use requestAnimationFrame to ensure DOM is updated
requestAnimationFrame(() => {
lrRef.current?.centerView(1, 0);
srRef.current?.centerView(1, 0);
});
}
};

const lrImg = new Image();
const srImg = new Image();
let loadedCount = 0;

const checkAndCenter = () => {
loadedCount++;
if (loadedCount === 2) {
// Both images loaded, center them
setTimeout(() => {
centerImages();
}, 50); // Small delay to ensure DOM is ready
}
};

lrImg.onload = () => {
imagesLoadedRef.current.lr = true;
checkAndCenter();
};
srImg.onload = () => {
imagesLoadedRef.current.sr = true;
checkAndCenter();
};

lrImg.src = image.LR;
srImg.src = image.SR;

// Fallback: center after a timeout even if images don't load
const fallbackTimer = setTimeout(() => {
centerImages();
}, 500);

return () => {
clearTimeout(fallbackTimer);
};
}, [image]);

return (
<ReactCompareSlider
onlyHandleDraggable
Expand Down Expand Up @@ -137,6 +193,7 @@ export const ImageComparison = ({ image }: ImageComparisonProps) => {
</TransformComponent>
</TransformWrapper>
}
key={`${image.LR}-${image.SR}`}
position={handlePosition}
onPositionChange={setHandlePosition}
/>
Expand Down
11 changes: 11 additions & 0 deletions src/elements/components/image-carousel.module.scss
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
.imageWrapper {
height: 350px;

@media screen and (min-width: 768px) {
height: 450px;
}

@media screen and (min-width: 1024px) {
height: 500px;
}

@media screen and (max-width: 1023px) {
border-radius: 0;
margin: -1rem 0 0 -1rem;
width: calc(100% + 2rem);
height: 300px;
}
}
2 changes: 1 addition & 1 deletion src/elements/components/image-carousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export const ImageCarousel = ({ images, readonly, indexKey, onChange }: ImageCar
return (
<div className="relative w-full">
<div
className={`${style.imageWrapper} flex h-96 w-full overflow-hidden rounded-lg bg-fade-100 align-middle dark:bg-fade-800`}
className={`${style.imageWrapper} flex w-full overflow-hidden rounded-lg bg-fade-100 align-middle dark:bg-fade-800`}
>
{selectedImage ? (
<ImageCarouselImage image={selectedImage} />
Expand Down
18 changes: 17 additions & 1 deletion src/elements/components/model-card.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,28 @@
border-radius: 0.5rem;
border-width: 1px;
border-style: solid;
transition: transform 0.3s ease, box-shadow 0.3s ease;
z-index: 1;

--inner-radius: calc(0.5rem - 1px);

&:hover {
transform: scale(1.02);
z-index: 10;
}

&.overflowHidden {
--inner-radius: 0;

overflow: hidden;
}

// Ensure popovers can escape the card's bounds when open
&:has([data-headlessui-state='open']) {
overflow: visible;
z-index: 100;
}

.inner {
position: relative;
display: flex;
Expand Down Expand Up @@ -60,6 +73,9 @@
.details {
padding: 0.75rem;
padding-top: 0;
overflow: visible;
position: relative;
z-index: 10;

&.paired {
position: absolute;
Expand All @@ -68,7 +84,7 @@
right: 0;
backdrop-filter: blur(2rem) saturate(2);
border-radius: 0 0 var(--inner-radius) var(--inner-radius);
overflow: hidden;
overflow: visible;

@include themed using($t) {
background: linear-gradient(transparent, t($t, white, $fade-900))
Expand Down
4 changes: 2 additions & 2 deletions src/elements/components/model-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ const useMakeLazyCard = (lazy: boolean, card: JSX.Element) => {
className={joinClasses(
style.modelCard,
!editMode && style.overflowHidden,
'border-gray-300 bg-white shadow-lg hover:shadow-xl dark:border-gray-700 dark:bg-fade-900'
'border-gray-300 bg-white shadow-lg hover:shadow-2xl dark:border-gray-700 dark:bg-fade-900'
)}
>
{card}
Expand All @@ -270,7 +270,7 @@ const useMakeLazyCard = (lazy: boolean, card: JSX.Element) => {
<LazyLoadComponent
placeholder={
<div
className={`${style.modelCard} border-gray-300 bg-white shadow-lg hover:shadow-xl dark:border-gray-700 dark:bg-fade-900`}
className={`${style.modelCard} border-gray-300 bg-white shadow-lg hover:shadow-2xl dark:border-gray-700 dark:bg-fade-900`}
/>
}
>
Expand Down
29 changes: 22 additions & 7 deletions src/pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,33 @@
import { Inter } from 'next/font/google';
import { useEffect } from 'react';
import '../styles/globals.scss';
import 'react-tooltip/dist/react-tooltip.css';
import { DevicePixelRatioProvider } from '../lib/hooks/use-device-pixel-ratio';
import { TooltipProvider } from '../lib/hooks/use-tooltip';
import { WebApiProvider } from '../lib/hooks/use-web-api';
import type { AppProps } from 'next/app';

const inter = Inter({
subsets: ['latin'],
variable: '--font-inter',
display: 'swap',
});

export default function App({ Component, pageProps }: AppProps) {
useEffect(() => {
// Ensure the font variable is available on the root element
document.documentElement.style.setProperty('--font-inter', inter.style.fontFamily);
}, []);

return (
<WebApiProvider>
<DevicePixelRatioProvider>
<TooltipProvider>
<Component {...pageProps} />
</TooltipProvider>
</DevicePixelRatioProvider>
</WebApiProvider>
<div className={inter.variable}>
<WebApiProvider>
<DevicePixelRatioProvider>
<TooltipProvider>
<Component {...pageProps} />
</TooltipProvider>
</DevicePixelRatioProvider>
</WebApiProvider>
</div>
);
}
8 changes: 6 additions & 2 deletions src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,12 @@ export default function Page({ modelData: staticModelData }: Props) {
</p>
</div>

<h1 className="mb-4 text-center text-2xl font-bold capitalize text-accent-500 dark:text-fade-200 md:mb-6 lg:text-3xl">
The best place to find AI Upscaling models
<h1 className="mb-4 text-center text-4xl font-extrabold md:mb-6 md:text-5xl lg:text-6xl">
<span className="text-gray-800 dark:text-gray-100">The best place to find </span>
<span className="bg-gradient-to-r from-accent-400 via-accent-500 to-accent-600 bg-clip-text text-transparent">
AI Upscaling
</span>
<span className="text-gray-800 dark:text-gray-100"> models</span>
</h1>

<p className="mx-auto max-w-screen-md text-center text-gray-600 dark:text-gray-400 md:text-lg">
Expand Down
67 changes: 39 additions & 28 deletions src/pages/models/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -334,26 +334,33 @@ function isTrue<T>(value: T | null | undefined | false | '' | 0): value is T {
}

function MetadataTable({ rows }: { rows: (false | null | undefined | readonly [string, ReactNode])[] }) {
const filteredRows = rows.filter(isTrue);
return (
<table className="w-full border-collapse text-left text-sm text-gray-700 dark:text-gray-400 ">
<tbody>
{rows.filter(isTrue).map((row, i) => {
const [label, value] = row;
const extraPadding = i === 0 ? 'pt-3' : i === rows.length - 1 ? 'pb-3' : '';
return (
<tr key={i}>
<th
className={`${extraPadding} whitespace-nowrap bg-fade-100 px-4 py-2 text-right align-top font-medium text-fade-900 dark:bg-fade-800 dark:text-white`}
scope="row"
<div className="overflow-hidden rounded-lg border border-fade-200 bg-white dark:border-fade-700 dark:bg-fade-900">
<table className="w-full border-collapse text-left text-sm text-gray-700 dark:text-gray-400">
<tbody>
{filteredRows.map((row, i) => {
const [label, value] = row;
const extraPadding = i === 0 ? 'pt-3' : i === filteredRows.length - 1 ? 'pb-3' : '';
const isLastRow = i === filteredRows.length - 1;
return (
<tr
className={!isLastRow ? 'border-b border-fade-200 dark:border-fade-700' : ''}
key={i}
>
{label}
</th>
<td className={`${extraPadding} px-4 py-2`}>{value}</td>
</tr>
);
})}
</tbody>
</table>
<th
className={`${extraPadding} whitespace-nowrap bg-fade-100 px-4 py-2 text-right align-top font-medium text-fade-900 dark:bg-fade-800 dark:text-white`}
scope="row"
>
{label}
</th>
<td className={`${extraPadding} px-4 py-2`}>{value}</td>
</tr>
);
})}
</tbody>
</table>
</div>
);
}
export default function Page({
Expand Down Expand Up @@ -437,16 +444,20 @@ export default function Page({
</Head>
)}
<PageContainer searchBar>
{/* Two columns */}
<div className="grid h-full w-full gap-4 pb-4 sm:grid-cols-1 md:grid-cols-1 lg:grid-cols-3">
{/* Left column */}
{/* Full-width preview at top (YouTube-style) */}
<div className="mb-6 w-full">
<ImageCarousel
images={model.images}
indexKey={modelId}
readonly={!editMode}
onChange={(images) => updateModelProperty('images', images)}
/>
</div>

{/* Two columns: Description and Sidebar */}
<div className="grid h-full w-full gap-6 pb-4 sm:grid-cols-1 lg:grid-cols-3">
{/* Left column: Description */}
<div className="relative flex h-full flex-col gap-4 sm:col-span-1 lg:col-span-2">
<ImageCarousel
images={model.images}
indexKey={modelId}
readonly={!editMode}
onChange={(images) => updateModelProperty('images', images)}
/>
<div className="relative">
<div>
{editMode && (
Expand Down Expand Up @@ -564,7 +575,7 @@ export default function Page({
</div>
</div>
</div>
{/* Right column */}
{/* Right column: Sidebar */}
<div className="col-span-1 w-full">
{/* Download Button */}
<div className="mb-2 flex w-full flex-col gap-2">
Expand Down
8 changes: 4 additions & 4 deletions src/styles/globals.scss
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@
:root {
--max-page-width: 1400px;

--fonts-heading: -apple-system, blinkmacsystemfont, 'Segoe UI', helvetica, arial, sans-serif, 'Apple Color Emoji',
'Segoe UI Emoji', 'Segoe UI Symbol';
--fonts-body: -apple-system, blinkmacsystemfont, 'Segoe UI', helvetica, arial, sans-serif, 'Apple Color Emoji',
'Segoe UI Emoji', 'Segoe UI Symbol';
--fonts-heading: var(--font-inter), -apple-system, blinkmacsystemfont, 'Segoe UI', helvetica, arial, sans-serif,
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
--fonts-body: var(--font-inter), -apple-system, blinkmacsystemfont, 'Segoe UI', helvetica, arial, sans-serif,
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
--fonts-mono: sfmono-regular, menlo, monaco, consolas, 'Liberation Mono', 'Courier New', monospace;

overflow-y: scroll;
Expand Down
11 changes: 11 additions & 0 deletions tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@ module.exports = {
content: ['./src/**/*.{js,ts,jsx,tsx}'],
theme: {
extend: {
fontFamily: {
sans: [
'var(--font-inter)',
'-apple-system',
'BlinkMacSystemFont',
'Segoe UI',
'Helvetica',
'Arial',
'sans-serif',
],
},
colors: {
'fade-50': '#f9f8ff',
'fade-100': '#f3f2fd',
Expand Down