# Custom Pages

# Custom Pages

:::info
Custom pages are your own tabs in the Info Hub book, defined in JSON - no code required. Each page gets its own line in the book's left navigation. The **Pages** board of the [admin window](./admin-panel#content-boards) edits this file with a live preview.
:::

**File:** `custom/pages.json`

## Supported Page Types

| Type | Description | Use Case |
|------|-------------|----------|
| `TEXT` | Simple text with color codes | Donation page, welcome text, announcements |
| `LIST` | List with expandable entries | Changelog, news, updates |
| `FAQ_STYLE` | Expandable questions & answers | Tips & tricks, extended FAQ |
| `GRID` | Items with icons and actions; shown as a list in the book | Quick links, categories |

Every page type has "page n of m" paging, so long pages are no longer cut off.

---

## Complete Example

```json
{
  "pages": [
    {
      "id": "changelog",
      "title": "Server Changelog",
      "icon": "Ore_Prisma",
      "type": "LIST",
      "showInHub": true,
      "quickAccess": false,
      "command": "changelog",
      "commandAliases": ["updates", "news"],
      "permission": "",
      "priority": 10,
      "entries": [
        {
          "title": "v1.2.0 - Big Update",
          "subtitle": "2026-02-01",
          "content": "&aAdded:&r New spawn area\n&eChanged:&r Economy balancing\n&cFixed:&r Login issues"
        },
        {
          "title": "v1.1.0 - Quality of Life",
          "subtitle": "2026-01-15",
          "content": "&aAdded:&r /home command\n&cFixed:&r Various bugs"
        }
      ]
    },
    {
      "id": "donate",
      "title": "Support Us",
      "icon": "Ore_Gold",
      "type": "TEXT",
      "showInHub": true,
      "quickAccess": true,
      "priority": 20,
      "content": "&6Thank you for supporting our server!&r\n\nYour donations help us:\n- Keep the server running 24/7\n- Add new features\n\n&bHow to donate:&r\nVisit &6store.example.com&r"
    },
    {
      "id": "tips",
      "title": "Tips & Tricks",
      "icon": "Furniture_Ancient_Torch",
      "type": "FAQ_STYLE",
      "showInHub": true,
      "command": "tips",
      "priority": 30,
      "entries": [
        {
          "title": "How do I get started?",
          "content": "Visit &6/spawn&r and follow the tutorial path.",
          "tags": ["beginner", "tutorial"]
        },
        {
          "title": "How do I claim land?",
          "content": "Use a &eGolden Shovel&r to create claims!",
          "tags": ["claims", "protection"]
        }
      ]
    }
  ]
}
```

---

## Configuration Fields

### Page Object

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `id` | String | Yes | Unique page identifier |
| `title` | String | Yes | Display title |
| `icon` | String | No | Item icon (e.g., `Ore_Gold`, `Furniture_Ancient_Torch`) |
| `type` | Enum | Yes | `TEXT`, `LIST`, `FAQ_STYLE`, `GRID` |
| `showInHub` | Boolean | No | Show on main page (default: `true`) |
| `quickAccess` | Boolean | No | Old sidebar flag; tiles are configured in `quickaccess.json` (or jump to a page with `infohub:page:<id>`) |
| `hidden` | Boolean | No | If `true`, the page is only reachable with its own command (not in the navigation, default: `false`). A hidden page without a command cannot be opened at all, which is useful for drafts |
| `command` | String | No | Register command (e.g., `"changelog"` → `/changelog`) |
| `commandAliases` | String[] | No | Alternative commands |
| `permission` | String | No | Permission required to view |
| `priority` | Integer | No | Sort order (lower = higher up, default: `99`) |
| `content` | String | TEXT only | Text content with color codes |
| `entries` | Array | LIST/FAQ | List of entries |
| `gridItems` | Array | GRID only | Grid items with icons and actions |
| `i18n` | Object | No | Optional title / content per language (also on every entry) |

### Entry Object (for LIST and FAQ_STYLE)

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `title` | String | Yes | Entry title |
| `subtitle` | String | No | Subtitle (e.g., date) |
| `content` | String | Yes | Content with color codes |
| `icon` | String | No | Item icon |
| `tags` | String[] | No | Search keywords (FAQ_STYLE only) |

---

## Page Types

### TEXT Type

Simple text with a small markup:

| Markup | Result |
|--------|--------|
| `# Heading`, `## Subheading` | Headings |
| `- item`, `* item`, `• item` | Bullets |
| `**bold**` | Bold |
| `&a` ... `&f` | Colour codes |
| `&o` | Italic |

```json
{
  "id": "welcome",
  "title": "Welcome",
  "icon": "Deco_Book_Pile_Small",
  "type": "TEXT",
  "showInHub": true,
  "content": "&6Welcome to our server!&r\n\nWe're glad you're here.\n\n&aEnjoy your stay!&r"
}
```

### LIST Type

Expandable list with entries. Each entry has a title, optional subtitle, and collapsible content.

```json
{
  "id": "changelog",
  "title": "Changelog",
  "icon": "Ore_Prisma",
  "type": "LIST",
  "command": "changelog",
  "entries": [
    {
      "title": "v1.2.0 - Major Update",
      "subtitle": "2026-02-01",
      "content": "&aNew features:&r\n- Feature 1\n- Feature 2"
    }
  ]
}
```

### FAQ_STYLE Type

Question and answer format with expandable answers. Supports tags for search filtering.

```json
{
  "id": "tips",
  "title": "Tips & Tricks",
  "icon": "Furniture_Ancient_Torch",
  "type": "FAQ_STYLE",
  "entries": [
    {
      "title": "How do I get started?",
      "content": "Visit &6/spawn&r and follow the tutorial.",
      "tags": ["beginner", "start"]
    }
  ]
}
```

### GRID Type

Button grid layout with icons and actions. Each item can execute a command, open a URL, or navigate to another custom page.

```json
{
  "id": "quicklinks",
  "title": "Quick Links",
  "icon": "Deco_Map",
  "type": "GRID",
  "showInHub": true,
  "gridItems": [
    {
      "label": "Spawn",
      "icon": "Ore_Prisma",
      "action": "command",
      "actionValue": "/spawn"
    },
    {
      "label": "Shop",
      "icon": "Ore_Gold",
      "action": "command",
      "actionValue": "/shop"
    },
    {
      "label": "Changelog",
      "icon": "Deco_Scroll",
      "action": "page",
      "actionValue": "changelog"
    },
    {
      "label": "Website",
      "icon": "Tool_Map",
      "action": "url",
      "actionValue": "https://example.com"
    }
  ]
}
```

#### Grid Item Fields

| Field | Type | Description |
|-------|------|-------------|
| `label` | String | Display text on the grid button |
| `icon` | String | Item ID for the button icon |
| `action` | String | Action type: `"command"`, `"url"`, or `"page:pageId"` |
| `actionValue` | String | The command, URL, or page ID to execute |

---

## Color Codes

Minecraft-style color codes are supported in all text fields:

| Code | Color | Code | Color |
|------|-------|------|-------|
| `&0` | Black | `&8` | Dark Gray |
| `&1` | Dark Blue | `&9` | Blue |
| `&2` | Dark Green | `&a` | Green |
| `&3` | Dark Cyan | `&b` | Cyan |
| `&4` | Dark Red | `&c` | Red |
| `&5` | Purple | `&d` | Pink |
| `&6` | Gold | `&e` | Yellow |
| `&7` | Gray | `&f` | White |
| `&r` | Reset (default color) | | |

**Example:** `"&aAdded:&r New feature"` → "Added:" in Green, "New feature" in default color

---

## Navigation Display

Pages with `showInHub: true` get one line each in the left navigation of the book, sorted by `priority` (lower values first). Search finds custom pages down to the single entry when `globalSearch.searchIn.pages` is on.

---

## Command Registration

When `command` is set, a command is automatically registered:

```json
{
  "command": "changelog",
  "commandAliases": ["updates", "news"]
}
```

This registers: `/changelog`, `/updates`, `/news`

All commands open the corresponding page directly. A new or renamed command name needs a server restart.

---

## Permissions

Optionally set a permission to restrict page visibility:

```json
{
  "permission": "infohub.page.vip"
}
```

Only players with this permission can see the page. It is hidden from the navigation and search, and its command answers "no permission" for players without it (the command still shows up in autocomplete, because the permission is checked when it is used).

---

## After Changes

After editing `pages.json`, reload the configuration:

```
/ksinfoadmin reload
```

:::tip Hot Reload
Changes to custom pages apply right after a reload or a save in the admin window - only new or renamed command names need a restart. Opening a page that does not exist (any more) returns to Start with "not available".
:::