From d35caa6dad761fee635b4eeb1b6a5dc11bf04ef1 Mon Sep 17 00:00:00 2001 From: Try Ajitiono Date: Mon, 9 Feb 2026 20:01:05 +0700 Subject: [PATCH 1/9] feat: init AI contribution --- .claude/skills/contribute/SKILL.md | 41 +++++++++++++++++++++++++++++ .claude/skills/create-plan/SKILL.md | 26 ++++++++++++++++++ .gitignore | 6 ++++- AGENTS.md | 30 +++++++++++++++++++++ CLAUDE.md | 1 + resources/plan.md | 34 ++++++++++++++++++++++++ 6 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 .claude/skills/contribute/SKILL.md create mode 100644 .claude/skills/create-plan/SKILL.md create mode 100644 AGENTS.md create mode 100644 CLAUDE.md create mode 100644 resources/plan.md diff --git a/.claude/skills/contribute/SKILL.md b/.claude/skills/contribute/SKILL.md new file mode 100644 index 0000000..a1e0512 --- /dev/null +++ b/.claude/skills/contribute/SKILL.md @@ -0,0 +1,41 @@ +--- +name: contribute +description: Implement design from a screenshot or a definition. Use model Claude Sonnet 4.5 for this task. +--- + +# Contribute + +## Overview + +Implements a design from a screenshot or a definition in a Extend Apps Directory structure. + +## When to Use + +Use this skill when: + +- You want to contribute to Extend Apps Directory. +- You are not familiar on how to contribute to Extend Apps Directory. + +## Implementation Principles + +1. Always follow semantic HTML. +2. DO NOT SKEW FROM THE DESIGN. Use exactly the same style _per element_. There may be flaws in the design, but it is what it is. +3. DO NOT CREATE ADDITIONAL FILES that are otherwise not required. Focus on the given task at hand. +4. If the prompt specifies a file (or files) that already exists, do not recreate them. +5. When running a code snippet (command line), use the following as terminal preference: + 1. Windows: Powershell 7. + 2. \*nix: Zsh. +6. Implement responsive design with mobile-first approach using CSS media queries. +7. For texts in the design, COPY THEM WORD FOR WORD. Do not deviate the text content from the design. Ensure that this not only covers a "free text", but also texts inside cards and text inside buttons. Ensure that there are no missing elements. + +## Instructions + +Make sure to keep the implementation principles above in mind when doing these steps. + +### Step 0: Verify requirements + +Ensure that you can establish connection to Figma MCP Server according [to the guide](https://developers.figma.com/docs/figma-mcp-server/remote-server-installation/#claude-code). If there is no MCP server named "figma", terminate the action. + +### Step 1: Implement the features + +Use the resources obtained from Figma MCP server to implement each of the sections. Ensure high quality of the implementation and it's pixel-perfect to what's provided in the design. \ No newline at end of file diff --git a/.claude/skills/create-plan/SKILL.md b/.claude/skills/create-plan/SKILL.md new file mode 100644 index 0000000..bc310c3 --- /dev/null +++ b/.claude/skills/create-plan/SKILL.md @@ -0,0 +1,26 @@ +--- +name: create-plan +description: "Create a detailed design plan from a raw plan." +--- + +# Plan + +## Overview + +Reads a file from `.claude/raw-plans` and creates a detailed plan in `.claude/plans` with the same file base name. + +## When to Use + +Use this skill when: + +- You want to contribute to Extend Apps Directory. +- You are not familiar on how to contribute to Extend Apps Directory. +- You want to make sure that your AI-assisted development can be as accurate as possible (reducing back and forth). + +## Flow + +Given a file name in the format of `.claude/raw-plans/{name}.md`, read that high-level plan and convert it into a detailed plan `.claude/plans/{name}.md`. Use all of the information in the raw plans and use it into the final plan. The final plan should contain these sections: + +1. Overview: an outline of the file. +2. Module breakdown (non-technical): visual elements, assets required, questions. +3. Module breakdown (technical): per-section high-level implementation detail. diff --git a/.gitignore b/.gitignore index cc7c3b4..9b44b18 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,8 @@ npm-debug.log* yarn-debug.log* yarn-error.log* -.yarn/install-state.gz \ No newline at end of file +.yarn/install-state.gz + +.claude/settings.local.json +.claude/plans +.claude/raw-plans \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..8fbdd50 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,30 @@ +# Extend Apps Directory + +## Prerequisites + +- Node.js LTS version, ideally v24 +- Yarn modern (_with_ Corepack) + +Always start with `yarn` in the root project to install the dependencies before you run any scripts in `package.json`, if you haven't already. + +## Conventions + +- Use React for the UI library. +- Use Ant Design library for the UI components. +- Always generate formatted code with Prettier. +- When generating JavaScript syntaxes, use the syntaxes available from the `module` field from the currently used `tsconfig.json`. +- For styling, follow these order: + - If possible to be styled built-in with Ant Design, use it. + - If the Ant Design style can't be overridden with Bootstrap class, then create a `*.module.css` file CLOSE TO THE component that uses it (in the same folder as the component). Sometimes it needs `!important` to override Ant Design styles, only use it when it can't be overridden in a "normal way" (e.g. using higher CSS selector specificity). +- We are using `msw` for mocking requests. When creating tests, ensure that you are mocking the response using `msw` instead of mocking the request call itself. +- When running a code snippet (command line), use the following as terminal preference: + - Windows: Powershell 7. + - \*nix: Zsh. + +## Running + +Run `yarn dev` from the root project. This will spin up a development server that runs in port 5173. + +## Testing + +Run `yarn test` from the root project. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..43c994c --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/resources/plan.md b/resources/plan.md new file mode 100644 index 0000000..a320413 --- /dev/null +++ b/resources/plan.md @@ -0,0 +1,34 @@ +# Design implementation plan for {feature_name} + + + +## Template name + +{feature_name} + +## Details + +These are the details required per feature-partition. In each section, there is a link to the frame in Figma. This allows more granular viewing rather than all-in-one viewing. + +### Home page intro paragraph + +{link-to-figma} + +1. There should be an additional text: _"Have an app to share? Learn how to build and submit an app."_. +2. The "Learn how to build and submit an app" should be a permalink to `?show-contributing-guide-modal=true`. + +### Contributing guideline modal + +{link-to-figma} + +1. When `show-contributing-guide-modal=true`, this modal is shown. +2. In the "Add app icon" bullet point, the "here" links to https://github.com/AccelByte/extend-apps-directory/tree/main/public. +3. In the "Register app or suite" bullet point, the "here" links to https://github.com/AccelByte/extend-apps-directory/blob/main/app/data/extend-apps-directory.json. +4. In the "Submit PR" bullet point, the "repository" links to https://github.com/AccelByte/extend-apps-directory. +5. In the alert on the modal footer area, the "Watch video" links to https://www.youtube.com/watch?v=Y3YU5g6ri5I. From b8ed4d9806b9e81541d618a3ea5c25cb6bf92518 Mon Sep 17 00:00:00 2001 From: Try Ajitiono Date: Mon, 9 Feb 2026 20:24:04 +0700 Subject: [PATCH 2/9] chore: update README.md --- README.md | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 6876780..0b92fb9 100644 --- a/README.md +++ b/README.md @@ -50,16 +50,30 @@ yarn start ## Project Structure -- `app/`: Contains the main application code. - - `assets/`: Static assets like images and logos. - - `components/`: Reusable React components. - - `data/`: JSON data for the Extend apps. - - `routes/`: Route components for different pages. - - `types/`: TypeScript type definitions. - - `app.css`: Global CSS styles. - - `root.tsx`: The root component of the application. - - `routes.ts`: Route configuration. -- `public/`: Public assets that are not processed by Vite. -- `vite.config.ts`: Vite configuration file. -- `package.json`: Project dependencies and scripts. -- `tsconfig.json`: TypeScript configuration. +- `app/`: Contains the main application code. + - `assets/`: Static assets like images and logos. + - `components/`: Reusable React components. + - `data/`: JSON data for the Extend apps. + - `routes/`: Route components for different pages. + - `types/`: TypeScript type definitions. + - `app.css`: Global CSS styles. + - `root.tsx`: The root component of the application. + - `routes.ts`: Route configuration. +- `public/`: Public assets that are not processed by Vite. +- `vite.config.ts`: Vite configuration file. +- `package.json`: Project dependencies and scripts. +- `tsconfig.json`: TypeScript configuration. + +## AI integration + +### Requirements + +- Download Claude Code: https://code.claude.com/docs/en/quickstart +- Set up Figma MCP server: https://developers.figma.com/docs/figma-mcp-server/remote-server-installation/#claude-code. + +### How-to + +- Copy `resources/plan.md` into `.claude/raw-plans/{page_name}.md`. For example: `.claude/raw-plans/{feature_name}.md`. +- Open Claude Code, make sure the model is Sonnet 4.5 (or higher). After that, run this: `/create-plan from .claude/raw-plans/{feature_name}.md.`. +- Answer the questions provided by the AI agent in the new plan document `.claude/plans/{feature_name}.md`. +- Inside Claude Code, run `/contribute with the context of .claude/plans/{feature_name}-sonnet.md.`. From a0d6ba9afa0957b8b1d7cdd0163dcf1482edea96 Mon Sep 17 00:00:00 2001 From: Try Ajitiono Date: Mon, 9 Feb 2026 20:28:58 +0700 Subject: [PATCH 3/9] feat: implement contributing guide --- .../ContributingGuideModal.module.css | 77 ++++++++++ app/components/ContributingGuideModal.tsx | 132 ++++++++++++++++++ app/global.d.ts | 6 + app/routes/home.module.css | 10 ++ app/routes/home.tsx | 18 ++- 5 files changed, 241 insertions(+), 2 deletions(-) create mode 100644 app/components/ContributingGuideModal.module.css create mode 100644 app/components/ContributingGuideModal.tsx create mode 100644 app/global.d.ts diff --git a/app/components/ContributingGuideModal.module.css b/app/components/ContributingGuideModal.module.css new file mode 100644 index 0000000..9838c98 --- /dev/null +++ b/app/components/ContributingGuideModal.module.css @@ -0,0 +1,77 @@ +.modal { + max-width: 100%; + + :global(.ant-modal-close) { + display: none; + } +} + +@media (min-width: 768px) { + .modal { + width: 640px !important; + } +} + +.modalHeader { + gap: 12px; + padding: 20px 24px; + border-bottom: 1px solid #f0f0f0; +} + +.modalTitle { + margin: 0px !important; +} + +.modalContent { + padding: 24px; +} + +.instructionsList { + margin: 0; + padding-left: 20px; + color: #000000a6; +} + +.instructionsList li { + margin-bottom: 0; + line-height: 32px; +} + +.instructionsList ol { + margin-top: 0; + margin-bottom: 0; +} + +.instructionsList ol li { + line-height: 32px; +} + +.instructionsList a { + text-decoration: underline; +} + +@media (max-width: 480px) { + :global(.ant-modal), + :global(.ant-modal-content) { + height: 100%; + width: 100vw; + margin: 0px !important; + top: 0px; + } + + :global(.ant-modal-content) { + border-radius: 0px !important; + } + + :global(.ant-modal-body) { + height: 100%; + } + + .modalTitle { + font-size: 20px !important; + } + + .modalContent { + min-height: 100vh; + } +} diff --git a/app/components/ContributingGuideModal.tsx b/app/components/ContributingGuideModal.tsx new file mode 100644 index 0000000..73719d5 --- /dev/null +++ b/app/components/ContributingGuideModal.tsx @@ -0,0 +1,132 @@ +import { CloseOutlined, InfoCircleFilled, VideoCameraFilled } from '@ant-design/icons' +import { Alert, Button, Modal, Typography } from 'antd' +import { useEffect } from 'react' +import { useSearchParams } from 'react-router-dom' +import { ExternalLink } from './ExternalLink' +import styles from './ContributingGuideModal.module.css' + +const { Title, Paragraph, Text } = Typography + +// External link constants +const LINKS = { + PUBLIC_FOLDER: 'https://github.com/AccelByte/extend-apps-directory/tree/main/public', + JSON_DATA: 'https://github.com/AccelByte/extend-apps-directory/blob/main/app/data/extend-apps-directory.json', + REPOSITORY: 'https://github.com/AccelByte/extend-apps-directory', + VIDEO: 'https://www.youtube.com/watch?v=Y3YU5g6ri5I' +} as const + +export function ContributingGuideModal() { + const [searchParams, setSearchParams] = useSearchParams() + const showModal = searchParams.get('show-contributing-guide-modal') === 'true' + + useEffect(() => { + // Track modal view with Google Analytics + if (showModal && window.gtag) { + window.gtag('event', 'view_contributing_guide', { + event_category: 'engagement', + event_label: 'Contributing Guide Modal Opened' + }) + } + }, [showModal]) + + const handleClose = () => { + searchParams.delete('show-contributing-guide-modal') + setSearchParams(searchParams, { preventScrollReset: true }) + } + + if (!showModal) return null + + return ( + +
+ + Submit your app + + +
+
+
+
+ + Follow these steps to submit a Pull Request (PR) to our team for review and approval: + +
    +
  1. + Go public: Ensure your repository (e.g., GitHub) is set to public. +
  2. +
  3. + Add app icon: Upload your icon{' '} + + + here + + + . Recommended: 512x512px. +
  4. +
  5. + Register app or suite: Add your app's details in extend-apps-directory.json{' '} + + + here + + + . +
      +
    1. + App: A single app hosted in one repository. +
    2. +
    3. + Suite: A collection of multiple related apps (e.g., Gacha Suite). +
    4. +
    +
  6. +
  7. + Submit PR: Open a Pull Request to this{' '} + + + repository + + + , which our team will review. +
  8. +
  9. + Go live: Once approved and merged, your app will automatically appear in the directory. +
  10. +
+
+ } + message={ +
+ Build your first Extend app in minutes using AI. + +
+ } + showIcon + /> +
+
+
+ ) +} diff --git a/app/global.d.ts b/app/global.d.ts new file mode 100644 index 0000000..e861973 --- /dev/null +++ b/app/global.d.ts @@ -0,0 +1,6 @@ +// Global type declarations + +interface Window { + gtag?: (command: string, ...args: any[]) => void + dataLayer?: any[] +} diff --git a/app/routes/home.module.css b/app/routes/home.module.css index ae1fdec..a6f097a 100644 --- a/app/routes/home.module.css +++ b/app/routes/home.module.css @@ -14,3 +14,13 @@ .title { color: #000000e0; } + +.contributingLink { + color: #0b6cff; + text-decoration: underline; +} + +.contributingLink:hover { + color: #0b6cff; + text-decoration: underline; +} diff --git a/app/routes/home.tsx b/app/routes/home.tsx index 08064b6..53c5c87 100644 --- a/app/routes/home.tsx +++ b/app/routes/home.tsx @@ -1,5 +1,6 @@ import { Select, Typography } from 'antd' -import { useSearchParams } from 'react-router-dom' +import { Link, useSearchParams } from 'react-router-dom' +import { ContributingGuideModal } from '~/components/ContributingGuideModal' import { ExtendDirectoryDetailModal } from '~/components/ExtendDirectoryDetailModal' import accelByteLogo from '../assets/accelbyte.svg' import { ExtendDirectoryItems } from '../components/ExtendDirectoryItems' @@ -51,6 +52,12 @@ export default function Home() { setSearchParams(searchParams) } + const handleContributingLinkClick = () => { + const newSearchParams = new URLSearchParams(searchParams) + newSearchParams.set('show-contributing-guide-modal', 'true') + setSearchParams(newSearchParams, { preventScrollReset: true }) + } + return ( <>
@@ -62,7 +69,13 @@ export default function Home() { Extend Apps Directory - Enhance your games with powerful Extend apps crafted by our community. + + Power up your game with community-built Extend apps. Have an app to share?{' '} + + Learn how to build and submit an app + + . +