settings web component for inlang apps
Closed this issue ยท 32 comments
Context
Just like opral/inlang-message-ui-components#16, we need a settings web component:
- unified settings experience across inlang apps
- saving inlang app developers' resources by offering embeddable ready to use component
- (an in-app settings view will always be better than redirecting to manage.inlang.com)
Features
Must have
- #2250
- slot for custom settings cc @opral/inlang-ide-extension
- responsive
- validation (take JSON schema of settings.json and module settings schema?)
Maybe
- (?) module management
- opral/inlang-message-ui-components#19
Out of scope
- ?
Additional information
We used to believe that we should build a site like manage.inlang.com
that offers a settings view. Apps can open the external site and spare themselves from building a settings view. However, linking to an external site is a large user flow breaking point. Instead of developing one website with a settings view, we can invest the resources into a web component that apps can embed.
I am unsure about:
- which group should develop and maintain the web component. Giving @jldec the job seems wrong given that we have @NilsJacobsen @NiklasBuchfink and @felixhaeberle on the team with design engineer experience. A large part of the settings view is a) embedding into apps and b) user experience.
- If module management should be part of the settings or a separate "tab". In any case, we can push updates to the component incrementally.
I think @NilsJacobsen would be a fit:
- Its a cross app thing like the inlang website aka marketplace.
- He is responsible for manage and this would replace it.
- Felix and I already have one large and one small app. This way Nils has the website as "large app" and the web component as (hopefully) "small App".
Why not I am happy to work on that. I guess the timeframe is to get an MVP ready until we get the getting-started right?
Gonna explore a bit and select requirements for the component.
**Notes from convo with @NilsJacobsen **
- main point: how to expose styles from host app
- awesome: settings.json JSONSchema and module
settingsSchema
(also a JSONSchema) can be used to build the settings UI
Insight: The entire component is "just" a rendering engine for JSON SChemas. APp settings, module settings and project settings can all be rendered from a JSON schema.
- make project read only -> no implicit behaviour for apps
<inlang-settings
project={project}
onSettingsSet={(settings) => project.setSettings(settings)}
appSettingsSchema={appSettings}
onAppSettingsSet={(settings) => {}}
>
</inlang-settings>
First exploration into styling and other questions:
https://www.loom.com/share/b3835c31ed3745a9832754bd023cbbd0
TL;DR
- I built a quick prototype with lit, vite, storybook, and shoelace (styled with CSS variables)
Questions:
- Do we want to have versioned releases for UI? (Yes)
- Does something speak against storybook? (I like it)
- Waht do you think about the CSS variables approach for style overwrites? (I like it)
Do we want to have versioned releases for UI? (Yes)
Yes.
Create a separate package for the settings component that is released like the other NPM packages.
Does something speak against storybook? (I like it)
Nothing speaks against storybook.
Waht do you think about the CSS variables approach for style overwrites? (I like it)
Yes, good. Don't expose shoelace variables, though/have your own naming convention (ideally the same one as the pattern editor will have).
Further notes
- i would name the package "settings-component" and not nest it in "shared-ui". let's strive for a flat package structure to avoid naming convention discussions. (nesting in versioned-interfaces was a mistake :D)
Notes after a call with @felix:
-
no need to ship themes. Apps need to adjust the style to their env anyways
-
thus, ship the component with "base" style that can be overwritten by the app. Base style = for example no colors, clear that the styling is not complete BUT usable
-
variants like button small, large etc seems redundant.
@NilsJacobsen Call me tomorrow so we can clarify on a few thoughts I had after seeing your loom what led to my response loom & a call with samuel about how we should build & enforce the right things to make our life really easy by not compromise on the goal we want to achieve (highly flexible styling, unified UX).
In short: (what samuel said above and) the right set of CSS variables with near unstyled defaults make variants & themes obsolete.
Moreover, the less we have to maintain = the better & we do not have to keep syntax & theme(s) in sync all the time.
Also, let us have a brief chat about the beloved topic of icons.
please just agree to ship icons with the component. this will ensure that:
- less maintenance for apps
- unified icons for settings! (imagine app 1 having a different icon than app 2 for the same setting)
at the cost of:
- icons that might not align with the rest of the app (can be improved in a follow up v2)
- no need to ship themes. Apps need to adjust the style to their env anyways
- thus, ship the component with "base" style that can be overwritten by the app. Base style = for example no colors, clear that the styling is not complete BUT usable
Apps have full control over styles, but if they want to take the base styling with small adjustments there is no need to define 300 CSS variables. Problem: If I build an app with dark styling I basically need to manually invert 300 tokens, instead of importing the dark base styling and change only the primary color. That was the idea.
We can also remove the dark styling for now. Because the ide extension can not set static dark themes, because it is based on a user-based theming.
Our UI will use a lot of shoelace components under the hood. The easiest way to style them is to change their css variables. So why not just using the same system with a inlang-token wrapper. That makes my components so much easier.
Let me explore how to make the wrapper.
the right set of CSS variables with near unstyled defaults make variants & themes obsolete.
variants like button small, large etc seems redundant.
Well the idea was to use CSS variables. They are used as a theme at shoelace. Where is this variant thing coming from?
If I build an app with dark styling I basically need to manually invert 300 tokens, instead of importing the dark base styling and change only the primary color. That was the idea.
Q: This will never meet the apps reqs in terms of styling. Think about it: If I have an app which supports dark mode, would I really want the settings component dark theme?
A: Likely not, because this theme works with its own shades of black which is not working with my own design which ships with other shades of black. There will always be the case of adjusting variables in order to unify the styling.
Real life example
Could Fink use this dark theme? No, Fink doesn't even support dark mode yet. Does the VS Code extension need it? No, there is no such thing as "dark theme" in VS Code, but 1000+ dark themes all with slightly different colors where I want the settings component to match every time to not look broken/alien.
Proposal
Ship the component with near unstyled defaults (a bit like a blank html page but a bit more beautiful) that it doesn't look broken and let the app handle the design from a-z.
@felixhaeberle You mean, just take the base color and text color from the parent? This way it always fits the theme. (black on white in Fink, white on gray in VS code default theme, etc)
Call with felix:
- we don't do the dark theme for now because we don't have a use case
- we provide base set of tokens (as a base theme)
- app users can override them
Update:
https://www.loom.com/share/543ed27d63a74608a5134718b56e9ae2
Two questions:
- Should we name the component
<inl-settings/>
while the package is named@inlang/settings-compoenent
? - Samuel can clarify the versioned interface mistake?
Should we name the component while the package is named @inlang/settings-compoenent?
Don't abbreviate. Name it <inlang-settings>
. The package name and HTML tag name prob do not need to align.
Samuel can clarify the versioned interface mistake?
Nesting is wrong. Just have a flat packages registry. Same problem with namespaces for keys.
Update settings component:
https://www.loom.com/share/25cac383d4164fbdb4c26018d7697971?sid=5de62c4e-19d2-4bf6-a00e-949d0574c6c8
TL;DR
-> Deriving the input fields from the schema and filling it with the settings was pretty straight forward
Save behaviour:
@NiklasBuchfink @felixhaeberle @martin-lysk
What do you expect from an input field in the settings?
1. Autosave
Pro:
- easy
- we need to indicate that a save happened (like the check mark in fink)
Cons:
- We need to validate after each keystroke (which could also be nice)
- If we save after every keystroke, that should not affect a reload of the app (might depend on apps)
2. Save per input
Pro:
- Known pattern
- Explicit
- Less frequent updates callback
Cons:
- not that fast
3. Save the whole form
Pro:
- Easy to maintain
- Known pattern
- Explicit (not as explicit as the save per input)
- Less frequent update callbacks
Cons:
- Save button placement is crucial
Takeaways from GH UI Guide -> https://primer.style/ui-patterns/saving
- Autosave only for toggles, single selects and menus
- Save should always be in view
- Group save must be obvious
- Don't mix auto-saving controls and explicitly saved controls
- Alert unsaved changes
- Never hide or disable save buttons
Proposal: Let's start with save whole form
Proposal: Let's start with save whole form
Agree. Have a save button that is always visible (not at the very bottom!) and nudges users to save their changes.
Only a WIP: Update before the weekend
https://www.loom.com/share/5b9914cdcb1c420086faa12092ac961e
@NilsJacobsen i propose to design the settings UX in figma before you code stuff. you can align everyone much better if you show what the resulting UX will be rather than showing "i coded this".
https://www.loom.com/share/9894ef2e87c94160b0afd0c92ba41d7a?sid=3963f6f6-2899-4ff7-aab0-d8b161cc7ee6
Quick feedback:
-
Most apps won't need the headline / context: "Project Settings" and subheadline are therefore to be put by apps if they needs this in the context.
-
Would be cool to have full control over the width of buttons and inputs, I likely want to have all input fields 100% width in really small widths (or you account for that ootb)
-
The save overlay is a pattern not being used by the vscode extension for example and therefore inherits a UX the user might not be familiar with.
-
Extending 3, I don't know how to style this element (overlay) with elevation from the background, because the "grey" color you anticipated for it already in the design mockup doesn't reliably exist in the vs code coloring hierarchy.
There are a few minors still in addition to that, but we can clean this is development.
@NilsJacobsen can you share the link to the exaclidraw? It's likely easier to comment directly on the excalidraw.
I have several questions about the UX flow:
- what happens if a user clicks "add module"?
- should module management be in the scope of v1?
- should module management be split in lint rules and plugins? yes, they are "modules" under the hood but does a user need to know that? aren't they looking for plugins and lint rules?
+1 for not exposing the concept of modules to users in the settings display but rather split them into the logical blocks/types = plugins & lint rules.
how is this currently being solved at manage.inlang.com ?
Excalidraw link: https://app.excalidraw.com/s/1RmnkzJA3Ph/7X9Tbfx6kAn
separate plugin and lint rules
yes
Remove modules for v1
-> + 1
save overlay?
let's have a quick chat @felixhaeberle
Decision in call with @NilsJacobsen @felixhaeberle:
Design the settings component as a dedicated "page". The tradeoff to design the component "embedabble" (to be rendered in the page of an app) is too high with questionable UX outcomes.
The tradeoff to design the component "embedabble"
This tradeoff should be accounted for / fixed sometime in the future but for a v0, the approach of introducing a component based save UX is tolerable.
closing because duplicate. see progress in https://linear.app/opral/project/seed-round-2fdb85393b97