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 type { Metadata } from "next";
|
||||||
import "./globalStyles.css";
|
import "./globalStyles.css";
|
||||||
import StyledComponentsRegistry from "./registry";
|
import StyledComponentsRegistry, { BodyPixelRatio } from "./registry";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "agb - a rust framework for making Game Boy Advance games",
|
title: "agb - a rust framework for making Game Boy Advance games",
|
||||||
|
@ -13,9 +13,9 @@ export default function RootLayout({
|
||||||
}>) {
|
}>) {
|
||||||
return (
|
return (
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<body>
|
<BodyPixelRatio>
|
||||||
<StyledComponentsRegistry>{children}</StyledComponentsRegistry>
|
<StyledComponentsRegistry>{children}</StyledComponentsRegistry>
|
||||||
</body>
|
</BodyPixelRatio>
|
||||||
</html>
|
</html>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,8 @@ import { ExternalLink } from "@/components/externalLink";
|
||||||
|
|
||||||
const HelpLinks = styled.div`
|
const HelpLinks = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 16px;
|
||||||
justify-content: space-around;
|
justify-content: space-around;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import React, { useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { useServerInsertedHTML } from "next/navigation";
|
import { useServerInsertedHTML } from "next/navigation";
|
||||||
import { ServerStyleSheet, StyleSheetManager } from "styled-components";
|
import styled, { ServerStyleSheet, StyleSheetManager } from "styled-components";
|
||||||
|
|
||||||
export default function StyledComponentsRegistry({
|
export default function StyledComponentsRegistry({
|
||||||
children,
|
children,
|
||||||
|
@ -27,3 +27,18 @@ export default function StyledComponentsRegistry({
|
||||||
</StyleSheetManager>
|
</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 { ContentBlock } from "@/components/contentBlock";
|
||||||
import { ExternalLink } from "@/components/externalLink";
|
import { ExternalLink } from "@/components/externalLink";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import Image, { StaticImageData } from "next/image";
|
|
||||||
import {
|
import {
|
||||||
ScreenshotsWrapper,
|
|
||||||
ScreenshotWrapper,
|
|
||||||
BackToShowcaseWrapper,
|
BackToShowcaseWrapper,
|
||||||
DescriptionAndScreenshots,
|
DescriptionAndScreenshots,
|
||||||
Description,
|
Description,
|
||||||
|
Screenshots,
|
||||||
} from "./styled";
|
} from "./styled";
|
||||||
|
|
||||||
export async function generateStaticParams() {
|
export async function generateStaticParams() {
|
||||||
|
@ -51,18 +49,6 @@ function DeveloperNames({ names }: { names: string[] }) {
|
||||||
return first.join(", ") + `, and ${names[names.length - 1]}`;
|
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 }) {
|
function Display({ game }: { game: ShowcaseGame }) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -1,19 +1,35 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { styled } from "styled-components";
|
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;
|
flex: 4;
|
||||||
|
text-align: center;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const ScreenshotWrapper = styled.div`
|
const Screenshot = styled(Image)`
|
||||||
text-align: center;
|
width: 100%;
|
||||||
img {
|
width: max(
|
||||||
width: 100%;
|
round(down, 100%, calc(240 * var(--device-pixel))),
|
||||||
width: round(down, 100%, 240px);
|
calc(240 * var(--device-pixel))
|
||||||
height: auto;
|
);
|
||||||
image-rendering: pixelated;
|
height: auto;
|
||||||
}
|
image-rendering: pixelated;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const Description = styled.div`
|
export const Description = styled.div`
|
||||||
|
@ -26,6 +42,10 @@ export const Description = styled.div`
|
||||||
export const DescriptionAndScreenshots = styled.div`
|
export const DescriptionAndScreenshots = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
|
|
||||||
|
@media (max-width: 1000px) {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const BackToShowcaseWrapper = styled.div`
|
export const BackToShowcaseWrapper = styled.div`
|
||||||
|
|
|
@ -6,20 +6,23 @@ import Image from "next/image";
|
||||||
|
|
||||||
export const GameGrid = styled.div`
|
export const GameGrid = styled.div`
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fit, 600px);
|
grid-template-columns: repeat(auto-fit, min(100vw, 600px));
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 48px;
|
gap: 48px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const GameImage = styled(Image)`
|
export const GameImage = styled(Image)`
|
||||||
width: 100%;
|
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;
|
height: auto;
|
||||||
image-rendering: pixelated;
|
image-rendering: pixelated;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const GameDisplay = styled(Link)`
|
export const GameDisplay = styled(Link)`
|
||||||
width: 600px;
|
width: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: black;
|
color: black;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
|
|
@ -14,11 +14,8 @@ const Section = styled.section<{ $color: string }>`
|
||||||
const CENTERED_CSS = `
|
const CENTERED_CSS = `
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
max-width: 60%;
|
width: 60%;
|
||||||
|
min-width: min(95%, 1000px);
|
||||||
@media (max-width: 40rem) {
|
|
||||||
max-width: 90%;
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const CenteredBlock = styled.div`
|
export const CenteredBlock = styled.div`
|
||||||
|
|
Loading…
Reference in a new issue