naturalcrit / homebrewery

Create authentic looking D&D homebrews using only markdown
https://homebrewery.naturalcrit.com
MIT License
1.04k stars 318 forks source link

Snippet Widgets Interface #1870

Open jeddai opened 2 years ago

jeddai commented 2 years ago

Terminology:

Term Definition
gutter a CodeMirror concept -- examples would be the line numbers gutter or code folding gutter
line widget a CodeMirror concept that is a widget either above or below a line of code in the CodeMirror instance
snippet HB's integrated snippets, such as images, class tables, monsters, etc...
widget a small utility that performs a function

Description

While discussing things with the DOMT team, one of the biggest topics that came up was snippet options. The overall concept stemmed from there being a solid number of users who are very unfamiliar with HTML/CSS, and having a UI to edit snippets would be really beneficial to them.

The DOMT team was initially thinking something akin to GMB's snippet modal, but this would allow for after-insertion editing as well as initial editing (the editor could be set up to open itself when a snippet is inserted).

Thoughts

Some ideas for what this could look like:

Working proof of concept: https://github.com/jeddai/homebrewery/pull/1 Videos: monster/table frame, artist credit position

Important Notes

CodeMirror handles line widgets normally by passing in dom elements. We do not want to do this, as the redraw process behind the scenes results in a new instance of the DOM elements and focus will be lost. This can be handled by the ReactDOM render method by rendering initially to a parent element and subsequently back into the widget's DOM node. This will allow for consistent editing of text/number inputs, sliders, or any other input types we want to include.

Any react components or fragments can be rendered into the element with the method described above, which should allow for external-to-HB components such as color pickers and more detailed components like image pickers.

BornToDoStuff commented 2 years ago

I think that these small widgets are incredibly useful for options like frames and width, but would like to make the argument that looking into the future for more complex snippets it would be nice to have a more robust snippet creator at least for creation, but if possible for editing. I remember @jeddai mentioning that what is triggered for gutter widgets can be customized, meaning that if that is true, in theory a more fleshed out editor in a modal could potentially be triggered.

A use case for this would be opening up a modal to create a table, or position an image. For instance having 2 menu items for tables, one that is just "table" and another "class table". Table could open a modal that lets you set number of columns and rows, and potentially enter values for the columns and rows. Class Table could let you select third caster/half caster/full caster/blank caster/martial (and decoration/frame/etc) and remove having to have menu items for all options.

jeddai commented 2 years ago

I definitely agree, there are some snippets that could really benefit from a pre-insertion editor in a modal. I think it would be good to flesh out what snippets would benefit from something like that. At the moment it seems that tables and images would be the big two to start with, are there any other existing snippets that could use a modal editor like that?

Gazook89 commented 2 years ago

At risk of jumping ahead on such things, "new page" could offer page layouts (single column left, single column right, top half picture, etc).

Table of contents can be customized to varying levels of specificity (only to h2 headers, or all the way to h6 headers). Include all headers, or ignore headers inside divs with class n (monster, spell, etc).

BornToDoStuff commented 2 years ago

Advanced Snippet Editor

If I were to put the snippets in order for what I think would benefit the community the most to have an "advanced editor" I would say:

  1. Images
  2. Monsters
  3. Tables

I imagine that doing the image advanced editor would open the possibility to do inline images, absolutely positioned images, background images, and splatters with about 90% of the same code. Absolutely positioned images is the most important of that sub-list though, as with absolutely positioned images you can do most of what is needed for the other types with a little massaging. Inline images need relative positioning (to the column its placed in) and an option to wrap the text around it or not, a background image is just an absolutely positioned image but I think having a separate option for it is good UX, and splatters are just absolutely positioned images but with a pre-determined list that can be viewed and chosen from.

I am of the opinion that any snippet could benefit from an "advanced editor" as a popup showing what the snippet is, how to edit it, and what the code means. Educating people on how to easily use the editor is only a boon for everyone involved. However, I consider the listed 3 "essential" rather than "nice to have".

New Page Editor

Gazook's suggestion would also be a nice feature to have. Its not possible to change individual column's widths but its absolutely possible to create a page with only 1 column of any given width. I dont see it as essential as its all very doable with current markup and a simple image element, but having it would be cool and simplify some aspects of layout.

calculuschild commented 2 years ago

One thing @jeddai and I discussed was adding an easily-readable widget list either to the existing snippet files or as a separate file. Then each theme can easily be given custom widgets without having to hand-code each item:

{
        name         : 'monster',
        prefix       : '{{monster',     // Regex or something to identify the presence of a snippet in the text
        widgets :  [
                {
                        name : frame,
                        type : checkBox,
                        text : frame
                },
                {
                        name : backgroundColor,
                        type : colorPicker,
                        text : background-color:
                },
                {
                        name : positionX,
                        type : slider,
                        text : left:
                }
        ]
}

I can imagine a few types of widgets, although we can start with just two or three that @jeddai already made:

Widget Type Description Example
checkBox checkbox to add or remove related CSS to the curly-brace line "frame" can be added or removed from a monster div
colorPicker simple color wheel that changes the hex value of a color color:#ffffff. Some snippets may have optional colors, such as the color of a note block, etc.
slider or arrowBox drag a knob left or right / click up & down arrows to set a number value Used to set x or y position of an image / change image size
button One-time, repeatable effect Auto "clean up" the current table, generate lorem ipsum
table editor popup of a GUI table editor Used to easily edit table contents, set column alignments, etc.
G-Ambatte commented 2 years ago

Random thought: if we scan the text for {{monster to replace with the output of a monster Snippet function, then this is essentially the same functionality as the proposed Brew Variable system. So Advanced Snippets could leverage the find/replace functionality of Brew Vars.

calculuschild commented 2 years ago

Yes, I imagine it would be very similar. Although we may be able to approach the variables as just a Markdown extension instead with Marked.js, depending how complex we want it to be.

ericscheid commented 2 years ago

Mentioned in variables discussion: https://github.com/naturalcrit/homebrewery/discussions/1400#discussioncomment-3090819 .. TL;DR: declaring locally scoped variables could simplify the scanning/parsing involved.

So, instead of scanning for "Armor Class" in a monster block (and failing because someone translated that to french), scan for a variable name (e.g. scan for[_.AC]:=) and updating the variable value (i.e. the text that comes after :=). Then the insertion of the new AC value gets handled by the variables functionality.