Skip to content
23 changes: 16 additions & 7 deletions src/app/compatibility/avm.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"use client";

import classes from "./avm.module.css";
import {
Button,
Expand All @@ -9,6 +11,7 @@ import {
Title,
} from "@mantine/core";
import Link from "next/link";
import { useTranslation } from "@/app/translate";

interface AvmProgressProps {
done: number;
Expand All @@ -21,25 +24,26 @@ interface AvmProgressPropsFull extends AvmProgressProps {
}

function AvmProgress(props: AvmProgressPropsFull) {
const { t } = useTranslation();
return (
<Group align="center" justify="spread-between" mt={props.mt}>
<Text size="sm" className={classes.progressName}>
{props.name}: {props.done}%
{t(props.name)}: {props.done}%
</Text>
<ProgressRoot size="xl" radius={10} className={classes.progress}>
<ProgressSection
striped
value={props.done}
color="var(--mantine-color-green-9)"
title={`${props.done}% done`}
title={`${props.done}% ${t("compatibility.done")}`}
></ProgressSection>
{props.stubbed && (
<ProgressSection
striped
value={props.stubbed}
color="ruffle-orange"
className={classes.stub}
title={`${props.stubbed}% partially done`}
title={`${props.stubbed}% ${t("compatibility.partial")}`}
></ProgressSection>
)}
</ProgressRoot>
Expand All @@ -57,25 +61,30 @@ interface AvmBlockProps {
}

export function AvmBlock(props: AvmBlockProps) {
const { t } = useTranslation();
return (
<Stack className={classes.avm}>
<Group justify="space-between">
<Title order={2}>{props.name}</Title>
<Title order={2}>{t(props.name)}</Title>
<Button
component={Link}
href={props.info_link}
target={props.info_link_target}
size="compact-md"
color="var(--ruffle-blue-7)"
>
More Info
{t("compatibility.more")}
</Button>
</Group>

{props.children}

<AvmProgress name="Language" mt="auto" {...props.language} />
<AvmProgress name="API" {...props.api} />
<AvmProgress
name="compatibility.language"
mt="auto"
{...props.language}
/>
<AvmProgress name="compatibility.api" {...props.api} />
</Stack>
);
}
17 changes: 12 additions & 5 deletions src/app/compatibility/avm2/class_box.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ import classes from "./avm2.module.css";
import React from "react";
import {
ClassStatus,
ProgressIcon,
displayedPercentage,
} from "@/app/compatibility/avm2/report_utils";
import { ProgressIcon } from "@/app/compatibility/avm2/icons";
import { useTranslation } from "@/app/translate";

export function ClassBox(props: ClassStatus) {
const { t } = useTranslation();
const [opened, { toggle }] = useDisclosure(false);
const pctDone = displayedPercentage(
props.summary.impl_points - props.summary.stub_penalty,
Expand All @@ -33,21 +35,23 @@ export function ClassBox(props: ClassStatus) {
);
return (
<Card bg="var(--ruffle-blue-9)" className={classes.class}>
<Title order={4}>{props.name || "(Package level)"}</Title>
<Title order={4}>
{props.name || t("compatibility.avm2.package-level")}
</Title>
<ProgressRoot size="xl" radius={10} className={classes.progress}>
<ProgressSection
striped
value={pctDone}
color="var(--mantine-color-green-9)"
title={`${pctDone}% done`}
title={`${pctDone}% ${t("compatibility.done")}`}
></ProgressSection>
{pctStub > 0 && (
<ProgressSection
striped
value={pctStub}
color="ruffle-orange"
className={classes.progressStub}
title={`${pctStub}% partially done`}
title={`${pctStub}% ${t("compatibility.partial")}`}
></ProgressSection>
)}
</ProgressRoot>
Expand All @@ -58,7 +62,10 @@ export function ClassBox(props: ClassStatus) {
className={classes.showMemberButton}
onClick={toggle}
>
{opened ? "Hide" : "Show"} Missing Members
{opened
? t("compatibility.avm2.hide")
: t("compatibility.avm2.show")}{" "}
{t("compatibility.avm2.missing-members")}
</Button>
<List hidden={!opened}>
{props.items.map((item, i) => (
Expand Down
65 changes: 65 additions & 0 deletions src/app/compatibility/avm2/icons.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"use client";

import { rem, ThemeIcon } from "@mantine/core";
import { IconCheck, IconProgress, IconX } from "@tabler/icons-react";
import { useTranslation } from "@/app/translate";

export function IconDone() {
const { t } = useTranslation();
return (
<ThemeIcon
size={20}
radius="xl"
color="var(--mantine-color-green-9)"
title={t("compatibility.avm2.done")}
>
<IconCheck
color="white"
style={{ width: rem(12), height: rem(12) }}
stroke={4}
/>
</ThemeIcon>
);
}

export function IconStub() {
const { t } = useTranslation();
return (
<ThemeIcon size={20} radius="xl" title={t("compatibility.avm2.partial")}>
<IconProgress
color="#3c1518"
style={{ width: rem(12), height: rem(12) }}
stroke={4}
/>
</ThemeIcon>
);
}

export function IconMissing() {
const { t } = useTranslation();
return (
<ThemeIcon
size={20}
radius="xl"
color="#3c1518"
title={t("compatibility.avm2.missing")}
>
<IconX
color="white"
style={{ width: rem(12), height: rem(12) }}
stroke={4}
/>
</ThemeIcon>
);
}

export function ProgressIcon(type: "stub" | "missing" | "done") {
switch (type) {
case "stub":
return <IconStub />;
case "missing":
return <IconMissing />;
case "done":
return <IconDone />;
}
}
97 changes: 63 additions & 34 deletions src/app/compatibility/avm2/page.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"use client";

import {
Container,
Group,
Expand All @@ -8,22 +10,26 @@ import {
Title,
} from "@mantine/core";
import Image from "next/image";
import React from "react";
import React, { useEffect, useState } from "react";
import classes from "./avm2.module.css";
import { ClassBox } from "@/app/compatibility/avm2/class_box";
import {
getReportByNamespace,
NamespaceStatus,
} from "@/app/compatibility/avm2/report_utils";
import {
IconDone,
IconMissing,
IconStub,
NamespaceStatus,
} from "@/app/compatibility/avm2/report_utils";
} from "@/app/compatibility/avm2/icons";
import Link from "next/link";
import { useTranslation, Trans } from "@/app/translate";

function NamespaceBox(props: NamespaceStatus) {
const { t } = useTranslation();
return (
<Stack className={classes.namespace}>
<Title order={2}>{props.name || "(Top Level)"}</Title>
<Title order={2}>{props.name || t("compatibility.avm2.top-level")}</Title>
<Group align="baseline">
{Object.entries(props.classes).map(([classname, classinfo]) => (
<ClassBox key={classname} {...classinfo} />
Expand All @@ -33,8 +39,22 @@ function NamespaceBox(props: NamespaceStatus) {
);
}

export default async function Page() {
const byNamespace = await getReportByNamespace();
export default function Page() {
const { t } = useTranslation();
const [byNamespace, setByNamespace] = useState<
{ [name: string]: NamespaceStatus } | undefined
>(undefined);
useEffect(() => {
const fetchData = async () => {
try {
const byNamespace = await getReportByNamespace();
setByNamespace(byNamespace);
} catch (error) {
console.error("Error fetching data", error);
}
};
fetchData();
}, []);
return (
<Container size="xl">
<Stack gap="xl">
Expand All @@ -48,43 +68,52 @@ export default async function Page() {
className={classes.progressImage}
/>
<Stack className={classes.actionscriptInfo}>
<Title className={classes.title}>ActionScript 3 API Progress</Title>
<Text>
ActionScript 3 contains many different methods and classes - not
all of which is ultimately <i>useful</i> to every application. The
majority of content only uses a small portion of the available
API, so even if we aren&apos;t 100% &quot;complete&quot; across
the entirely of AVM 2, we may have enough for that content to run
completely fine.
</Text>
<Text>
On this page, we list every single ActionScript 3 API that exists
but Ruffle does not yet 100% implement. We classify items into
three different stages:
</Text>
<Title className={classes.title}>
{t("compatibility.avm2.title")}
</Title>
<Text>{t("compatibility.avm2.description")}</Text>
<Text>{t("compatibility.avm2.classification")}</Text>
<List spacing="sm">
<ListItem icon={<IconDone />}>
<b>Implemented</b> items are marked as &quot;Done&quot;, and we
believe they are fully functional. For brevity, we do not list
completed items on this page.
<Trans
i18nKey="compatibility.avm2.implemented-description"
components={[
<b key="implemented">
{t("compatibility.avm2.implemented")}
</b>,
]}
/>
</ListItem>
<ListItem icon={<IconStub />}>
<b>Partial</b> items exist and are enough for most content to
work, but are incomplete. A partial class may be missing items,
or a method may just simply return a value without performing
its intended function.
<Trans
i18nKey="compatibility.avm2.partial-description"
components={[
<b key="partial">{t("compatibility.avm2.partial")}</b>,
]}
/>
</ListItem>
<ListItem icon={<IconMissing />}>
<b>Missing</b> items do not exist at all in Ruffle yet, and
trying to use them will give an error.
<Trans
i18nKey="compatibility.avm2.missing-description"
components={[
<b key="missing">{t("compatibility.avm2.missing")}</b>,
]}
/>
</ListItem>
</List>
<Text>
You can also visualize the progress{" "}
<Link href="/compatibility/avm2/tree.svg" target="_blank">
as a tree graph
</Link>
.
<Trans
i18nKey="compatibility.avm2.tree"
components={[
<Link
key="link"
href="/compatibility/avm2/tree.svg"
target="_blank"
>
{t("compatibility.avm2.tree-link")}
</Link>,
]}
/>
</Text>
</Stack>
</Group>
Expand Down
Loading