import { html, LitElement, css } from "lit"; import { customElement, property, state } from "lit/decorators.js"; import { baseStyling } from "../styling/base.js"; import { ProjectSettings } from "@inlang/sdk"; import checkRequired from "../helper/checkRequired.js"; import overridePrimitiveColors from "../helper/overridePrimitiveColors.js"; import "./input-fields/general-input.js"; import SlSelect from "@shoelace-style/shoelace/dist/components/select/select.component.js"; import SLOption from "@shoelace-style/shoelace/dist/components/option/option.component.js"; import SlInput from "@shoelace-style/shoelace/dist/components/input/input.component.js"; import SlButton from "@shoelace-style/shoelace/dist/components/button/button.component.js"; import SlCheckbox from "@shoelace-style/shoelace/dist/components/checkbox/checkbox.component.js"; // in case an app defines it's own set of shoelace components, prevent double registering if (!customElements.get("sl-select")) customElements.define("sl-select", SlSelect); if (!customElements.get("sl-option")) customElements.define("sl-option", SLOption); if (!customElements.get("sl-input")) customElements.define("sl-input", SlInput); if (!customElements.get("sl-button")) customElements.define("sl-button", SlButton); if (!customElements.get("sl-checkbox")) customElements.define("sl-checkbox", SlCheckbox); type SchemaType = { meta?: any; schema?: { type: string; properties: Record>; }; }; @customElement("inlang-settings") export default class InlangSettings extends LitElement { static override styles = [ baseStyling, css` h2 { margin: 0; padding-top: 1rem; } .container { position: relative; display: flex; flex-direction: column; gap: 48px; } .module-container { display: flex; flex-direction: column; gap: 40px; } .hover-bar-container { width: 100%; box-sizing: border-box; position: sticky; bottom: 1rem; } .hover-bar { box-sizing: border-box; width: 100%; max-width: 500px; padding-top: 0.5rem; padding-bottom: 0.5rem; margin: 0 auto; display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 8px; background-color: var(--sl-panel-background-color); padding-left: 1rem; padding-right: 0.8rem; border-radius: 0.5rem; border: 1px solid var(--sl-panel-border-color); filter: drop-shadow(0 4px 3px rgb(0 0 0 / 0.07)) drop-shadow(0 2px 2px rgb(0 0 0 / 0.06)); font-weight: 600; line-height: 1.5; font-size: 14px; } .hover-bar-text { margin: 0; } .module-link-container { display: flex; color: var(--sl-input-help-text-color); gap: 6px; padding-top: 0.5rem; } .module-link { margin: 0; font-size: 14px; line-height: 1.5; flex-grow: 1; text-decoration: none; color: var(--sl-input-help-text-color); } .module-link:hover { color: var(--sl-color-primary-600); } .module-type { background-color: var(--sl-input-background-color-disabled); width: fit-content; padding: 0px 6px; border-radius: 2px; font-size: 14px; display: flex; align-items: center; justify-content: center; color: var(--sl-input-color-disabled); margin: 0; line-height: 1.5; flex-grow: 0; } `, ]; @property({ type: Object }) settings: ProjectSettings = {} as ProjectSettings; @property({ type: Array }) installedPlugins: Array = []; dispatchOnSetSettings(settings: ProjectSettings) { const onSetSettings = new CustomEvent("set-settings", { detail: { argument: settings, }, }); this.dispatchEvent(onSetSettings); } @state() private _newSettings: ProjectSettings | undefined = undefined; @state() private _unsavedChanges: boolean = false; override async firstUpdated() { await this.updateComplete; if (this.settings) { this._newSettings = JSON.parse(JSON.stringify(this.settings)); } //override primitive colors to match the design system overridePrimitiveColors(); } handleInlangProjectChange = ( //value needs to be exactly how it goes in the project settings json value: string, property: string, moduleId?: string ) => { //update state object if (this._newSettings && moduleId) { this._newSettings = { ...this._newSettings, // plugin: { // ...this._newSettings.plugin // [moduleId]: { // ...this._newSettings[moduleId], // [property]: value, // }, // } }; } else if (this._newSettings) { this._newSettings = { ...this._newSettings, [property]: value, }; } if (JSON.stringify(this.settings) !== JSON.stringify(this._newSettings)) { this._unsavedChanges = true; } else { this._unsavedChanges = false; } }; _revertChanges = () => { if (this.settings) { this._newSettings = JSON.parse(JSON.stringify(this.settings)); } this._unsavedChanges = false; }; _saveChanges = () => { if (this._newSettings) { this.dispatchOnSetSettings(this._newSettings); this.settings = JSON.parse(JSON.stringify(this._newSettings)); } this._unsavedChanges = false; }; private get _settingProperties(): Record< string, { meta?: any; schema?: { type: string; properties: Record>; }; } > { const _settings = this.settings; if (!_settings) throw new Error("No inlang settings"); const generalSchema = { internal: { schema: ProjectSettings } }; return generalSchema; } override render() { return html`
${Object.entries(this._settingProperties).map(([key, value]) => { // TODO remove marketplace registry (bundling is too expensive) //const item = registry.find((item) => item.id === value.meta?.id) return value.schema?.properties && this._newSettings ? html`
${value.meta && (value.meta?.displayName as { en: string }).en && html`

${value.meta && (value.meta?.displayName as { en: string }).en}

`} ${Object.entries(value.schema.properties).map( ([property, schema]) => { if ( property === "$schema" || property === "modules" || property === "languageTags" || property === "sourceLanguageTag" ) return undefined; return key === "internal" ? html` ` : html` `; } )}
` : undefined; })} ${this._unsavedChanges ? html`

Attention, you have unsaved changes.

{ this._revertChanges(); }} varaint="default" > Cancel { this._saveChanges(); }} variant="primary" > Save Changes
` : html``}
`; } } // add types declare global { interface HTMLElementTagNameMap { "inlang-settings": InlangSettings; } }