### Install Dependencies and Start Development Server Source: https://github.com/modrinth/code/blob/main/apps/frontend/README.md Run these commands to install project dependencies and start the development server with hot-reloading. ```bash pnpm install pnpm web:dev ``` -------------------------------- ### Install Dependencies and Start Dev Server Source: https://github.com/modrinth/code/blob/main/apps/docs/README.md Run these commands to install project dependencies and start a local development server for the documentation site. Changes will automatically refresh the browser. ```bash pnpm install pnpm docs:dev ``` -------------------------------- ### Install Dependencies and Start Dev Server Source: https://github.com/modrinth/code/blob/main/apps/app/README.md Run these commands to install project dependencies and start the development server with hot-reloading. ```bash pnpm install pnpm app:dev ``` -------------------------------- ### Install the package Source: https://github.com/modrinth/code/blob/main/packages/api-client/README.md Install the client using pnpm. ```bash pnpm add @modrinth/api-client ``` -------------------------------- ### Install Dependencies and Start Dev Server Source: https://github.com/modrinth/code/blob/main/apps/docs/src/content/docs/contributing/docs.md Use these commands to install project dependencies with pnpm and start a hot-reloading development server for the docs site. ```bash pnpm install pnpm run docs:dev ``` -------------------------------- ### Install for Tauri Source: https://github.com/modrinth/code/blob/main/packages/api-client/README.md Install the client along with the required Tauri HTTP plugin. ```bash pnpm add @modrinth/api-client @tauri-apps/plugin-http ``` -------------------------------- ### Install sqlx-cli Source: https://github.com/modrinth/code/blob/main/apps/docs/src/content/docs/contributing/labrinth.md Install the sqlx-cli tool to manage database migrations and schema. Ensure to include necessary features for different database types and TLS. ```sh cargo install sqlx-cli --no-default-features --features mysql,sqlite,postgres,rustls,completions ``` -------------------------------- ### Setup Tauri Provider in App Frontend Source: https://github.com/modrinth/code/blob/main/standards/frontend/DEPENDENCY_INJECTION.md Create a setup function in `apps/app-frontend/src/providers/setup/` to provide platform-specific implementations. This function is registered in `apps/app-frontend/src/providers/setup.ts` and called from `App.vue`'s `setup()`. ```typescript // apps/app-frontend/src/providers/setup/my-feature.ts import { ref } from 'vue' import { provideMyFeature } from '@modrinth/ui' export function setupMyFeatureProvider() { const items = ref([]) provideMyFeature({ items, addItem: async (item) => { await invoke('add_item', { item }) items.value.push(item) }, removeItem: async (id) => { await invoke('remove_item', { id }) items.value = items.value.filter(i => i.id !== id) }, }) } ``` -------------------------------- ### Start Labrinth with Docker Compose Source: https://github.com/modrinth/code/blob/main/apps/docs/src/content/docs/contributing/labrinth.md Start Labrinth and its backing services using Docker Compose. The `--profile with-labrinth` flag ensures Labrinth is included in the startup. ```sh docker compose --profile with-labrinth up ``` -------------------------------- ### Stage Configuration Example Source: https://github.com/modrinth/code/blob/main/standards/frontend/MODALS.md Example of defining a stage configuration for a multi-stage modal, including conditional logic and button configurations. ```APIDOC ## Stage Configuration ### Description Defines the configuration for a single stage within a multi-stage modal. It includes properties for content, titles, navigation logic, and button actions. ### Fields #### `id` (string) Unique identifier for the stage, used for navigation. #### `stageContent` (Component) The Vue component to render for this stage. Must be wrapped with `markRaw()`. #### `title` (MaybeCtxFn) The title displayed for the stage, potentially dependent on context. #### `skip` (MaybeCtxFn) Determines if the stage should be skipped based on the context. #### `nonProgressStage` (MaybeCtxFn) If true, this stage will not be included in the progress bar. #### `hideStageInBreadcrumb` (MaybeCtxFn) If true, this stage will be hidden from the breadcrumb navigation. #### `cannotNavigateForward` (MaybeCtxFn) If true, prevents the user from navigating to the next stage, typically used for validation. #### `disableClose` (MaybeCtxFn) If true, the modal's close button will be disabled. #### `leftButtonConfig` (MaybeCtxFn) Configuration for the button on the left side of the modal footer. #### `rightButtonConfig` (MaybeCtxFn) Configuration for the button on the right side of the modal footer. #### `maxWidth` (MaybeCtxFn) Specifies the maximum width for this specific stage. Defaults to `560px`. ### Button Config Fields #### `label` (string) Text displayed on the button. #### `icon` (Component) An icon component to display on the button. #### `iconPosition` ('before' | 'after') Determines if the icon appears before or after the label. #### `color` (string) Prop for the `ButtonStyled` component to control button color. #### `disabled` (boolean) If true, the button will be disabled. #### `onClick` (Function) Handler function to execute when the button is clicked. ### Example Usage ```ts import type { StageConfigInput } from '@modrinth/ui' import type { MyModalContext } from '../my-modal' export const detailsStageConfig: StageConfigInput = { id: 'details', stageContent: markRaw(DetailsStage), title: 'Details', skip: (ctx) => ctx.shouldSkipDetails.value, cannotNavigateForward: (ctx) => !ctx.formData.value.name, disableClose: (ctx) => ctx.isSubmitting.value, leftButtonConfig: (ctx) => ({ label: 'Cancel', onClick: () => ctx.modal.value?.hide(), }), rightButtonConfig: (ctx) => ({ label: 'Next', icon: RightArrowIcon, iconPosition: 'after', disabled: !ctx.formData.value.name, onClick: () => ctx.modal.value?.nextStage(), }), } ``` ``` -------------------------------- ### Complete Storybook Story File Example Source: https://github.com/modrinth/code/blob/main/packages/ui/src/stories/add-stories.md A full example of a Storybook story file for a Vue 3 component using Vite. Includes meta configuration, component rendering, and multiple story variations. ```typescript import type { Meta, StoryObj } from '@storybook/vue3-vite' import { ref } from 'vue' import Badge from '../../components/base/Badge.vue' const meta = { title: 'Base/Badge', component: Badge, render: (args) => ({ components: { Badge }, setup() { return { args } }, template: /* html */ ` Badge Text `, }), } satisfies Meta export default meta type Story = StoryObj export const Default: Story = { args: { color: 'green', }, } export const AllColors: StoryObj = { render: () => ({ components: { Badge }, template: /* html */ `
Green Red Orange Blue Purple Gray
`, }), } export const AllTypes: StoryObj = { render: () => ({ components: { Badge }, template: /* html */ `
Default Outlined Highlight
`, }), } ``` -------------------------------- ### Interactive Component (Modal) Source: https://github.com/modrinth/code/blob/main/packages/ui/src/stories/add-stories.md Demonstrates how to create a story for an interactive component like a modal, including setup for refs and event handling. ```typescript export const Default: Story = { render: () => ({ components: { Modal, ButtonStyled }, setup() { const modalRef = ref | null>(null) return { modalRef } }, template: /* html */ `

Modal content

`, }), args: {}, } ``` -------------------------------- ### Query Key Structure Examples Source: https://github.com/modrinth/code/blob/main/standards/frontend/FETCHING_DATA.md Illustrates the hierarchical array pattern for TanStack Query keys, emphasizing the placement of resource IDs for effective invalidation. ```typescript // Resource type → version/qualifier → ID ['project', 'v3', projectId] // Resource type → ID → sub-resource ['project', projectId, 'members'] ['project', projectId, 'versions', 'v3'] // Domain → action → ID ['backups', 'list', serverId] ['tech-reviews'] ``` -------------------------------- ### Connect to Minecraft Server and Get Status Source: https://github.com/modrinth/code/blob/main/packages/async-minecraft-ping/README.md Use this snippet to establish a connection to a Minecraft server, configure connection parameters like port and timeout, and retrieve the server's status information. Requires the `ConnectionConfig` and `Duration` types. ```rust let config = ConnectionConfig::build("mc.example.com") .with_port(25565) .with_timeout(Duration::from_secs(5)); let connection = config.connect().await?; let status = connection.status().await?; println!( "{} of {} player(s) online", status.status.players.online, status.status.players.max ); ``` -------------------------------- ### Minotaur Upload Configuration (New) Source: https://github.com/modrinth/code/blob/main/packages/blog/articles/redesign.md Simplified configuration for uploading mods to Modrinth using Minotaur 2.0.0. Uses a dedicated `modrinth` block and offers automatic detection for token, game version, and loader when using standard build setups. ```groovy modrinth { projectId = 'AABBCCDD' versionName = "[$project.minecraft_version] Mod Name $project.version" releaseType = 'alpha' changelog = project.changelog uploadFile = remapJar gameVersions = ['1.18', '1.18.1', '1.18.2'] loaders = ['fabric'] dependencies = [ new ModDependency('P7dR8mSH', 'required') // Creates a new required dependency on Fabric API ] } ``` -------------------------------- ### Set up database schema Source: https://github.com/modrinth/code/blob/main/apps/docs/src/content/docs/contributing/labrinth.md Use the sqlx CLI to set up the database schema. This command applies migrations and creates the necessary tables. ```sh cargo sqlx database setup ``` -------------------------------- ### Run development build and lint commands Source: https://github.com/modrinth/code/blob/main/packages/api-client/README.md Commands for building and linting the API client package. ```bash pnpm --filter @modrinth/api-client build pnpm --filter @modrinth/api-client lint # or pnpm prepr:frontend:lib in turborepo root. ``` -------------------------------- ### Seed database with initial data Source: https://github.com/modrinth/code/blob/main/apps/docs/src/content/docs/contributing/labrinth.md Source environment variables and then use psql to import seed data into the database. This populates essential entities like categories and project types. ```sh source .env psql "$DATABASE_URL" < fixtures/labrinth-seed-data-202508052143.sql ``` -------------------------------- ### Define a Typed Context with createContext Source: https://github.com/modrinth/code/blob/main/standards/frontend/DEPENDENCY_INJECTION.md Use `createContext` to generate a typed `[inject, provide]` tuple for sharing state and functions. Call `provideMyContext` in a parent's `setup()` and `injectMyContext` in any descendant's `setup()`. Use `injectMyContext(null)` for optional contexts. ```typescript import { createContext } from '@modrinth/ui' interface MyContext { someValue: Ref doSomething: () => void } export const [injectMyContext, provideMyContext] = createContext('MyComponent') ``` -------------------------------- ### Authorization Header Example Source: https://github.com/modrinth/code/blob/main/apps/labrinth/src/api_v2_description.md The Authorization header format required for authenticated requests to the Modrinth API. ```http Authorization: mrp_RNtLRSPmGj2pd1v1ubi52nX7TJJM9sznrmwhAuj511oe4t1jAqAQ3D6Wc8Ic ``` -------------------------------- ### Initialize Generic Client Source: https://github.com/modrinth/code/blob/main/packages/api-client/README.md Create a client instance for Node.js or browser environments with authentication. ```ts import { AuthFeature, GenericModrinthClient, type Labrinth } from '@modrinth/api-client' const client = new GenericModrinthClient({ userAgent: 'my-app/1.0.0', features: [new AuthFeature({ token: process.env.MODRINTH_TOKEN })], }) const project: Labrinth.Projects.v2.Project = await client.labrinth.projects_v2.get('sodium') const members = await client.labrinth.projects_v3.getMembers(project.id) ``` -------------------------------- ### Client Initialization and Module Access Source: https://github.com/modrinth/code/blob/main/packages/api-client/README.md How to access API modules and perform requests using the client. ```APIDOC ## SDK Method: client.labrinth.projects_v3.get ### Description Retrieves project information from the Labrinth API. ### Signature `client.labrinth.projects_v3.get(id: string)` ### Example ```ts const project = await client.labrinth.projects_v3.get('sodium'); ``` ``` -------------------------------- ### Accessing API Modules Source: https://github.com/modrinth/code/blob/main/packages/api-client/CLAUDE.md Modules are accessed lazily as a nested structure. This example shows common module paths for different services. ```typescript client.labrinth.projects_v2 client.labrinth.projects_v3 client.labrinth.versions_v3 client.labrinth.collections client.labrinth.billing_internal client.archon.servers_v0 client.archon.servers_v1 client.archon.backups_queue_v1 client.archon.backups_v1 client.archon.content_v0 client.kyros.files_v0 client.iso3166.data ... etc. ``` -------------------------------- ### Wrap SQLx Pool with sqlx-tracing Source: https://github.com/modrinth/code/blob/main/packages/sqlx-tracing/README.md Instantiate a traced pool using `sqlx_tracing::Pool::from` with an existing SQLx pool, or use `PoolBuilder` to manually configure tracing attributes like name, database, and host. ```rust let pool = sqlx::PgPool::connect(&url).await?; // the attributes will be resolved from the url let traced_pool = sqlx_tracing::Pool::from(pool); // or manually overwrite them let traced_pool = sqlx_tracing::PoolBuilder::from(pool) .with_name("my-domain-database") .with_database("database") .with_host("somewhere") .with_port(1234) .build(); ``` -------------------------------- ### Define translatable messages in Vue Source: https://github.com/modrinth/code/blob/main/standards/frontend/INTERNATIONALIZATION.md Use defineMessages to register static strings with unique IDs and default English values within script setup. ```ts const messages = defineMessages({ welcomeTitle: { id: 'auth.welcome.title', defaultMessage: 'Welcome' }, welcomeDescription: { id: 'auth.welcome.description', defaultMessage: "You're now part of the community…" }, }) ``` -------------------------------- ### Database and Cache Management Commands Source: https://github.com/modrinth/code/blob/main/apps/labrinth/AGENTS.md Commands for interacting with local infrastructure services via Docker. ```bash docker exec labrinth-postgres psql -c "select 1" ``` ```bash docker exec labrinth-redis redis-cli flushall ``` ```bash docker exec labrinth-clickhouse clickhouse-client "select 1" ``` -------------------------------- ### Initialize Tauri Client Source: https://github.com/modrinth/code/blob/main/packages/api-client/README.md Configure the client for use within a Tauri application. ```ts import { getVersion } from '@tauri-apps/api/app' import { AuthFeature, TauriModrinthClient } from '@modrinth/api-client' const client = new TauriModrinthClient({ userAgent: async () => `modrinth/theseus/${await getVersion()} (support@modrinth.com)`, features: [new AuthFeature({ token: process.env.MODRINTH_TOKEN })], }) const project = await client.labrinth.projects_v2.get('sodium') ``` -------------------------------- ### Query Key Invalidation Example Source: https://github.com/modrinth/code/blob/main/standards/frontend/FETCHING_DATA.md Demonstrates how to invalidate queries using partial key matching by placing the resource ID last in the query key array. ```typescript // Invalidates all project queries for this ID queryClient.invalidateQueries({ queryKey: ['project', projectId] }) ``` -------------------------------- ### Configure analytics via query parameters Source: https://github.com/modrinth/code/blob/main/packages/blog/articles/analytics-overhaul.md Use mr_-prefixed query parameters as an alternative to headers when tracking download metadata. ```text https://cdn.modrinth.com/...?mr_download_reason=standalone&mr_game_version=1.20.1&mr_loader=fabric ``` -------------------------------- ### Example Markdown Frontmatter for Blog Article Source: https://github.com/modrinth/code/blob/main/packages/blog/README.md Frontmatter is used to define metadata for a blog article. Include title, short title, summary, short summary, and date. ```markdown --- title: Quintupling Creator Revenue and Becoming Sustainable short_title: Becoming Sustainable summary: Announcing an update to our monetization program, creator split, and more! short_summary: Announcing 5x creator revenue and updates to the monetization program. date: 2024-09-13T12:00:00-08:00 --- ``` -------------------------------- ### Modal with Action Buttons Source: https://github.com/modrinth/code/blob/main/standards/frontend/MODALS.md Implement the '#actions' slot to render a footer with buttons, typically used for confirmation or cancellation actions. This example shows a danger-themed modal with delete and cancel options. ```vue

This action cannot be undone.

``` -------------------------------- ### Create Modal Wrapper Component Source: https://github.com/modrinth/code/blob/main/standards/frontend/MODALS.md Set up a wrapper component to provide the modal context and render the `MultiStageModal` component. Use `shallowRef` for the modal instance and expose a `show` method. ```vue ``` -------------------------------- ### Implementing Client Features Source: https://github.com/modrinth/code/blob/main/packages/api-client/README.md Configure features like authentication, retries, and circuit breakers during client instantiation. ```ts import { AuthFeature, CircuitBreakerFeature, RetryFeature } from '@modrinth/api-client' const client = new GenericModrinthClient({ features: [new AuthFeature({ token: async () => process.env.MODRINTH_TOKEN }), new RetryFeature({ maxAttempts: 3, backoffStrategy: 'exponential' }), new CircuitBreakerFeature({ maxFailures: 3, resetTimeout: 30_000 })], }) ``` -------------------------------- ### Get Design Context with Figma MCP Source: https://github.com/modrinth/code/blob/main/standards/frontend/FIGMA_MCP_USAGE.md Use the `get_design_context` tool to retrieve reference code, a screenshot, and metadata for a specific Figma node. Specify the desired client languages and frameworks for the output. ```python get_design_context(nodeId: "1:2", clientLanguages: "typescript,html,css", clientFrameworks: "vue") ``` -------------------------------- ### Start Labrinth with Docker Compose Watch Source: https://github.com/modrinth/code/blob/main/apps/docs/src/content/docs/contributing/labrinth.md Enable Compose Watch to automatically rebuild and restart the Labrinth container when source code changes are detected during development. Note potential performance impacts on certain operating systems. ```sh docker compose --profile with-labrinth up --watch ``` -------------------------------- ### Database Seeding Command Source: https://github.com/modrinth/code/blob/main/apps/labrinth/AGENTS.md Command to seed the local database with fixture data. ```bash psql postgresql://labrinth:labrinth@localhost/labrinth -f apps/labrinth/fixtures/labrinth-seed-data-202508052143.sql ``` -------------------------------- ### ReadyTransition with useReadyState Source: https://github.com/modrinth/code/blob/main/standards/frontend/CROSS_PLATFORM_PAGES.md Use `ReadyTransition` to wrap the main UI, driven by `useReadyState` which monitors the primary TanStack query's loading state. This prevents content flashing on initial load. ```vue ``` ```typescript const primaryQuery = useQuery({ /* ... */ }) const readyPending = useReadyState(primaryQuery) // or useReadyState({ isLoading, data }) when not using the full query object ``` -------------------------------- ### Initialize Nuxt Client Source: https://github.com/modrinth/code/blob/main/packages/api-client/README.md Configure the client for use within a Nuxt application with circuit breaker support. ```ts import { AuthFeature, CircuitBreakerFeature, NuxtCircuitBreakerStorage, NuxtModrinthClient } from '@modrinth/api-client' export const useModrinthClient = async () => { const config = useRuntimeConfig() return new NuxtModrinthClient({ userAgent: 'my-nuxt-app/1.0.0', rateLimitKey: import.meta.server ? config.rateLimitKey : undefined, features: [ new AuthFeature({ token: process.env.MODRINTH_TOKEN, }), new CircuitBreakerFeature({ storage: new NuxtCircuitBreakerStorage(), }), ], }) } ```