Skip to content

Commit

Permalink
update editor to react setup
Browse files Browse the repository at this point in the history
  • Loading branch information
felixhaeberle committed Jan 30, 2025
1 parent 2f6c7e0 commit bbabc97
Show file tree
Hide file tree
Showing 26 changed files with 1,653 additions and 1,101 deletions.
5 changes: 3 additions & 2 deletions inlang/packages/sherlock/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -237,15 +237,16 @@
"clean": "rm -rf ./dist ./node_modules"
},
"dependencies": {
"@inlang/sdk": "workspace:*",
"@inlang/settings-component": "workspace:*",
"@inlang/editor-component": "workspace:*",
"@inlang/recommend-sherlock": "workspace:*",
"@inlang/rpc": "workspace:*",
"@inlang/sdk": "workspace:*",
"@inlang/settings-component": "workspace:*",
"@vitest/coverage-v8": "2.1.8",
"comlink": "^4.4.1",
"fast-glob": "^3.2.12",
"https-proxy-agent": "7.0.2",
"kysely": "^0.27.4",
"lit-html": "^3.1.2",
"prettier": "^3.3.3",
"require-from-string": "^2.0.2",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
50 changes: 50 additions & 0 deletions inlang/packages/sherlock/src/utilities/editor/editor-app/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# React + TypeScript + Vite

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.

Currently, two official plugins are available:

- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh

## Expanding the ESLint configuration

If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:

- Configure the top-level `parserOptions` property like this:

```js
export default tseslint.config({
languageOptions: {
// other options...
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
},
})
```

- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked`
- Optionally add `...tseslint.configs.stylisticTypeChecked`
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config:

```js
// eslint.config.js
import react from 'eslint-plugin-react'

export default tseslint.config({
// Set the react version
settings: { react: { version: '18.3' } },
plugins: {
// Add the react plugin
react,
},
rules: {
// other rules...
// Enable its recommended rules
...react.configs.recommended.rules,
...react.configs['jsx-runtime'].rules,
},
})
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
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 },
],
},
},
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"name": "editor-app",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview"
},
"dependencies": {
"@inlang/editor-component": "workspace:*",
"@lit/react": "^1.0.5",
"@shoelace-style/shoelace": "^2.19.1",
"@types/vscode-webview": "^1.57.5",
"clsx": "^2.1.1",
"jotai": "^2.11.1",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"uuid": "^11.0.5",
"vscode": "^1.1.37"
},
"devDependencies": {
"@eslint/js": "^9.19.0",
"@types/react": "^19.0.8",
"@types/react-dom": "^19.0.3",
"@vitejs/plugin-react": "^4.3.4",
"eslint": "^9.19.0",
"eslint-plugin-react-hooks": "^5.1.0",
"eslint-plugin-react-refresh": "^0.4.18",
"globals": "^15.14.0",
"typescript": "~5.7.3",
"typescript-eslint": "^8.22.0",
"vite": "^6.0.11"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#root {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}

.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
transition: filter 300ms;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.react:hover {
filter: drop-shadow(0 0 2em #61dafbaa);
}

@keyframes logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}

@media (prefers-reduced-motion: no-preference) {
a:nth-of-type(2) .logo {
animation: logo-spin infinite 20s linear;
}
}

.card {
padding: 2em;
}

.read-the-docs {
color: #888;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { useEffect, useState } from "react"
import { vscode } from "./utils/vscode"
import Editor from "./components/Editor"
import { BundleNested, ProjectSettings } from "@inlang/sdk"

type VscodeMessage = {
command: "update",
payload: {
bundle: BundleNested,
settings: ProjectSettings
}
}

function App() {
const [bundle, setBundle] = useState<BundleNested | undefined>(undefined)
const [settings, setSettings] = useState<ProjectSettings | undefined>(undefined)

useEffect(() => {
// Listen for messages from the extension
vscode.onMessage((message: unknown) => {
const typedMessage = message as VscodeMessage; // Type assertion

setBundle(typedMessage.payload.bundle)
setSettings(typedMessage.payload.settings)
});
}, [])

return (
<div>
{bundle && settings ? (
<Editor
bundle={bundle}
settings={settings}
setShowHistory={(variantId) => console.log("Show history", variantId)}
/>
) : (
<p>Loading...</p>
)}
</div>
)
}

export default App
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import './App.css';
import { BundleNested, ProjectSettings } from '@inlang/sdk';
import { vscode } from '../utils/vscode';
import React, { FormEvent } from 'react';
import { InlangAddSelector, InlangMessage, InlangPatternEditor, InlangVariant, InlangBundle } from '@inlang/editor-component';
import {
SlDialog
} from "@shoelace-style/shoelace/dist/react";
import { createComponent } from '@lit/react';

const Editor = ({ bundle, settings, setShowHistory }: {
bundle: BundleNested;
settings: ProjectSettings;
setShowHistory: (variantId: string) => void;
}) => {
const ReactInlangBundle = createComponent({
tagName: "inlang-bundle",
elementClass: InlangBundle,
react: React,
events: {
change: "change",
},
});

const ReactInlangMessage = createComponent({
tagName: "inlang-message",
elementClass: InlangMessage,
react: React,
});

const ReactInlangVariant = createComponent({
tagName: "inlang-variant",
elementClass: InlangVariant,
react: React,
});

const ReactInlangPatternEditor = createComponent({
tagName: "inlang-pattern-editor",
elementClass: InlangPatternEditor,
react: React,
events: {
onPatternEditorFocus: "pattern-editor-focus",
onPatternEditorBlur: "pattern-editor-blur",
},
});

const ReactInlangAddSelector = createComponent({
tagName: "inlang-add-selector",
elementClass: InlangAddSelector,
react: React,
events: {
change: "change",
onSubmit: "submit",
},
});

const handleChangeEvent = (e: FormEvent<HTMLElement>) => {
console.log('bundleChange', e);
vscode.postMessage({ type: 'bundleChange', bundle });
};

return (
<ReactInlangBundle bundle={bundle} onChange={handleChangeEvent}>
{bundle.messages.map((message) => (
<ReactInlangMessage
key={message.id}
slot="message"
message={message}
variants={message.variants}
settings={settings}
>
{message.variants.map((variant) => (
<ReactInlangVariant key={variant.id} slot="variant" variant={variant}>
<ReactInlangPatternEditor slot="pattern-editor" variant={variant} />
{/* Show "Add Selector" only if there's no selector and a single variant */}
{message.selectors?.length === 0 && message.variants.length <= 1 ? (
<>
<div slot="variant-action" onClick={() => setShowHistory(variant.id)}>
Add selector
</div>
<SlDialog slot="variant-action" label="Add Selector">
<ReactInlangAddSelector
bundle={bundle}
message={message}
variants={message.variants}
/>
</SlDialog>
</>
) : null}
</ReactInlangVariant>
))}

<div slot="selector-button" className="add-selector" onClick={() => setShowHistory(message.id)}>
Add selector
</div>
<SlDialog slot="selector-button" label="Add Selector">
<ReactInlangAddSelector
bundle={bundle}
message={message}
variants={message.variants}
/>
</SlDialog>
</ReactInlangMessage>
))}
</ReactInlangBundle>
);
};

export default Editor;
Loading

0 comments on commit bbabc97

Please sign in to comment.