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
8 changes: 4 additions & 4 deletions .cursor/rules/CODE_STYLE.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -72,17 +72,17 @@ frontend/src/pages/Home.tsx

#### Test Files

- **Same name as source** with `.spec.ts` suffix
- **Same name as source** with `.test.ts` suffix
- Co-located with source file when possible

```
βœ… Good:
frontend/src/environment-options.ts
frontend/src/environment-options.spec.ts
frontend/src/environment-options.test.ts

❌ Avoid:
test/environment-options.spec.ts (not co-located)
frontend/src/environment-options.test.ts (use .spec.ts)
test/environment-options.test.ts (not co-located)
frontend/src/environment-options.spec.ts (use .test.ts)
```

### Components and Classes
Expand Down
56 changes: 56 additions & 0 deletions .yarn/changelogs/frontend.3bb2111e.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<!-- version-type: minor -->
# frontend

<!--
FORMATTING GUIDE:

### Detailed Entry (appears first when merging)

Use h3 (###) and below for detailed entries with paragraphs, code examples, and lists.

### Simple List Items

- Simple changes can be added as list items
- They are collected together at the bottom of each section

TIP: When multiple changelog drafts are merged, heading-based entries
appear before simple list items within each section.
-->

## ✨ Features

### Redesigned Home Page

The landing page now uses a card-based layout with `PageContainer`, `Card`, `CardHeader`, `CardContent`, and `CardActions` components, providing a cleaner visual hierarchy for the available tools.

### Auto-Hiding App Bar

Adopted the `PageLayout` component with `auto-hide` variant for the app bar, replacing the previous manual scroll-based visibility logic.

## ♻️ Refactoring

- Migrated routing from `Router` to `NestedRouter` and links from `RouteLink` to `NestedRouteLink` (shades v12 API)
- Replaced `useDisposable` + `ObservableValue` pattern with the `useState` hook in `JsonSchemaSelector`
- Migrated Monaco editor and diff editor components to use `useRef`, `useHostProps`, and disposable lifecycle patterns
- Moved inline styles to component-level `css` property in `ComparePage`, `ValidatePage`, `JsonSchemaSelector`, and `Home`
- Replaced manual layout styling in `Layout` with the `PageLayout` component
- Updated Monaco JSON language import path in `MonacoModelProvider`

## πŸ§ͺ Tests

- Updated E2E visual snapshots to match the redesigned home page
- Added placeholder unit test

## ⬆️ Dependencies

- `@furystack/shades` ^11.0.28 β†’ ^12.0.0
- `@furystack/shades-common-components` ^10.0.28 β†’ ^12.0.0
- `@furystack/core` ^15.0.27 β†’ ^15.0.35
- `@furystack/inject` ^12.0.21 β†’ ^12.0.29
- `@furystack/logging` ^8.0.21 β†’ ^8.0.29
- `@furystack/rest-client-fetch` ^8.0.27 β†’ ^8.0.35
- `@furystack/utils` ^8.1.3 β†’ ^8.1.9
- `@types/node` ^24.7.2 β†’ ^25.2.2
- `monaco-editor` ^0.54.0 β†’ ^0.55.1
- `vite` ^7.1.11 β†’ ^7.3.1
- `vitest` ^3.2.4 β†’ ^4.0.18
56 changes: 56 additions & 0 deletions .yarn/changelogs/json-tools.3bb2111e.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<!-- version-type: minor -->
# json-tools

<!--
FORMATTING GUIDE:

### Detailed Entry (appears first when merging)

Use h3 (###) and below for detailed entries with paragraphs, code examples, and lists.

### Simple List Items

- Simple changes can be added as list items
- They are collected together at the bottom of each section

TIP: When multiple changelog drafts are merged, heading-based entries
appear before simple list items within each section.
-->

## πŸ“¦ Build

- Upgraded Yarn from 4.10.3 to 4.12.0
- Added `@furystack/yarn-plugin-changelog` for automated changelog management
- Renamed `test:unit` script to `test`, `prettier` to `format`, and `prettier:check` to `format:check`
- Consolidated `applyVersionBumps` into `applyReleaseChanges` (now includes changelog apply and formatting)
- Replaced `vitest.workspace.mts` with a unified `vitest.config.mts`

## πŸ‘· CI

- Added `check-changelog.yml` workflow to validate changelog entries on PRs
- Added `release.yml` workflow for automated releases
- Updated `build-test.yml` and `check-version-bump.yml` pipelines

## ⬆️ Dependencies

- `@eslint/js` ^9.37.0 β†’ ^10.0.1
- `@playwright/test` ^1.56.0 β†’ ^1.58.2
- `@types/node` ^24.7.2 β†’ ^25.2.2
- `@vitest/coverage-v8` ^3.2.4 β†’ ^4.0.18
- `eslint` ^9.37.0 β†’ ^10.0.0
- `eslint-plugin-jsdoc` ^61.1.4 β†’ ^62.5.4
- `eslint-plugin-playwright` ^2.2.2 β†’ ^2.5.1
- `eslint-plugin-prettier` ^5.5.4 β†’ ^5.5.5
- `jsdom` ^27.0.0 β†’ ^28.0.0
- `lint-staged` ^16.2.4 β†’ ^16.2.7
- `prettier` ^3.6.2 β†’ ^3.8.1
- `rimraf` ^6.0.1 β†’ ^6.1.2
- `typescript-eslint` ^8.46.1 β†’ ^8.54.0
- `vite` ^7.1.11 β†’ ^7.3.1
- `vitest` ^3.2.4 β†’ ^4.0.18
- Added `@vitest/coverage-istanbul` 4.0.18

## πŸ”§ Chores

- Renamed package from `furystack-boilerplate-app` to `json-tools`
- Updated description and repository URL in `package.json`
3 changes: 3 additions & 0 deletions .yarn/versions/3bb2111e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
releases:
frontend: minor
json-tools: minor
1 change: 0 additions & 1 deletion e2e/page.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ test.describe('JSON-Tools Application', () => {
await page.goto('/')

const title = page.locator('shade-app-bar')
await page.hover('shade-app-bar')
await expect(title).toHaveScreenshot('title.png')

const home = page.locator('shade-home')
Expand Down
Binary file modified e2e/page.spec.ts-snapshots/home-content-chromium-linux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified e2e/page.spec.ts-snapshots/home-content-firefox-linux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified e2e/page.spec.ts-snapshots/title-chromium-linux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 7 additions & 7 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@
"vitest": "^4.0.18"
},
"dependencies": {
"@furystack/core": "^15.0.34",
"@furystack/inject": "^12.0.28",
"@furystack/logging": "^8.0.28",
"@furystack/rest-client-fetch": "^8.0.34",
"@furystack/shades": "^11.1.0",
"@furystack/shades-common-components": "^11.0.0",
"@furystack/core": "^15.0.35",
"@furystack/inject": "^12.0.29",
"@furystack/logging": "^8.0.29",
"@furystack/rest-client-fetch": "^8.0.35",
"@furystack/shades": "^12.0.0",
"@furystack/shades-common-components": "^12.0.0",
"@furystack/utils": "^8.1.9",
"@types/node": "^25.2.0",
"@types/node": "^25.2.2",
"fflate": "^0.8.2",
"monaco-editor": "^0.55.1"
}
Expand Down
22 changes: 9 additions & 13 deletions frontend/src/components/body.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,19 @@
import { createComponent, Shade, Router } from '@furystack/shades'
import { createComponent, Shade, NestedRouter } from '@furystack/shades'
import { ComparePage } from '../pages/compare.js'
import { ValidatePage } from '../pages/validate.js'
import { Home } from '../pages/home.js'
import { NotyList } from '@furystack/shades-common-components'

export const Body = Shade<{ style?: Partial<CSSStyleDeclaration> }>({
export const Body = Shade({
shadowDomName: 'shade-app-body',
render: () => {
return (
<div id="Body">
<Router
routes={[
{ url: '/compare', routingOptions: { end: false }, component: () => <ComparePage /> },
{ url: '/validate', routingOptions: { end: false }, component: () => <ValidatePage /> },
{ url: '/', routingOptions: { end: false }, component: () => <Home /> },
]}
/>
<NotyList style={{ marginBottom: '2em' }} />
</div>
<NestedRouter
routes={{
'/compare': { component: () => <ComparePage /> },
'/validate': { component: () => <ValidatePage /> },
'/': { component: () => <Home />, routingOptions: { end: false } },
}}
/>
)
},
})
18 changes: 1 addition & 17 deletions frontend/src/components/header.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { createComponent, Shade, styledShade } from '@furystack/shades'
import { AppBar, Button, AppBarLink as ShadeAppBarLink } from '@furystack/shades-common-components'
import { environmentOptions } from '../environment-options.js'
import { ScrollService } from '../services/scroll-service.js'
import { GithubLogo } from './github-logo/index.js'
import { ThemeSwitch } from './theme-switch/index.js'

Expand All @@ -12,22 +11,7 @@ const AppBarLink = styledShade(ShadeAppBarLink, {

export const Header = Shade({
shadowDomName: 'shade-app-header',
css: {
position: 'absolute',
top: '-42px',
transition: 'top 0.3s ease-in-out',
'&:hover': { top: '0' },
'&.scrolled': { top: '0' },
},
render: ({ useDisposable, injector, element }) => {
const scrollService = injector.getInstance(ScrollService)

useDisposable('scrollListener', () =>
scrollService.subscribe('onScroll', ({ top }) => {
element.classList.toggle('scrolled', top)
}),
)

render: () => {
return (
<AppBar id="header">
<AppBarLink title="JSON Tools" href="/">
Expand Down
24 changes: 11 additions & 13 deletions frontend/src/components/json-schema-selector.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Shade, createComponent } from '@furystack/shades'
import { Button, Modal, Paper, fadeIn, fadeOut } from '@furystack/shades-common-components'
import { ObservableValue } from '@furystack/utils'
import { MonacoEditor } from './monaco/monaco-editor.js'

type JsonSchemaSelectorProps = {
Expand All @@ -16,27 +15,26 @@ export const JsonSchemaSelector = Shade<JsonSchemaSelectorProps>({
marginRight: '8px',
},
},
render: ({ props, useDisposable }) => {
const isVisible = useDisposable('isVisible', () => new ObservableValue(false))
const value = useDisposable('value', () => new ObservableValue(props.schema))
render: ({ props, useState }) => {
const [isVisible, setIsVisible] = useState('isVisible', false)
const [value, setValue] = useState('value', props.schema)

return (
<>
<Button
title="Edit JSON schema"
variant="outlined"
onclick={() => {
isVisible.setValue(true)
setIsVisible(true)
}}
>
<i className="material-symbols-outlined">data_object</i>
Schema
</Button>
<Modal
title="Select JSON Schema"
isVisible={isVisible}
onClose={() => {
isVisible.setValue(false)
setIsVisible(false)
}}
backdropStyle={{
background: 'rgba(128,128,128, 0.3)',
Expand All @@ -54,33 +52,33 @@ export const JsonSchemaSelector = Shade<JsonSchemaSelectorProps>({
onclick={(ev) => ev.stopPropagation()}
onkeyup={(ev) => {
if (ev.key === 'Escape') {
isVisible.setValue(false)
setIsVisible(false)
}
}}
>
<h5>Edit JSON schema</h5>
<MonacoEditor
value={value.getValue()}
value={value}
options={{
automaticLayout: true,
language: 'json',
}}
onValueChange={(newValue) => {
value.setValue(newValue)
setValue(newValue)
}}
/>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'flex-end', paddingBottom: '.5em' }}>
<Button
onclick={() => {
isVisible.setValue(false)
setIsVisible(false)
}}
>
Close
</Button>
<Button
onclick={() => {
props.onSchemaChange(value.getValue())
isVisible.setValue(false)
props.onSchemaChange(value)
setIsVisible(false)
}}
>
Apply
Expand Down
33 changes: 9 additions & 24 deletions frontend/src/components/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,21 @@
import { createComponent, Shade } from '@furystack/shades'
import { ThemeProviderService } from '@furystack/shades-common-components'
import { PageLayout, NotyList } from '@furystack/shades-common-components'
import { Body } from './body.js'
import { Header } from './header.js'

export const Layout = Shade({
shadowDomName: 'shade-app-layout',
css: {
'& #Layout': {
position: 'fixed',
top: '0',
left: '0',
width: '100%',
height: '100%',
display: 'flex',
flexDirection: 'column',
lineHeight: '1.6',
overflow: 'hidden',
padding: '0',
margin: '0',
},
},
render: ({ injector }) => {
render: () => {
return (
<div
id="Layout"
style={{
background: injector.getInstance(ThemeProviderService).theme.background.default,
<PageLayout
appBar={{
variant: 'auto-hide',
component: <Header />,
}}
>
<Header title="JSON-Tools" />
<Body style={{ width: '100%', height: '100%', overflow: 'auto' }} />
</div>
<Body />
<NotyList style={{ marginBottom: '2em' }} />
</PageLayout>
)
},
})
Loading
Loading