Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 6 additions & 65 deletions .github/workflows/web.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ jobs:
- ".github/workflows/web.yml"
build:
name: Build
name: Build & Check
needs: [changes]
if: needs.changes.outputs.web == 'true'
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
Expand All @@ -55,68 +57,7 @@ jobs:
cache: "npm"
cache-dependency-path: vortex-web/package-lock.json
- run: npm ci
- run: npm run build
- run: npm run wasm
- run: npm run lint
- uses: actions/upload-artifact@v4
with:
name: vortex-web-dist
path: vortex-web/dist
retention-days: 7

preview:
name: Deploy Preview
needs: [build, changes]
if: needs.changes.outputs.web == 'true'
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
pull-requests: write
deployments: write
environment:
name: preview
url: ${{ steps.deploy.outputs.deployment-url }}
steps:
- uses: actions/download-artifact@v4
with:
name: vortex-web-dist
path: dist
- name: Deploy to Cloudflare Pages
id: deploy
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: >-
pages deploy dist/
--project-name=vortex-web
--branch=${{ github.head_ref || github.ref_name }}
- name: Comment preview URL on PR
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const body = `**Vortex Web Preview:** ${{ steps.deploy.outputs.deployment-url }}`;
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const existing = comments.find(c =>
c.body?.startsWith('**Vortex Web Preview:**')
);
if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body,
});
}
- run: npm run typecheck
- run: npm run build-storybook
14 changes: 14 additions & 0 deletions .idea/copyright/profiles_settings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions .idea/scopes/web_files.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions vortex-web/.gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
node_modules
dist
storybook-static
src/wasm/pkg
*.local
16 changes: 16 additions & 0 deletions vortex-web/.storybook/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: Copyright the Vortex contributors

import type { StorybookConfig } from '@storybook/react-vite';

const config: StorybookConfig = {
"stories": [
"../src/**/*.mdx",
"../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"
],
"addons": [
"@storybook/addon-docs",
],
"framework": "@storybook/react-vite"
};
export default config;
18 changes: 18 additions & 0 deletions vortex-web/.storybook/preview.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: Copyright the Vortex contributors

import type { Preview } from '@storybook/react-vite'
import '../src/index.css'

const preview: Preview = {
parameters: {
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
},
};

export default preview;
76 changes: 76 additions & 0 deletions vortex-web/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Vortex Web

A web UI for exploring Vortex data files, built with React, TypeScript, Tailwind CSS, and Rust/WASM.

## Prerequisites

- Node.js 22+
- [wasm-pack](https://rustwasm.github.io/wasm-pack/installer/) (for full app development)
- Rust toolchain (for full app development)

## Getting Started

```bash
npm install
```

### Full App (requires Rust + wasm-pack)

```bash
# Start dev server (builds WASM in debug mode, then starts Vite)
npm run dev
```

### Storybook (no Rust/WASM required)

Storybook lets you develop and preview UI components in isolation:

```bash
npm run storybook
```

This starts a dev server at http://localhost:6006.

## Scripts

| Command | Description |
|---------------------------|--------------------------------------------|
| `npm run dev` | Build WASM (debug) + start Vite dev server |
| `npm run build` | Production build (WASM release + Vite) |
| `npm run storybook` | Start Storybook dev server on port 6006 |
| `npm run build-storybook` | Build static Storybook site |
| `npm run lint` | Run ESLint |
| `npm run lint:fix` | Run ESLint with auto-fix |
| `npm run typecheck` | Run TypeScript type checking |
| `npm run check` | Build WASM + lint + typecheck |

## Writing Stories

Add story files alongside your components as `*.stories.tsx`:

```tsx
import type {Meta, StoryObj} from '@storybook/react-vite';
import {MyComponent} from './MyComponent';

const meta: Meta<typeof MyComponent> = {
component: MyComponent,
};
export default meta;

type Story = StoryObj<typeof MyComponent>;

export const Default: Story = {
args: {},
};
```

## Project Structure

```
vortex-web/
crate/ # Rust WASM crate (vortex bindings)
src/ # React/TypeScript frontend
wasm/pkg/ # Generated WASM bindings (not checked in)
.storybook/ # Storybook configuration
public/ # Static assets
```
40 changes: 19 additions & 21 deletions vortex-web/eslint.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,25 @@ import js from "@eslint/js";
import globals from "globals";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import storybook from "eslint-plugin-storybook";
import tseslint from "typescript-eslint";

export default tseslint.config(
{ ignores: ["dist"] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ["**/*.{ts,tsx}"],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
"react-hooks": reactHooks,
"react-refresh": reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
"react-refresh/only-export-components": [
"warn",
{ allowConstantExport: true },
],
},
export default tseslint.config({ ignores: ["dist"] }, {
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ["**/*.{ts,tsx}"],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
);
plugins: {
"react-hooks": reactHooks,
"react-refresh": reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
"react-refresh/only-export-components": [
"warn",
{ allowConstantExport: true },
],
},
}, storybook.configs["flat/recommended"]);
Loading
Loading