mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-23 08:11:33 +11:00
pixel perfect scaling even on high density screens
This commit is contained in:
parent
1991fbf056
commit
917d7b3d5a
|
@ -1,6 +1,6 @@
|
|||
import type { Metadata } from "next";
|
||||
import "./globalStyles.css";
|
||||
import StyledComponentsRegistry from "./registry";
|
||||
import StyledComponentsRegistry, { BodyPixelRatio } from "./registry";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "agb - a rust framework for making Game Boy Advance games",
|
||||
|
@ -13,9 +13,9 @@ export default function RootLayout({
|
|||
}>) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>
|
||||
<BodyPixelRatio>
|
||||
<StyledComponentsRegistry>{children}</StyledComponentsRegistry>
|
||||
</body>
|
||||
</BodyPixelRatio>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@ import { ExternalLink } from "@/components/externalLink";
|
|||
|
||||
const HelpLinks = styled.div`
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16px;
|
||||
justify-content: space-around;
|
||||
`;
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
"use client";
|
||||
|
||||
import React, { useState } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useServerInsertedHTML } from "next/navigation";
|
||||
import { ServerStyleSheet, StyleSheetManager } from "styled-components";
|
||||
import styled, { ServerStyleSheet, StyleSheetManager } from "styled-components";
|
||||
|
||||
export default function StyledComponentsRegistry({
|
||||
children,
|
||||
|
@ -27,3 +27,18 @@ export default function StyledComponentsRegistry({
|
|||
</StyleSheetManager>
|
||||
);
|
||||
}
|
||||
|
||||
const BodyWithPixelRatio = styled.body<{
|
||||
$pixel?: number;
|
||||
}>`
|
||||
--device-pixel: calc(1px / ${(props) => props.$pixel});
|
||||
`;
|
||||
|
||||
export function BodyPixelRatio({ children }: { children: React.ReactNode }) {
|
||||
const [pixel, setPixel] = useState(1);
|
||||
useEffect(() => {
|
||||
setPixel(window.devicePixelRatio);
|
||||
}, []);
|
||||
|
||||
return <BodyWithPixelRatio $pixel={pixel}>{children}</BodyWithPixelRatio>;
|
||||
}
|
||||
|
|
|
@ -3,13 +3,11 @@ import { Games, ShowcaseGame } from "../games";
|
|||
import { ContentBlock } from "@/components/contentBlock";
|
||||
import { ExternalLink } from "@/components/externalLink";
|
||||
import Link from "next/link";
|
||||
import Image, { StaticImageData } from "next/image";
|
||||
import {
|
||||
ScreenshotsWrapper,
|
||||
ScreenshotWrapper,
|
||||
BackToShowcaseWrapper,
|
||||
DescriptionAndScreenshots,
|
||||
Description,
|
||||
Screenshots,
|
||||
} from "./styled";
|
||||
|
||||
export async function generateStaticParams() {
|
||||
|
@ -51,18 +49,6 @@ function DeveloperNames({ names }: { names: string[] }) {
|
|||
return first.join(", ") + `, and ${names[names.length - 1]}`;
|
||||
}
|
||||
|
||||
function Screenshots({ screenshots }: { screenshots: StaticImageData[] }) {
|
||||
return (
|
||||
<ScreenshotsWrapper>
|
||||
{screenshots.map((screenshot) => (
|
||||
<ScreenshotWrapper key={screenshot.src}>
|
||||
<Image src={screenshot} alt="" />
|
||||
</ScreenshotWrapper>
|
||||
))}
|
||||
</ScreenshotsWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
function Display({ game }: { game: ShowcaseGame }) {
|
||||
return (
|
||||
<>
|
||||
|
|
|
@ -1,19 +1,35 @@
|
|||
"use client";
|
||||
|
||||
import { styled } from "styled-components";
|
||||
import Image, { StaticImageData } from "next/image";
|
||||
|
||||
export const ScreenshotsWrapper = styled.div`
|
||||
export function Screenshots({
|
||||
screenshots,
|
||||
}: {
|
||||
screenshots: StaticImageData[];
|
||||
}) {
|
||||
return (
|
||||
<ScreenshotsWrapper>
|
||||
{screenshots.map((screenshot) => (
|
||||
<Screenshot src={screenshot} alt="" key={screenshot.src} />
|
||||
))}
|
||||
</ScreenshotsWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
const ScreenshotsWrapper = styled.div`
|
||||
flex: 4;
|
||||
text-align: center;
|
||||
`;
|
||||
|
||||
export const ScreenshotWrapper = styled.div`
|
||||
text-align: center;
|
||||
img {
|
||||
const Screenshot = styled(Image)`
|
||||
width: 100%;
|
||||
width: round(down, 100%, 240px);
|
||||
width: max(
|
||||
round(down, 100%, calc(240 * var(--device-pixel))),
|
||||
calc(240 * var(--device-pixel))
|
||||
);
|
||||
height: auto;
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
`;
|
||||
|
||||
export const Description = styled.div`
|
||||
|
@ -26,6 +42,10 @@ export const Description = styled.div`
|
|||
export const DescriptionAndScreenshots = styled.div`
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
|
||||
@media (max-width: 1000px) {
|
||||
display: block;
|
||||
}
|
||||
`;
|
||||
|
||||
export const BackToShowcaseWrapper = styled.div`
|
||||
|
|
|
@ -6,20 +6,23 @@ import Image from "next/image";
|
|||
|
||||
export const GameGrid = styled.div`
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, 600px);
|
||||
grid-template-columns: repeat(auto-fit, min(100vw, 600px));
|
||||
justify-content: center;
|
||||
gap: 48px;
|
||||
`;
|
||||
|
||||
export const GameImage = styled(Image)`
|
||||
width: 100%;
|
||||
width: round(down, 100%, 240px);
|
||||
width: max(
|
||||
round(down, 100%, calc(240 * var(--device-pixel))),
|
||||
min(calc(240 * var(--device-pixel)), 100vw)
|
||||
);
|
||||
height: auto;
|
||||
image-rendering: pixelated;
|
||||
`;
|
||||
|
||||
export const GameDisplay = styled(Link)`
|
||||
width: 600px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
|
|
|
@ -14,11 +14,8 @@ const Section = styled.section<{ $color: string }>`
|
|||
const CENTERED_CSS = `
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
max-width: 60%;
|
||||
|
||||
@media (max-width: 40rem) {
|
||||
max-width: 90%;
|
||||
}
|
||||
width: 60%;
|
||||
min-width: min(95%, 1000px);
|
||||
`;
|
||||
|
||||
export const CenteredBlock = styled.div`
|
||||
|
|
Loading…
Reference in a new issue