passiomatic / elm-designer Goto Github PK
View Code? Open in Web Editor NEWA visual code generator for Elm UI.
License: BSD 3-Clause "New" or "Revised" License
A visual code generator for Elm UI.
License: BSD 3-Clause "New" or "Revised" License
Recently released elm-codegen package will help greatly to avoid to produce code that doesn't compile.
The idea is to generate the bindings for the Elm-ui package, add to this repo, and make it straightforward for the Elm compiler to check for any mismatched type.
Currently Elm Designer uses HTML <input type=color..>
to pick an element color. This is extremely simple to integrate but has several limitations.
We should adapt simonh1000/elm-colorpicker and extend it to allow users to pick recently used and theme colors too. Also we need to allow users to reset a color and set an "inherit" value (where applicable).
At this point specify an opacity value within the image picker seems an anti-pattern to me:
With a totally opaque color type, we can calculate contrast for accessibility evaluation easily. An alpha channel means we'd have to emulate browser mixing to do that, which I'm not sure is consistent.
— Source
So the idea is to provide a color picker without alpha value, and provide alternative UI controls to pick opacity value (for the record Adobe Photoshop does exactly that). At the moment I'm just waiting to Elm UI 2 to finalize and then follow its API.
Also interesting for the picker design:
When switching fonts the weight of the new font should match, or be closer as possible, to the weight of the old one.
The typical use-case is the following:
We can probably reuse the font-weight CSS mapping where Hairline is 100 and Heavy is 900 to figure out the best match we have available in the new font.
Inherit
The new "Insert" menu allows to create non-renderable nodes, e.g. Try to create a Radio Option outside a Radio Selection.
To fix this we need to enable/disable certain app menu items accordingly to the application status. Since we need to implement this mechanism anyway it is better to postpone this fix until we have a general purpose solution.
I'm not sure if this issue is specific to my non-standard system or not.
I'm on NixOS, a Linux distribution that does not follow standard FHS conventions. AppImages are not completely portable on this system but a tool called appimage-run
is provided.
Running appimage-run ElmDesigner-0.2.0-linux.AppImage
works. It correctly opens the GUI and echoes the following in the console:
Uncompress ElmDesigner-0.2.0-linux.AppImage of type 02 @ offset 188392
[=================================================================================================================================================================================================-] 2930/2930 100%
ElmDesigner-0.2.0-linux.AppImage is now installed in /home/theo/.cache/appimage-run/4c97e0aae6d9c722d07a00e4af6318536b8f9bd26e26682e2c13fd8cf605a0c2
(node:4997) electron: The default of contextIsolation is deprecated and will be changing from false to true in a future release of Electron. See https://github.com/electron/electron/issues/23506 for more information
On the contrary, calling appimage-run ElmDesigner-0.2.1-linux.AppImage
does not work. It exits with error code 139, printing the following in the console (no GUI is opened at all):
ElmDesigner-0.2.1-linux.AppImage installed in /home/theo/.cache/appimage-run/b34818eed209fd01ac2eed62afc6b9f15fd1bb3b26040799093c1c6b0f74cd46
Segmentation fault (core dumped)
Function CodeGen.emitAllStyles
is not generating code to honor node offsetX
, offsetY
and rotation
values.
Cannot apply a color to radio selection label.
This is an unfortunate limit of Imgbb service, which doesn't allow SVG upload. This is quite frustrating since SVG is perfect for resolution-independent icons.
I guess that for now we can restrict the accepted images types to JPEG, WebP, PNG and GIF.
Currently Elm Designer uses the native page CSS overflow and scroll behavior to allow the workspace to be bigger than the browser viewport.
We can swap the current implementation with something more polished by leveraging the Zoom
abstraction from the elm-visualization
package or elm-pan-and-zoom .
A first proof of concept implementation seems promising: https://ellie-app.com/gS7tKm4BVPNa1
We aim to mimic Figma and Sketch here and map UI commands as follows:
For normal text I can double click it and to turn it into a text input that I can then edit. It seems intuitive that the same behavior would be present for the text shown on buttons, but currently it doesn't work like that.
It can be convenient to save a node/group of elements for later. The idea is to allow the user to select a document element, name it, and save into a "user library", which is a particular section of the element library.
A user library item could be also reused in the codegen phase, by referencing it instead of duplicate its code over and over. This is probably the most straightforward way to allow some code reuse/structure in the generated code.
One interesting extension of this process could be the ability of alter the original document element and reflect changes to the "replicas" of such element. This mirrors similar concepts found in Figma or Sketch (Components and Symbols respectively).
In Elm we can think about it as a "view function": define once and reuse multiple times.
Currently library has a default number of primitive elements, which mostly maps 1:1 with Elm UI functions, stored in Library.elm
. The idea is to enrich such library at runtime, maybe using a List
field in the model, and add more document nodes when user needs it. Every new node becomes a LibraryItem
when added into such list.
Elm Designer already knows how to transform a LibraryItem
into a Tree Node
when use drags it into the workspace, and these new nodes are no exceptions.
So, if we want to implement the original-replicas scenario described above we need a way to discriminate the concrete, original elements and the replicas. We could turn Node
into a custom type:
type Node
= Original NodeData
| ReplicaOf NodeId
While traversing the document for rendering we need to handle both custom type variants, and with replicas we need look up the data for the original one, including its children - because a replica doesn't have any content.
When a replica node is selected you can go back to its original node and edit it.
Visually there's should be an obvious way to tell apart a replica from an original node. Maybe we could mark the selection border with a different color and add a little label showing the library item name.
User library must be persistent, and for now we can save it within the current document. Ideally they should be tied to user, and available cross-documents.
Instead of hand picking nice fonts from Google service we could embed in Elm Designer information for all available typefaces (see attachment) and let users to pick all the fonts they need. Picked fonts will then appear in the inspector font family drop down.
To pick more fonts we could have a "Settings" modal which includes a "Fonts" section.
Initially the modal can preset a list of top 20 used/most popular (we have some data about that in the JSON file). The user can expand one of these fonts and see its specimen, filter by category (Top 20, Sans Serif, Serif, Display, Scripts, etc.) or search for a font name. By clicking on a "Add font" button user adds the font to those available in the workspace.
Each font is referenced by name in the serialized document (see Codecs.fontFamilyCodec
) so it is easy to lookup a font (see Fonts.findFamily
).
Note: the issue that can arise is that a user install a font using the picker, save a document with that font, uninstall it and later then reopen the document. This trigger a "missing font" scenario that we'll handle in a separate way.
Using the font JSON information we can easily build the final font URL and requests actual font files from Google, like we do today.
Periodically (at each release?) we can easily refresh the font list using the Google Webfont Helper public API: https://gwfh.mranftl.com/fonts
curl https://gwfh.mranftl.com/api/font > google-fonts.json
Google Fonts dump:
google-fonts.json.zip
If an Image is inserted into a row element it collapses if it has a width=fill.
Elm UI generated code is still OK: https://ellie-app.com/f92CvrmNbXXa1 but same the image wrapped in a el
exhibits the issue: https://ellie-app.com/fyB6ZhQWGJZa1 (this is basically what happens in the editor since I need to wrap all document nodes into an extra el
element to selection highlight and other things).
This seems similar to mdgriffith/elm-ui#240
In the new web app version of Elm Designer, when user adds a new page by dropping it onto the outline view, or using Insert->Page menu item, the software sets its position to the upper left portion of the workspace (0;0).
This forces the user to "hunt" for the new page within the workspace or use "Show in workspace" context menu item to see it. We can improve the situation in various ways:
Currently code emitter tries to reduce to write redundant values like: zero padding, zero spacing, "regular" font weight, etc.
This is great but for certain elements this causes to Elm UI to pick its default values in the generate Elm code. I'll keep the list updated with the values that needs to be specified even if they are zero:
This boils down to check for Node.type_
and decide what to do while emitting each style.
Element.shrink
“Shrink an element to fit its contents.” — says the docs.
However, images has an intrinsic size so apply a shrink has no effect (see https://ellie-app.com/hqMkTncprgpa1). On the other hand, Element.fill
applied to an image should shrink or enlarge it to fill the available space.
So the UI should reflect this peculiarity. The idea is to remove the "Fit" label and allow only "Fill" and "Px" options. Now that we know uploaded images dimension (stored in ImageData
record) we could pre-populate the "Max" field if empty.
The above scenario works mostly fine. The only doubt is how we can have vertically responsive images, because if we fill along X, Y should be constrained to maintain the aspect-ratio. Vice versa, if we fill along Y, X should be constrained. It is unclear to me if elm-ui works like this at all.
Native font-stack is emitted incorrectly:
Font.family
[ Font.typeface "System"
, Font.typeface "System"
, Font.typeface "System"
]
Instead, this should list all the typefaces in the font stack.
Using the label position "hidden" option generate code that does not compile. See https://package.elm-lang.org/packages/mdgriffith/elm-ui/latest/Element-Input#labelHidden
We miss the ability to specify a border style for every element (https://package.elm-lang.org/packages/mdgriffith/elm-ui/latest/Element-Border#solid).
So let's add a new button group switcher (https://getbootstrap.com/docs/4.5/components/button-group/#basic-example) like the ones we have already, most likely positioned in the inspector between Border size and color, which sets Node.borderStyle
property accordingly. I would call the three border styles labels "Solid", "Dashed" and "Dotted".
To accomplish that a new Msg
is needed, so BorderStyleChanged BorderStyle
would do the trick.
This is how the image and text should be rendered: https://ellie-app.com/hPLZ2WjjH6Wa1
This is caused by the paragraph (not the image) being wrapped by the usual select el
element (ex. https://ellie-app.com/hPPCZBG28cMa1) - so there's an extra element which interfere with the floating behavior.
Add a media library to the UI so user can see and select again every document image.
We can add a "Media" tab right where the element library currently is and list all used images there. Once located the user could drop the image again on the document.
Once loaded to the document an image is added to the media library. The library could be a dictionary or a similar structure that is serialized together with the document.
If an image is deleted from the document it still remains in the library, ready to be added back later.
Steps to reproduce:
enter
keybackspace
key to remove the 0
from the 10
The focus needs to be reset after hitting the enter
key. I need to investigate on why this is not the case.
This is most likely linked to #7.
Currently we have a sloppy way to figure out if a border or shadow style is specified:
blur
or size
values are /= 0width
or corner
values are /= 0When the user, after tweaking the shadow or border fields, set them back to a zero value the panel collapses unexpectedly.
This is caused by the way types are currently written, e.g.:
type alias BorderWidth =
{ locked : Bool
, top : Int
, right : Int
, bottom : Int
, left : Int
}
Compare these with the Background
type which has a None
variant which precisely turns off the background style.
So a first step would be to unify the BorderWidth
, BorderStyle
, BorderCorner
and Node.borderColor
values, since it makes no sense to have separate records for them. I can see something like this could work better:
type alias BorderData =
{ locked : Bool
, top : Int
, topLeftCorner: Int
, right : Int
, topRightCorner: Int
...
, style: BorderStyle
, color: Color
}
Then we need to add the Border
type to the mix, adding a None
variant:
type Border
= None
| Solid BorderData
| Dashed BorderData
| Dotted BorderData
This way to define an element border one needs to set at least a color and a width. Elm Designer can always generate some defaults: 1px border width, solid style, dark gray color and square corners (radius with 0px).
We could change the Shadow type in the same way:
type alias ShadowData =
{ offsetX : Float
, offsetY : Float
, size : Float
, blur : Float
, color : Color
}
type Shadow
= None
| Inner ShadowData
| Outer ShadowData
With these changes None
in the UI is then set only by the click on the panel trash can icon, make it more obvious that user is gonna to delete some styles. On the contrary, when switching from Inner
to Outer
style we copy the ShadowData
record from one variant to another.
Note: This change causes a MAJOR schema change and it needs to be handled accordingly. We need to bump the schema version and create a decoder which reads back old JSON data serialized with v4.
When I remove a label, it either remove the text field or it resets to "Label"
CSS has the ability to do text transformations: (uppercase, lowercase, etc). Does Elm UI has it? It seems not the case.
So, how do you translate lower case, uppercase in the generated Elm code? Should we pass the typed string value in the editor thru String.toUpper
before rendering or CodeGen it?
Or maybe we leave the typed value untouched and we generate code that calls String.toUpper
?
I guess this is best done via a pill selector Aa | AA | aa
similar to Sketch (see below), mapped to a Elm type:
type FontTransform
= Uppercase
| Lowercase
| None
On related topic: should stuff like “small-caps”, which in Elm UI is a font feature, be in the same group of the text transformation functions? Perhaps it makes sense to a have a different place in the UI for the OpenType features.
If I look at Sketch it has a little Text Options panel (first), while Figma group everything into a Type details panel (second).
After placing a paragraph element it says "Double click to edit" but only double clicking doesn't set focus to the text input region that becomes visible. Instead a third click is needed before the user can enter text in the paragraph.
When opening https://elm-designer.passiomatic.com/ for the first time (or after I clear local storage) if I click and drag a primary button onto the page, and then drag the primary button after I've placed it, releasing it will cause the viewport to scroll really far down and to the right.
Browser: Firefox
OS: Windows 10
Internally we represent Spacing
like this:
type Spacing
= SpaceEvenly
| Spacing ( Int, Int )
This matches Elm UI nicely. However we currently don't expose this in the UI. We should model the Spacing X/Y fields accordingly. A few gotchas:
row
accepts an horizontal spacing onlycolumn
accepts a vertical spacing onlytextColumn
accepts both values and uses horizontal spacing for "floated" elements on left and rightparagraph
seems to happily ignore SpaceEvenly
(see Para1) but works like textColumn
(see Para2), see: https://ellie-app.com/c2jCXBTFB5Va1The reason why this hasn't been implemented yet is because it isn't clear how to design the UI. We can have:
TextColumn
node (and we need to fix this #59 fist!)So the only implemented scenario right now is the paragraph one, since it is quite an ad-hoc solution.
Current shadow box is nice but doesn't expose the Shadow.type_
field. We should add a Outer|Inner UI toggle/chekbox which emits the corresponding shadow
and innerShadow
Elm UI calls.
We could use a negative value for shadow "Size" field but I fear it is too obscure to find out. One nice UI thing that could be added once we have the toggle in place is to switch it by assigning a negative value to "Size" field.
Currently isn't possible to drop a background image into an element, because this will create a new image node. Hence you have to specify the image URL in the background -> image inspector panel.
The idea is to remove the editable image URL field and to allow to drop the image in the background inspector panel. The operation will trigger the usual upload progress bar, and at the end it will assign the uploaded image to the selected element background.
We can put back the image URL as a readonly field with a "copy" button aside (just like the regular image node 'info' panel).
This is caused by the option
function signature: https://package.elm-lang.org/packages/mdgriffith/elm-ui/latest/Element-Input#option which produces Option value msg
.
We could avoid to generate code for certain nodes, requiring the user to select a different element. That is, if she wants to output an option she needs to select the parent radio
.
This is probably handled out-of-the-box by a more type safe generator tool like elm-codegen, see: #63
Elm Designer still uses Parcel 1 for development and build phases.
As today I have tried unsuccessfully to switch to Parcel 2 (see the parcel2
branch). While running in dev mode everything seems smooth, but when running the "build" command Parcel hangs indefinitely.
We identified the issues being in the terser
module which interacts weirdly with the Parcel's Elm plugin, disabling it (manually) fix things.
So we can wait a bit and hope that Em and Terser work better together or we'll be forced to switch to a different bundler.
Vite seems very popular these days and it has an Elm plugin (https://github.com/hmsk/vite-plugin-elm) , but I personally never used it, so if you have experience with it let me now.
Currently the background image sizing controls in the inspector (crop/uncrop/tile) do not switch when clicked.
I wanted to build an app and this was literally the first thing I looked for, but it seems to be missing? 😅
It happened to me to remove what I've done by pressing 4 times backspaces to remove a text but I selected the field. I had 20 minutes of work disappeared haha.
I know this is early beta but this has to be done for sure ;)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.