Export HTML in format similar to LEO desktop

282 views
Skip to first unread message

brian

unread,
Sep 3, 2025, 12:15:10 AMSep 3
to leo-editor
Is there a way to export an outline in an html format where the format of the html is similar to the desktop version of Leo with the expands and collapses.  I want to send someone a copy of my outline that they can use in a browser to view.  This is view only.    

I tried the plugin leo to html but it seems that this is for an outline that was written as html.  

I tried RST3 but the html is all on the left margin and I’m getting weird error messages.  

I read about rendered view exporting as html but I couldn’t get the html to be export.  

I saw a JS port of leo for the web but I suspect I’l have to host a version.  I just want to send an html document that everyone can use out of the box.  

It looks like I’ll have to write a plugin.  Would RST3 be the best place to start?  

Brian  

Thomas Passin

unread,
Sep 3, 2025, 8:31:22 AMSep 3
to leo-editor
You haven't explained how you want your users to interact with the outline. Should they be able to edit, create, and destroy nodes?  Or do you want them to only be able to read it.  Do you want subtrees to be able to collapse and expand as they can in Leo?

Do you want to be able to export arbitrary outlines, or would you be satisfied with some specialized kind?  For example, you can create a very good documentation-like set of HTML pages by using Sphinx, but you have to write the outline in ReStructuredText (RsT) and run the rst3 command on it first. BTW, rst3 will not create an HTML document in itself.  It creates a set of nodes into linked RsT files, which can then be transformed into an HTML version.

If you don't mind using just a little RsT or Markdown in your nodes, you can produce very good HTML output using the Viewrendered3 (VR3) plugin. VR3 can export a node or an entire tree to very readable HTML, but it won't have Leo's interactivity.

Unfortunately, Leo's export-xxx commands seem to only export a view of the outline, without the node content.

So please think some more about what you want to accomplish with an export. If you were thinking of sending a set of HTML files and viewing them in a browser with full Leo capability, that would require re-creating full Leo capability in javascript. Felix has done that with LeoJS except that it's running in Visual Studio Code instead of a browser.  

Thomas Passin

unread,
Sep 3, 2025, 9:01:48 AMSep 3
to leo-editor
I posted the last message before I was finished.  I meant to add that the effort of reproducing Leo in a browser, similar to what Felix has done with LeoJS, is an enormous years-long effort, so don't plan on doing that in a plugin anytime soon.

brian

unread,
Sep 3, 2025, 11:23:48 AMSep 3
to leo-editor
I don't want the person to be able to modify the outline.  That is what I meant by "read only".  I want someone to view a representation in a browser that is similar to how it looks in the installed version of Leo and without having to install the leo executable.  I do want expand and collapse.  I know how to create expand and collapse in html but I'm not sure how to get the content out of Leo.  

I looked at LeoJS and didn't consider because it can only be used in VS code.  I want to send someone a self contained html file they can double click on and view in the browser.  

I'm only concerned about exporting the outlines I create.  My outlines mostly have text but a few nodes have markdown.  

I'm not sure what you mean by "write the outline in RsT" and run rst3.  When I ran Rst3, all the content in the html was on the left margin and it got confused about some of the node headlines (e.g., something like "I.  Learn about leo").  I don't want a lot of constraints on the outlines I create.  I'm fine with minor edits but I don't want have to rework every node.  After trying Rst3, I assumed it could not do the task.  If rst3 can do this, I'd rather not write a plugin.  Can you point me in the right direction to get rst3 to do what I want?  

I looked at VR3 and I could figure out how to export my entire outline.  The documentation I found was sparse and I didn't dig into the source code.    

I've written the HTML with a hard coded outline where nodes will expand and collapse (used Bootstrap).  I just need to get my data out of Leo and into my html.  I planned on using the Django template engine to generate the html.  I assumed this would be an easy task.  LeoJS is a huge undertaking.  It seems tweaking rst3 to export to the Django template engine would be simple tweak of rst3.  If I'm missing something, let me know.    

I'm looking for the easiest path to go from my Leo outline to html in a format I want.         

brian

unread,
Sep 3, 2025, 12:07:44 PMSep 3
to leo-editor
Also, I want some way to add tags in the outline that will get included in the html.  For example, tool tip.

Thomas Passin

unread,
Sep 3, 2025, 1:18:17 PMSep 3
to leo-editor
On Wednesday, September 3, 2025 at 11:23:48 AM UTC-4 brian wrote:
I don't want the person to be able to modify the outline.  That is what I meant by "read only".  I want someone to view a representation in a browser that is similar to how it looks in the installed version of Leo and without having to install the leo executable.  I do want expand and collapse.  I know how to create expand and collapse in html but I'm not sure how to get the content out of Leo.  

Getting output from Leo is easy.  You walk the tree and for each node output headline and body text with whatever format you like.  The hard part is working out what the HTML should be, including how to manage and display the nesting level.
 ...
> I'm only concerned about exporting the outlines I create.  My outlines mostly have text but a few nodes have markdown.  

Do you want those markdown nodes to look as they do in the body editor, or do you want them rendered by a Markdown processor?

>  I'm not sure what you mean by "write the outline in RsT" and run rst3.  When I ran Rst3, all the content in the html was on the left margin and it got confused about some of the node headlines (e.g., something like "I.  Learn about leo").  I don't want a lot of constraints on the outlines I create.  I'm fine with minor edits but I don't want have to rework every node.  After trying Rst3, I assumed it could not do the task.  If rst3 can do this, I'd rather not write a plugin.  Can you point me in the right direction to get rst3 to do what I want?  

The rst3 command is oriented to creating an overall tree of RestructuredText (RsT) files in a form that Sphinx will be able to process to produce a set of documentation files, which are usually HTML but could also be pdf or other formats. The command by itself isn't going to create a nice finished HTML file. For this to make sense, the nodes in an @rst tree need to be written using RsT (Sphinx can be made to use Markdown files too, but the rst3 command only knows about RsT).

> I looked at VR3 and I could figure out how to export my entire outline.  The documentation I found was sparse and I didn't dig into the source code.    

VR3 renders the tree's body, creating headlines using the text of each node's headline. It sounds like you want to include an outline panel, and VR3 won't do that.

> I've written the HTML with a hard coded outline where nodes will expand and collapse (used Bootstrap).  I just need to get my data out of Leo and into my html.  I planned on using the Django template engine to generate the html.  I assumed this would be an easy task.  LeoJS is a huge undertaking.  It seems tweaking rst3 to export to the Django template engine would be simple tweak of rst3.  If I'm missing something, let me know.    

As I said, you walk the tree of nodes in your outline, and output whatever you want based on the output format you want to create.  Walking the tree is easy. I've never used Django templates and I don't know what they should look like. To process the tree starting at the currently selected node (c.p), your script could look like this:

    for p1 in c.p.subtree():
        headline = p1.h
        text = p1.b
        # Do something with the the headline and text
        # Indentation level is p1.level()

> I'm looking for the easiest path to go from my Leo outline to html in a format I want.         
... It looks like I’ll have to write a plugin.  Would RST3 be the best place to start?  

You don't need a plugin, as best I can see, certainly not for experimenting until you can produce what you want.  You only need a Leo script, which you can attach to a button. Then select the top node you want to start from, and press the button to run the script. You could develop the whole thing in Leo's workbook. 

As I said, the hard part is figuring out what the output should look like. Anything that links two different nodes together is going to be harder.  Anything that assembles several pieces of information (like tooltips that can optionally be made visible ) is going to be harder.  But those are not Leo issues. They are format and output issues.  That's what you need to figure out first.

jkn

unread,
Sep 3, 2025, 2:32:45 PMSep 3
to leo-editor

ISTM that the OP just wants a 'style' of HTML output that will be rendered with output text optionally expanded or collapsed, according to where a viewer might click on the rendered output.

This is often seen in modern web pages when looking at code-oriented content. I haven't got an example to hand, but one should be easy to find.

I'd have thought the main issue was understanding how such HTML/CSS(+Javascript?) works ... once that is done, actually creating the exporter should be fairly easy.

Just my $.02 ...
    J^n

jkn

unread,
Sep 3, 2025, 3:44:43 PMSep 3
to leo-editor

Edward K. Ream

unread,
Sep 3, 2025, 4:25:33 PMSep 3
to leo-e...@googlegroups.com
On Tue, Sep 2, 2025 at 11:15 PM brian <yakka...@gmail.com> wrote:

Is there a way to export an outline in an html format where the format of the html is similar to the desktop version of Leo with the expands and collapses.  I want to send someone a copy of my outline that they can use in a browser to view.  This is view only.    

I tried the plugin leo to html but it seems that this is for an outline that was written as html.

I strongly recommend running vs-code (or vscode.dev) with the LeoJS plugin installed. Using vscode.dev is a quick (zero install!) solution. LeoJS is what you want. Imo, you are wasting your time doing anything else.

Edward


 

I tried RST3 but the html is all on the left margin and I’m getting weird error messages.  

I read about rendered view exporting as html but I couldn’t get the html to be export.  

I saw a JS port of leo for the web but I suspect I’l have to host a version.  I just want to send an html document that everyone can use out of the box.  

It looks like I’ll have to write a plugin.  Would RST3 be the best place to start?  

Brian  

--
You received this message because you are subscribed to the Google Groups "leo-editor" group.
To unsubscribe from this group and stop receiving emails from it, send an email to leo-editor+...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/leo-editor/4c3aa801-903b-4150-b50b-3d0cf3a193a4n%40googlegroups.com.


--
-----------------------------------------------------------------
Edward K. Ream: edre...@gmail.com
-----------------------------------------------------------------

Thomas Passin

unread,
Sep 3, 2025, 4:26:39 PMSep 3
to leo-editor
The OP wrote that he knows how to make collapsing outline-style lists. I used to make them with nested UL lists, formatted with CSS to automatically apply the indentation.  The CSS can also be used to provide vertical guide lines for the indent level.  IMO, one doesn't need to import packages or use templates to do the job, but everything depends on the detailed things the OP wants to do. I used frames to contain the left and right panels, but that, I know, is considered old fashioned.

Once you have the expandable outline under control, the next thing to solve is how to link a click on an outline node with the display of its contents. It's not hard, but you do need to figure it out.

Then you may want a search function ...

brian

unread,
Sep 3, 2025, 10:32:10 PMSep 3
to leo-editor
I attached a sample leo file and the desired html output.  I'm not sure the best way to add tool tips, title, and sub-title in leo.  My actually leo file that I want to generate the html for caused  RST3 to generate errors.  

@tbp1
I envision running every node body through markdown render.  Thank you for the snippet of code.  The code will get me started.     

@edward 
My goal is to generate a self contained html file that I can send to someone so they can view the content I created without installing leo.  I'm using leo as an outlining tool and not as a software development tool.  With the html someone can double click the html file and view a representation of the outline in a browser.  Some people have issues with installing software so I'm trying to avoid forcing someone to install leo.  Some businesses require IT sign off before even thinking about installing software.  Having to install leo could be a blocker.  LeoJS  will not work since it has to be setup with VS code.  It is easier for someone to install leo than setup LeoJS with VS code.  A non-dev will be lost in VS code.    

My plan is to use leo to quickly create prototype variations and then if the idea gets traction, rewrite in an actually web app.  I'm debating if it is easier to go straight to the web app.  I'm going on using leo 20 years and I love organizing content with it.  I use leo daily to organize my notes.        
desired_output.html
sample_input.leo

Thomas Passin

unread,
Sep 3, 2025, 11:40:33 PMSep 3
to leo-editor
All right, that looks simple enough.  You just have to track the nesting level and back out of it when the level decreases - emit a <div> when the level increases (which will always be by 1) and emit a </div> for each decrease in the node level (the decrease might be any number of steps). Forget rst3.  It's not designed to do anything like this. Just walk the tree and emit the corresponding HTML, which you have already designed. Since everything will happen in order, you will have almost no complications, expect maybe for the tool tips.  I don't know if they are tied to nodes or function/method names.

If you decide you want to render markdown that may be in some nodes, look at the code in plugins/viewrendered3.py, the part where it converts the markdown to HTML. It should give you a head start.

If and when you do start writing your web apps, you can write them in Leo outlines. As a 20-year Leo user I suppose that's what you would automatically think about doing.

Edward K. Ream

unread,
Sep 4, 2025, 5:54:59 AMSep 4
to leo-e...@googlegroups.com
On Wed, Sep 3, 2025 at 9:32 PM brian <yakka...@gmail.com> wrote:
 

@edward 
My goal is to generate a self contained html file that I can send to someone so they can view the content I created without installing leo.  I'm using leo as an outlining tool and not as a software development tool.  With the html someone can double click the html file and view a representation of the outline in a browser.  Some people have issues with installing software so I'm trying to avoid forcing someone to install leo.  Some businesses require IT sign off before even thinking about installing software.  Having to install leo could be a blocker.  LeoJS  will not work since it has to be setup with VS code.  It is easier for someone to install leo than setup LeoJS with VS code.  A non-dev will be lost in VS code.    

My advice is to use vscode.dev if at all possible.

Edward

Thomas Passin

unread,
Sep 4, 2025, 9:54:42 AMSep 4
to leo-editor
With LeoJS in vscode.dev, outlines have to be in a GitHub repository.  The OP probably doesn't want to be limited like that. 

Félix

unread,
Sep 4, 2025, 2:36:05 PMSep 4
to leo-editor
Hi Brian. Great question. Indeed your concept could be very useful. I'll try my hand at it this week-end. 

And yes leojs is great, but like Thomas said, it's a full fledged leo that is not a minimal html readable tree that you would like

Thanks for your interest in Leo 😃

Hopefully ill get something that would fit the bill in a few days when i have some free time

Félix

jkn

unread,
Sep 4, 2025, 3:45:01 PMSep 4
to leo-editor
Hi Felix - whilst you are here...

I was reminded about LeoJS by Thomas' comment, and also: "With LeoJS in vscode.dev, outlines have to be in a GitHub repository"

OOI, does it have to be in Github (only)? eg. could an outline be in Gitlab, for instance?

Thanks a lot
    J^n

Thomas Passin

unread,
Sep 4, 2025, 4:07:39 PMSep 4
to leo-editor
vscode.dev doesn't offer any control or menu to open a project except in GitHub or some equivalent Azure system. It seems to be very closely tied to GitHub.  However, if there is a Leo outlne in a GitHub project, you can open it in LeoJS without explicitly going through vscode.dev. You click on the file, which brings up a browser view in GitHub. There is a pencil icon for more edit options. One of these is for github.dev. This is actually a version of vscode.dev.  When it opens, you can install the leoJS extension and then open any Leo outline in the repo in leoJS.

Edward K. Ream

unread,
Sep 5, 2025, 3:56:24 AMSep 5
to leo-editor
On Thursday, September 4, 2025 at 1:36:05 PM UTC-5 Félix wrote:

Hi Brian. Great question. Indeed your concept could be very useful. I'll try my hand at it this week-end. 

And yes leojs is great, but like Thomas said, it's a full fledged leo that is not a minimal html readable tree that you would like

Thanks for your interest in Leo 😃

Félix, there is no one but you I would trust with such a project. Only you have the deep knowledge of Leo, your LeoJS scripts, and web technology that would be required for such a project.

But does the OP's request make sense? Isn't  possible malware another name for an .html file? How will distributing Leo outlines as .html files pass the first security sniff test?

Edward

Thomas Passin

unread,
Sep 5, 2025, 9:09:05 AMSep 5
to leo-editor
On Friday, September 5, 2025 at 3:56:24 AM UTC-4 Edward K. Ream wrote:
Félix, there is no one but you I would trust with such a project. Only you have the deep knowledge of Leo, your LeoJS scripts, and web technology that would be required for such a project.

But does the OP's request make sense? Isn't  possible malware another name for an .html file? How will distributing Leo outlines as .html files pass the first security sniff test?

It seems to me that the display of an outline should be read-only, with a few interactive features like expanding nodes. That way the user doesn't need to learn anything special. Security aside, this brings in the tricky question about how to handle @other trees in a way that a user can understand without climbing a learning curve. Named sections don't present a problem, I think.  I'm also sure that sentinels should not be visible.  I don't know where that leaves Leo directives.

Security might be a real concern.  OTOH, a Leo outline running in Leo could also be a security concern - it could modify a standard Leo command to do something nefarious. For myself, I use a javascript blocker in my browser. It would be best if the read-only representation of a Leo outline wouldn't need to import any script packages, for then a script blocker won't need to be told to make an exception, which once again could become a security matter.

Edward K. Ream

unread,
Sep 6, 2025, 7:14:35 AMSep 6
to leo-editor
On Friday, September 5, 2025 at 8:09:05 AM UTC-5 Thomas wrote:

It seems to me that the display of an outline should be read-only, with a few interactive features like expanding nodes. That way the user doesn't need to learn anything special. Security aside, this brings in the tricky question about how to handle @other trees in a way that a user can understand without climbing a learning curve. Named sections don't present a problem, I think.  I'm also sure that sentinels should not be visible.  I don't know where that leaves Leo directives.

 This seems straightforward, and it would be tempting to charge ahead with coding.

Security might be a real concern.

 Unless I misunderstand the OP, security is the only concern. Otherwise, people could just install Leo or LeoJS.

Before discussing this topic further,  I recommend that Brian consult with management what would be acceptable. Unless then, our discussions lack direction. I don't envy anyone trying to keep a company's computers free from malware. I would clear any plan first.

OTOH, a Leo outline running in Leo could also be a security concern

Absolutely! As I write this, I see that Leo should have an info item about security. The general rule is:

    Be wary of receiving a .leo file from anyone you don't know and trust.

Leo prevents any outline except myLeoSettings.leo from setting @bool scripting-at-script-nodes = True.
I thank Paul Patterson for pointing out the danger.

But Leo can do nothing to prevent the unwary from foolishly clicking a button in an outline from an unknown source. In this sense, passing .leo files around should be a real security concern.

- it could modify a standard Leo command to do something nefarious. For myself, I use a javascript blocker in my browser. It would be best if the read-only representation of a Leo outline wouldn't need to import any script packages, for then a script blocker won't need to be told to make an exception, which once again could become a security matter.

I don't believe BitDefender would likely detect malicious .leo file. They would likely constitute a Day zero exploit.

Summary

Before exploring this topic further, I believe Brian should consult with his management to determine whether there are any acceptable use cases for using any form of Leo, including .html files.

Edward

Thomas Passin

unread,
Sep 6, 2025, 8:47:06 AMSep 6
to leo-editor

On Saturday, September 6, 2025 at 7:14:35 AM UTC-4 Edward K. Ream wrote:
... 
But Leo can do nothing to prevent the unwary from foolishly clicking a button in an outline from an unknown source. In this sense, passing .leo files around should be a real security concern.

- it could modify a standard Leo command to do something nefarious. For myself, I use a javascript blocker in my browser. It would be best if the read-only representation of a Leo outline wouldn't need to import any script packages, for then a script blocker won't need to be told to make an exception, which once again could become a security matter.

I don't believe BitDefender would likely detect malicious .leo file. They would likely constitute a Day zero exploit.

I agree; I was only referring to read-only representations that don't include executable scripts. Exploiting them would require smuggling new code in using imports of external libraries. That's what a javascript blocker could prevent. As could a simple representation that doesn't need to use imported libraries.

Edward K. Ream

unread,
Sep 6, 2025, 9:14:35 AMSep 6
to leo-e...@googlegroups.com
My concern is that any .html file, no matter how supposedly simple, could contain malware.

We aren't going to be generating malware, and we aren't going to be knowingly passing around malware, but how do we prevent others from adding malware to our .html files?

In other words, trusting Félix doesn't solve our security problems.

Edward

brian

unread,
Sep 6, 2025, 12:58:10 PMSep 6
to leo-editor
@Félix 
Let me know if you want to work together one this.  Currently, I'm working on the Django aspect.  My current plan is to use pydantic to create a nodeWrapper that has a children field that is a list of other nodeWrappers.  

@Edward,
You are correct about still being a security issue with html.  Most companies have protections against web attacks.  

My thought is most users won't have admin access to their work computer so they would have to go through IT which would take a lot of time and may not be able to happen.  I suspect attaching a html file will be able to be opened.  But worst case, I can put the html on my website and give them a link. 

I didn't realize VS code has a web based version. 

Félix

unread,
Sep 7, 2025, 12:12:53 AMSep 7
to leo-editor
@Edward @Brian

Let me cook...  😎

@jkn 

Oh! -> about gitlab: great question! I'll look into it when I have more time. But about vscode.dev: going to github.com instead of vscode.dev is much better! See this video I made explaining 'why' and 'how' within the first minute of the video https://www.youtube.com/watch?v=M_mKXSbVGdE

Now, I'll try to finish a working HTML export demo tonight!
--
Félix

Edward K. Ream

unread,
Sep 7, 2025, 6:08:27 AMSep 7
to leo-editor
On Saturday, September 6, 2025 at 11:58:10 AM UTC-5 brian wrote:

@Edward,
You are correct about still being a security issue with html.  Most companies have protections against web attacks.  

My thought is most users won't have admin access to their work computer so they would have to go through IT which would take a lot of time and may not be able to happen.  I suspect attaching a html file will be able to be opened.  But worst case, I can put the html on my website and give them a link.

I don't see how anyone can protect against a JS onLoad event that executes text in a .leo file. But I'll leave it at that. I've stated my security concerns.

Edward

Edward K. Ream

unread,
Sep 7, 2025, 6:10:22 AMSep 7
to leo-editor
On Saturday, September 6, 2025 at 11:12:53 PM UTC-5 Félix wrote:
@Edward @Brian

Let me cook...  😎

No doubt this is an interesting project. I'll be interested to see your results! And I would be interested to hear your thoughts about security.

Edward

Félix

unread,
Sep 7, 2025, 2:25:16 PMSep 7
to leo-editor
@Edward About security with relation to a html file content.

I think in an office setting, an executable, or a pdf file or microsoft-office document containing a malicious macro to be run is far worse.

Unlike running  a python script, (or any other scripting environment like a macro in excel , etc.) a browser running a web page /html script cannot arbitrarily read/write files on your hard drive. Even if it the browser's executable is run as admin,  the browser will bring up warning and permissions dialogs. That is because browsers do not open/load nor follow links with the "file://:" protocol.  You have to start up a web server so that the protocol is "http://localhost/blablabla/index.html" for the browser to load/open files..

The only thing you can do locally with an html file opened directly from the filesystem on your hard-disk is : rendering that html file 'alone'. - That is why it then has to be self-contained. Meaning that all the css styling and javascript scripts have to be inline in the file and cannot be imported in the html header from other script.js and style.css files like on a regular web page.

Malevolent webpages and/or html does not have to do with typical security concerns (file read/write on your hard-drive) but instead have to do with mimicking graphical design and layout of the html page, (like for your own bank, and have your real name and personal info printed on it that they automatically got somewhere else because its public info) to have the user confidently put in credentials. (to enter a fake sweepstake, or fake login, etc...) 

So in conclusion, opening a local html file in your browser is not a security concern in itself. 

Félix



Edward K. Ream

unread,
Sep 7, 2025, 8:15:38 PMSep 7
to leo-e...@googlegroups.com
On Sun, Sep 7, 2025 at 1:25 PM Félix <felix...@gmail.com> wrote:
@Edward About security with relation to a html file content.

Thanks for this detailed response. 

I think in an office setting, an executable, or a pdf file or microsoft-office document containing a malicious macro to be run is far worse.

Unlike running  a python script, (or any other scripting environment like a macro in excel , etc.) a browser running a web page /html script cannot arbitrarily read/write files on your hard drive. Even if it the browser's executable is run as admin,  the browser will bring up warning and permissions dialogs. That is because browsers do not open/load nor follow links with the "file://:" protocol.  You have to start up a web server so that the protocol is "http://localhost/blablabla/index.html" for the browser to load/open files..

The only thing you can do locally with an html file opened directly from the filesystem on your hard-disk is : rendering that html file 'alone'. - That is why it then has to be self-contained. Meaning that all the css styling and javascript scripts have to be inline in the file and cannot be imported in the html header from other script.js and style.css files like on a regular web page.

Does that mean that scripts in local html files (including onLoad) never run? That would be jolly.

Malevolent webpages and/or html does not have to do with typical security concerns (file read/write on your hard-drive) but instead have to do with mimicking graphical design and layout of the html page, (like for your own bank, and have your real name and personal info printed on it that they automatically got somewhere else because its public info) to have the user confidently put in credentials. (to enter a fake sweepstake, or fake login, etc...) 

So in conclusion, opening a local html file in your browser is not a security concern in itself. 

That's good to know!

Félix

brian

unread,
Sep 7, 2025, 11:20:20 PMSep 7
to leo-editor
@Félix
How to you want to colab?  I'm an independent hacker so I haven't joint developed before.  If you want to setup a github project, my user name is:  briancdowning

I've written a pydantic model and written a Django app to take an instance of the model and create the html.  
Here is pydantic model and an instance of it:
----------------------------------------------------
from typing import List, Optional

from pydantic import BaseModel

class NodeWrapper(BaseModel):

  headline: str

  body: str

  htmlId: int

  tooltip: Optional[str] = None

  children: Optional[List['NodeWrapper']] = []

NodeWrapper.model_rebuild()


#section 1 -> section 1.1 -> section 1.1.1

section1p1p1Node = NodeWrapper(

  headline="Section 1.1.1",

  body="This is even more deeply nested content under Section 1.1.1.",

  htmlId=1,

)

section1p1Node = NodeWrapper(

  headline="Section 1.1",

  body="This is nested content under Section 1.1.",

  htmlId=2,

  children=[section1p1p1Node],

)

section1Node = NodeWrapper(

  headline="Section 1",

  body="This is the content under Section 1.",

  htmlId=3,

  children=[section1p1Node],

  tooltip="Random tip: Rotate the knob gently to start calibration.",

)

-------------------------------------------------------------------

Currently, my plan is to run the body text through a markup lib to create the html.  

I'm planning on making the field htmlId of the model optional and then auto generate the id in my code.  

Currently, I have everything written as a Django App.  I'll need to repackage to run in a plugin   

Félix

unread,
Sep 8, 2025, 1:09:17 AMSep 8
to leo-editor
@brian 

Hi! 

I'm almost done with a proof-of-concept demo which will be easily adaptable to your specific needs.

I've made it into a self-contained html file because it's quite easy and not that big at all (Having the whole thing be read only for someone to browse - without needing to have the whole of Leo's editing functionality - makes it possible to be quite small)

I've written the converter, and the javascript to allow navigation in the outline (expand collapse, etc...) and it obviously shows the proper body pane content on node selection/navigation.

Something like a totally stripped down leovue from Joe Orr in pure vanilla html+javascript that fits in under 500 lines of code.

 I'll make a repo to share and collaborate in a day or two: I just want to polish my keyboard navigation and to cleanup my code :)

Félix

Edward K. Ream

unread,
Sep 8, 2025, 5:30:44 AM (14 days ago) Sep 8
to leo-e...@googlegroups.com
On Mon, Sep 8, 2025 at 12:09 AM Félix <felix...@gmail.com> wrote:

I've written the converter, and the javascript to allow navigation in the outline (expand collapse, etc...)

What happens if someone replaces your javascript with malicious code and distributes the resulting .html file?

Edward

Thomas Passin

unread,
Sep 8, 2025, 4:04:06 PM (14 days ago) Sep 8
to leo-editor

Félix

unread,
Sep 8, 2025, 11:51:55 PM (13 days ago) Sep 8
to leo-editor
@Edward 

You're right - unknown html files, unlike safer PDF file, images, word documents, etc., are a security risk and people should not 'open/run' by double clicking on a html file willy-nilly.

For instance, when I went through Brian's example in notepad first, just to make sure...

But I'm a web developper, so I could recognized the imports he made as standard bootstrap from known 'content-delivery-networks' or "CDN" which are harmless and expected.  So yeah, people should not open those if they are not sure of having confidence in them like I did.

(But some html file is still less dangerous than a python script, or a leoscript that is ran (CTRL+B). because those have network AND full file read/write capabilities all over your drives, unlike a html file in a browser who can only do malignant stuff in your bookmarks, cookies, open / redirect to phishing URLs etc and cannot read arbitrary files.)

But like Thomas pointed out, the more common and dangerous stuff are contributions to popular open-source repositories that are then compiled in sites/software all over the place! :O 

@Brian

Examples are coming soon!! 

Félix


Félix

unread,
Sep 9, 2025, 2:05:00 AM (13 days ago) Sep 9
to leo-editor
@brian (and others!) Here's something to wet your appetite:

For starters, here is the base minimal Leo script to make html that represents the outline. (easily customizable)

output = ''
indentation = '        '

def AllRootChildren():
    p = c.rootPosition()
    while p:
        yield p
        p.moveToNext()

# Recursive function to generate the HTML structure
def doChildren(children):
    global output
    for child in children:
        indent = indentation * child.level()
        output += f"\n{indent}    <li>"
        output += f"\n{indent}        <b>{child.h}</b>"
        output += f"\n{indent}        <pre>\n{child.b}\n{indent}        </pre>"
        output += f"\n{indent}        <ul>"
        doChildren(child.children())
        output += f"\n{indent}        </ul>"
        output += f"\n{indent}    </li>"

# Start
output += "<ul>"
doChildren(AllRootChildren())
output += "\n</ul>"
g.es(output)


This generates valid HTML in the Leo Log Pane . (paste it in a new file and save it as a .html file to open it in your browser, remove the line with 'child.b' if you only want the headlines)

I've also made a script that makes a real, complete HTML document with the same layout and functionality as you've provided (with bootstrap accordions and everything, etc..) See the "brian-html" @button node in the attached leo File 

To have a button (or @command available) that does not reside in your current outline (and pollute the HTML output), put it in the @buttons (plural) section of your myLeoSettings.leo like so, and do alt+x reload-settings (or restart leo): you should see those 'html' buttons above any outline you open to export them as valid html documents in the log pane.

myLeoSettings.png

Check out the attached leo file for those 3 html generating @buttons!

I'll make a repository with even much better examples (which do not repeat data for clones, a single body pane on the side, keyboard navigation, instantly responsive like a read-only Leo, etc...) in a day or so... 

In the meantime, please try out those examples and give me your thought! :)

Félix
sample-leo-to-html.leo

Edward K. Ream

unread,
Sep 9, 2025, 7:12:42 AM (13 days ago) Sep 9
to leo-e...@googlegroups.com
On Mon, Sep 8, 2025 at 10:51 PM Félix <felix...@gmail.com> wrote:
@Edward 

You're right - unknown html files, unlike safer PDF file, images, word documents, etc., are a security risk and people should not 'open/run' by double clicking on a html file willy-nilly.
... 
But I'm a web developper, so I could recognized the imports he made as standard bootstrap from known 'content-delivery-networks' or "CDN" which are harmless and expected.
To be clear, I wasn't worried that you would write malware :-)
 
  So yeah, people should not open those if they are not sure of having confidence in them like I did.

I'm happy to leave it at that. I'm not sure about Brian's management, but that's not my problem.

For the record, I think converting a .leo file to a .html file is an interesting project worth doing, regardless of the security considerations.

But like Thomas pointed out, the more common and dangerous stuff are contributions to popular open-source repositories that are then compiled in sites/software all over the place! :O 

Right.

@Brian

Examples are coming soon!! 

I too am looking forward to them.

Edward

Edward K. Ream

unread,
Sep 9, 2025, 7:19:42 AM (13 days ago) Sep 9
to leo-e...@googlegroups.com
Thanks for this, Thomas. I agree that compromising repos is a bigger problem.

But I want to safeguard Leo's reputation above all else.

It's imperative that Leonistas don't open .leo files (or .html files representing Leo outlines) unless they trust the sender completely.

Edward

Robert-Felix

unread,
Sep 9, 2025, 10:03:20 AM (13 days ago) Sep 9
to leo-e...@googlegroups.com
@Edward Thanks for merging that 'all_root_children' into the commander's generators. As you can see from my preliminary examples two messages above, It's the only 'custom' function I needed outside the recursive one. (That will make it that much cleaner!)

Stay tuned for more elaborate examples later this week! :) (Thanks to @Brian for the inspiration!) 

A point I wanted to make is that it should be relatively easys to output outline documents without rst, shpinx, markdown, docusaurus, etc, etc... Those scripts are an attempt at that! :)

Félix

--
You received this message because you are subscribed to the Google Groups "leo-editor" group.
To unsubscribe from this group and stop receiving emails from it, send an email to leo-editor+...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/leo-editor/CAMF8tS2od1pz8Ome2WCtRgn9JxdekQT827-3cVtrApLob3U9wA%40mail.gmail.com.

Thomas Passin

unread,
Sep 9, 2025, 10:28:13 AM (13 days ago) Sep 9
to leo-editor
On Tuesday, September 9, 2025 at 10:03:20 AM UTC-4 Félix wrote:
A point I wanted to make is that it should be relatively easys to output outline documents without rst, shpinx, markdown, docusaurus, etc, etc... Those scripts are an attempt at that! :)

I totally agree.  I also want to point out that some of the current menu items in File/Export have slightly confusing names. That's because the word "outline" could refer to the entire Leo outline, or just the outline pane. The menu commands seem to use it to mean the outline pane only, but someone who wants to export the entire Leo outline will be looking for something like "export entire outline" and be disappointed to try one and only get the headlines.

brian

unread,
Sep 9, 2025, 12:37:44 PM (13 days ago) Sep 9
to leo-editor
@Félix

I cannot see the suggestions by Edward about merging that 'all_root_children' into the commander's generators.  Can you share?  

Based on your example code, it seems if I move the options like @tool-tip into the leo node body, then it would be easy to create the pydantic model from leo.  For page title and other meta data, I could put it into the node body in a node (probably first node).  I'd need to walk the pydantic tree once to set the ID in the html elements so I could parse the node body to look for options.  This approach would be slower and use more memory than your approach but would be easier to customize the html.   Another disadvantage of this approach is mapping an error in the pydantic models to the spot in leo that caused the problem.  I may need to add the leo model node id to the pydantic model.    

The html I posted automatically handles the indenting displayed in a brower.  When I generate the html code, I ignore the indent in the html code.  My thoughts are that in production, I'd want to minify the html and in development I could run through a prettifier to make the html nicely formatted.  

Here is html template for generating the html from a pydantic model:
-------------- 
{# this is a version of a single node that has production formating  #}

{% if nodeInst%}

    <div class="accordion-item"> <!-- {{ nodeInst.headline }} -->
        <button class="btn btn-accordion bg-light text-dark"
            data-bs-toggle="collapse"
            data-bs-target="#id{{nodeInst.htmlId}}"
            aria-expanded="false"
            aria-controls="id{{nodeInst.htmlId}}"
            aria-describedby="idTooltip{{nodeInst.htmlId}}">
            <span class="heading-text">{{ nodeInst.headline }}</span>
            <span class="toggle-arrow">&#9660;</span>

            {#if have tool tip, add it  #}
            {% if nodeInst.tooltip %}
                <span class="tooltip-html" id="idTooltip{{nodeInst.htmlId}}" role="tooltip">{{ nodeInst.tooltip }}</span>
            {% endif %}
        </button>
        <div id="id{{nodeInst.htmlId}}" class="collapse">
            <div class="collapse-content">
                <p>{{ nodeInst.body }}</p>

                {# loop child nodes if have #}
                {% if nodeInst.children %}
                    {% for childInst in nodeInst.children %}
                        {% include "site/node.html" with nodeInst=childInst %}

                    {% endfor %}

                {% endif %}
            </div>
        </div>
    </div> <!-- /{{ nodeInst.headline }} -->

{% else %}
    <h1 class="text-danger">Error: nodeInst not set in node.html</h1>
{% endif %}
-------------   

I handle recursion and rest of the web page in other templates.  Also, I have test templates like a node version that just prints out the variables in the node.  

  



On Tuesday, September 9, 2025 at 10:03:20 AM UTC-4 Félix wrote:

Edward K. Ream

unread,
Sep 9, 2025, 1:29:48 PM (13 days ago) Sep 9
to leo-e...@googlegroups.com
On Tue, Sep 9, 2025 at 11:37 AM brian <yakka...@gmail.com> wrote:
@Félix

I cannot see the suggestions by Edward about merging that 'all_root_children' into the commander's generators. 

The devel branch now contains the new code. I merged it a few hours ago.

Edward

Félix

unread,
Sep 10, 2025, 11:00:39 PM (11 days ago) Sep 10
to leo-editor
@Edward @Thomas @jkn

Ah! I'm so silly!  Here's a much better (and smaller) minimal example who's output can be saved in a file and dragged onto your browser,  using vnodes instead of positions. (uncomment that line for bodies too): 


output = ''
indentation = '        '
level = -1

def doChildren(children, level=0):
    global output
    for child in children:
        indent = indentation * level
        output += f"\n{indent}    <li>"
        output += f"\n{indent}        <b>{child.headString()}</b>"
        # output += f"\n{indent}        <pre>\n{child.bodyString()}\n{indent}        </pre>"
        output += f"\n{indent}        <ul>"
        doChildren(child.children, level + 1)
        output += f"\n{indent}        </ul>"
        output += f"\n{indent}    </li>"

output += "<ul>"
doChildren(c.hiddenRootNode.children)
output += "\n</ul>"
g.es(output)


@brian I havent had the chance to look at your source leo file... (I didnt notice it, and had only looked at your 'desired output file' oops !!)

I now understand your  @tool-tip  nodes and what you were going for. 

I'll have some more time in the weekend to make a script that really goes from your leo file example to your 'desired' output HTML file.

Again - thanks for your interest in Leo - and sorry for that delay! 

Félix

brian

unread,
Sep 11, 2025, 12:35:34 AM (11 days ago) Sep 11
to leo-editor
@Félix

I updated the leo sample.  I created a @metadata node that contains the @title and @sub-title nodes.  And I moved the @tool-tip into the body.  

Attached is the updated leo file.   

I've go the @metadata children parsing down.  Now I'm working on parsing the node body.
sample_input3.leo

jkn

unread,
Sep 11, 2025, 7:23:06 AM (11 days ago) Sep 11
to leo-editor
FWIW I might have a use for this as a cheap way of printing out 'scratch' nodes/subnodes, with indentation. I make things like shopping lists this way. Having a default scratch HTML file might be a nicer way to do this, for me at least.

Thomas Passin

unread,
Sep 11, 2025, 9:26:46 AM (11 days ago) Sep 11
to leo-editor
On Thursday, September 11, 2025 at 7:23:06 AM UTC-4 jkn wrote:
FWIW I might have a use for this as a cheap way of printing out 'scratch' nodes/subnodes, with indentation. I make things like shopping lists this way. Having a default scratch HTML file might be a nicer way to do this, for me at least.

Here's a quick-and-dirty script to display a subtree in the browser as an indented list. It leaves an .html file in the ~/.leo directory. It's not fancy but it does the job. 

@language python
"""Display current subtree in web browser.

   Writes a temporary .html file in ~/.leo.
"""
 
import os.path
import webbrowser
from tempfile import NamedTemporaryFile

TEMPDIR = os.path.expanduser(r'~/.leo')
ENCODING = 'utf-8'

def subtree_to_indented_list(event = None):
    """Output to browser an indented list for a subtree."""
    tree = c.p.self_and_subtree()

    indented = ''
    for x in tree:
        indent = '   ' * (x.level() - 1)
        body_lines = x.b.split('\n')
        body_lines_indented = [indent + l for l in body_lines]
        body = '\n'.join(body_lines_indented)
        indented += indent + x.h + '\n' + body + '\n'
    return indented

indented = subtree_to_indented_list()

if indented:
    html = f'<pre>{indented}</pre>'
    with NamedTemporaryFile(suffix = '.html',
            dir = TEMPDIR, delete = False) as f:
        f.write(html.encode(ENCODING))
    webbrowser.open(f.name)
else:
    g.es('No results')


I also have a version that will open a print dialog and print on a printer, if you would like that.

jkn

unread,
Sep 11, 2025, 1:08:06 PM (11 days ago) Sep 11
to leo-editor
Thanks Thomas. This does not give me quite what I was thinking of but I can certainly experiment with it.

I was not aware of, or had forgotten, the 'webbrowser' module, so thanks for that also;-)

    J^n

Thomas Passin

unread,
Sep 11, 2025, 1:47:26 PM (11 days ago) Sep 11
to leo-editor
What more are you thinking about? The script I posted was an enhancement of an wokrbook one I used to make sure I knew how to do a basic walk down the tree, so it's very bare-bones.

jkn

unread,
Sep 11, 2025, 2:31:54 PM (11 days ago) Sep 11
to leo-editor
just some layout and style changes ... the sort of thing that one can have fun playing with...

Thomas Passin

unread,
Sep 11, 2025, 2:48:54 PM (11 days ago) Sep 11
to leo-editor
On Thursday, September 11, 2025 at 2:31:54 PM UTC-4 jkn wrote:
just some layout and style changes ... the sort of thing that one can have fun playing with...


On Thursday, September 11, 2025 at 6:47:26 PM UTC+1 tbp1...@gmail.com wrote:
What more are you thinking about? The script I posted was an enhancement of an wokrbook one I used to make sure I knew how to do a basic walk down the tree, so it's very bare-bones.

Yes, my script is awfully basic with no styling, that's a fact. 

jkn

unread,
Sep 14, 2025, 7:40:19 AM (8 days ago) Sep 14
to leo-editor
Out of interest ... I haven't seen the use of child.headstring() and child.bodystring() before. Are these basically equivalent to p.h and p.b? Is one form to be preferred?

    Thanks, J^n

Félix

unread,
Sep 14, 2025, 1:22:09 PM (8 days ago) Sep 14
to leo-editor
Ah! jkn, Very good question!!

That is because I'm not using positions and going from node to node sequentially (and having to keep track of level, and keeping track of level going back lower to close tags when finishing doing children) 

I'm using the underlying vnodes, and recursion, thus simplifying everything as I know exactly the levels going up/down as its tied directly to entering/exiting the doChildren function. (as opposed to using 'c.all_nodes' for all vnodes in outline order, or 'c.all_positions' for the same but with positions) 

If you dont use recursion, again, you have then to keep track of the current level you are outputting in order to know when to 'close' opened tags. 

To illustrate this precise point, note that this canonical example about generators at https://leo-editor.github.io/leo-editor/tutorial-scripting.html#generators does NOT care about closing any tags, thus is totally ok with "c.all_positions"


for p in c.all_positions():
    print(' '*p.level()+p.h)


Please take a few minutes to study this construction and its output - compared to using 'Positions' (which do have their uses in other scenarios).

def doChildren(children, level=0):
    global output
    for child in children:
        indent = indentation * level
        output += f"\n{indent}    <li>"
        output += f"\n{indent}        <b>{child.headString()}</b>"
        # output += f"\n{indent}        <pre>\n{child.bodyString()}\n{indent}        </pre>"
        output += f"\n{indent}        <ul>"
        doChildren(child.children, level + 1)
        output += f"\n{indent}        </ul>"
        output += f"\n{indent}    </li>"

output += "<ul>"
doChildren(c.hiddenRootNode.children)
output += "\n</ul>"
g.es(output)

Félix

Thomas Passin

unread,
Sep 14, 2025, 3:40:21 PM (8 days ago) Sep 14
to leo-editor
That's a nice simple example of using recursion.  A point, not about the recursion but about the HTML - I'd like to point out that the rendered HTML won't show the indentation properly because all spaces will be collapsed into a single space. So 

f"\n{indent}        <pre>

won't show as intended.  One way I've handled this is to use CSS to create the indents. Each <ul> or <li> element, for example, could use relative positioning with left padding.  You can also produce a left margin line by specifying a left border for the elements. For example, in one project, I used a CSS class "term" for my indented items, and the CSS to produce the indent with margin line was

.terms {border-left:1px lightgrey solid;}
.terms {margin-left:0em; padding-left: 1.2em}

brian

unread,
Sep 14, 2025, 4:00:18 PM (8 days ago) Sep 14
to leo-editor
@Félix

Attached is the first version of leo to html plugin I wrote and a sample leo file I ran with.  

Overview of code:
  - plugin called “s_leo_to_html”.  I’m not sure best naming convention within leo plugin.  
  - the class “HTMLDataWrapper” reads the leo outline and creates a DataWrapper Pydantic object. DataWrapper includes options and pydantic nodes.  This is first time trying to write a leo plugin so I expect this class to be hacky.  Let me know if you have improvements.
  -  the class “GenerateHTMLFromNodesFactory” takes the  DataWrapper Pydantic object and uses Django to create the html.  I wrote a normal Django app to develop the templates and Pydantic models and then I pasted the templates and Pydantic models into this leo plugin.  The html can be changed by editing the template.  The node body is rendered with a markdown render.  I’m using Django 4.2.  I haven't tested this with errors in the html templates.  I believe this code is solid.  
  - I have 3 loggers setup – python standard out, leo, and file.  Search for the line “logLevel =” to set the debug level.  I currently have at DEBUG level.  The INFO level will produce less output.  I’m not sure how leo handles logging so it may not fit into the leo framework.  You can comment out all loggers or just handlers don’t want.  Now that I think about it, it seems the plugin method should use the leo method to write to log console.  Let me know if you suggests to better fit into the leo framework.    
  - The class “sTiming” has a timer to track how long plugin took and creates in a human readable format. 

I chose LEO ->Pydantic models -> html to help separate the processes.  I’m not sure if Django can be used dynamically like you are doing with generating raw html.  Also, with the Pydantic models approach, I could write different output formats.   I put all my html specific settings in the HTMLDataWrapper Pydantic model so I could swap in other output formats later.  .

In the html, I wanted cloned nodes reproduced.  I'm thinking of ways I can add 'go to clone' like feature in html.

Brian 

s_leo_to_html.py
sample_input4.leo

Thomas Passin

unread,
Sep 14, 2025, 5:53:43 PM (7 days ago) Sep 14
to leo-editor
Could you post a sample HTML output, please?

Félix

unread,
Sep 14, 2025, 6:17:42 PM (7 days ago) Sep 14
to leo-editor
@Thomas

That indentation is not meant to be rendered, it was just to indent the html code to be more human readable. 
(you are right that spaces inside tags as text content are all collapsed)

Félix

unread,
Sep 14, 2025, 6:19:25 PM (7 days ago) Sep 14
to leo-editor
@thomas forgot to mention, there is still indentation happening: because of the interleaving of the ul and il tags themselves. which are meant exactly for that use. 

brian

unread,
Sep 14, 2025, 7:37:43 PM (7 days ago) Sep 14
to leo-editor
@tbp1

Attached is html generated from the sample_input4.leo.  I don't believe I changed the html from the earlier post.  My main work was converting flat html to Django template.  

Brian

leo_export.html

Thomas Passin

unread,
Sep 14, 2025, 11:46:48 PM (7 days ago) Sep 14
to leo-editor
Thanks.  It seems to me that the HTML is much more complicated than it needs to be. For one thing, I would prefer that the page will work without an Internet connection.  There is nothing going on in the page that requires Internet calls. For another, the page can be much simpler, to the point that I don't see why any templating machinery is needed. I admit that if you insist on those timed transitions and some other visual features that the code would get more complicated. I personally would not bother - an easily readable, simple layout is what I would be going after. The tool tips also add a little complication, especially as I don't like them showing up whether or not I want them.  I think that could be handled fairly easily, again without needing a template of Django.

Félix

unread,
Sep 15, 2025, 1:55:16 PM (7 days ago) Sep 15
to leo-editor
@Thomas

About the HTML end result: His customer/ end users may actually want that type of front-end layout (big bootstrap accordions, tooltips, etc.) his product may be some documentation for non-technical users for whom those types of rich front end components are desired.

About using external libraries: In modern web development and front end production, those 'bootstrap',  'react', 'tailwind' are common usage.

Respectfully, I'd like to say: Let's try not to comment like on stackoverflow, where instead of answering what the original poster asked, (in its given context or constraints & requirements), they tell them his question is wrong and he should do his project completely differently.

Hoping I'm not coming across as inappropriate with that last remark...

In a spirit of friendship, :)
Félix

Thomas Passin

unread,
Sep 15, 2025, 5:22:04 PM (6 days ago) Sep 15
to leo-editor
On Monday, September 15, 2025 at 1:55:16 PM UTC-4 Félix wrote:

About using external libraries: In modern web development and front end production, those 'bootstrap',  'react', 'tailwind' are common usage.

Yes, I know. And they can be overkill, too.  Of course, it depends on what you want to do.
 
Hoping I'm not coming across as inappropriate with that last remark...

No, not at all. I probably shouldn't have written anything without a better idea of the usage scenario, anyway (and probably not with it either).

Mike Hodson

unread,
Sep 15, 2025, 5:33:31 PM (6 days ago) Sep 15
to leo-e...@googlegroups.com


On Mon, Sep 15, 2025, 15:22 Thomas Passin <tbp1...@gmail.com> wrote:

On Monday, September 15, 2025 at 1:55:16 PM UTC-4 Félix wrote:

About using external libraries: In modern web development and front end production, those 'bootstrap',  'react', 'tailwind' are common usage.

Yes, I know. And they can be overkill, too.  Of course, it depends on what you want to do.

My two cents: 

Inline whatever CSS and JavaScript you might need as opposed to calling third-party resources.  Compile tailwind locally and simply have it as a part of the header of the page. Once it's compiled you probably never have to compile it again and can simply distribute the CSS as compiled. Similarly with bootstrap, it should be minified and inlined if you are going to simply distribute an HTML file. 

React, now that is a bit of a large framework... If at all possible I would avoid React. 

But then again I grew up making websites with PHP on the server side and very little client side CSS except to decorate a few tags, and only enough JavaScript to support simple dynamic elements in the page.

Mike

jkn

unread,
Sep 16, 2025, 3:01:56 AM (6 days ago) Sep 16
to leo-editor
My two cents: I would tend to agree with Mike/Thomas, to aim towards a more 'standalone' HTML file. But I am not necessarily the target audience.

   J^n

Félix

unread,
Sep 20, 2025, 1:42:47 PM (2 days ago) Sep 20
to leo-editor
Although I wholeheartedly agree with Mike, Thomas and Jkn, I wanted to distinguish between that clean and self-contained approach, and a job-related/commercial requirement that might be requiring to stick with the standards in place for that particular case... (their in-house styling with such and such external library, their in-house usage of react or other big framework for integration purposes into their existing web-portal infrastructure) the corporate and business world is full of such idiosyncrasies and red-tape to be respected. (the ugly side of web-development) :)

Note: Using either a clean approach, or a bulky 'external frameworks and libraries' approach, a bottleneck that is not to be overlooked is that for a large outline, outputting each and every node to the browser's DOM will give a sluggish and problematic performance!

The trick is to use 'tree-node-virtualisation' where only the visible nodes are to be built in the DOM. (Not many frameworks offer this kind of components out-of-the-box)


That being said, I was inspired by Brian's original inquiry about how to "export an outline in an html format where the format of the html is similar to the desktop version of Leo with the expands and collapses.

So I cooked up a script, with virtualisation, that does just that: A clean, self-contained with inline css and script, without any external frameworks or libraries, version of an working 'Leo Outline' in read-only, interactive form. (meaning an interactive tree browsing experience like the real Leo)

Also, thanks to Thomas's example above on how to use 'webbrowser.open', I've also made the script output the resulting HTML file in the user's home/.leo folder, and open it in the browser automatically.

I've even tested it with LeoPyRef itself! No problem at all with big outlines! - And unlike LeoJS or LeoInteg, this offers a snappy and quick real-time interactive response, similar to the original Leo.

Again, to try it out, copy the @button node into your 'myLeoSettings' under the @settings/@buttons node like so (see attached demo-export-html.leo Leo file for the @button node itself)

This screenshot shows where to paste it:
myLeoSettings.png

Please give it a try (use the 'gear' button to adjust visible icons and settings) and share your feedback!

Félix
demo-export-html.leo

Thomas Passin

unread,
Sep 20, 2025, 4:20:06 PM (2 days ago) Sep 20
to leo-editor
Felix, that is superb! It's just the sort of thing I had pictured to myself, only more refined (e.g., the smooth transition between light and dark themes). And you added that nice search capability. It all feels very elegant.

On my system there is one minor buglet.  The tabs for scrolling the tree view don't show up and it can be hard to scroll below the visible position.  This must involve some tweak to the CSS. My browser (this is Windows) is Zen, a Firefox-based browser.

jkn

unread,
Sep 20, 2025, 5:10:36 PM (2 days ago) Sep 20
to leo-editor
Wow. That is much more than the slight 'itch' I was mentioning ... really impressive. I will study more. Great work!

    Regards
    J^n

jkn

unread,
Sep 21, 2025, 6:17:19 AM (23 hours ago) Sep 21
to leo-editor
An unrelated point which I think came up in a different thread when I was discussing various commands in myLeoSettings.leo etc...

IIUC there is no need to have extra @buttons and @commands nodes under @settings: you can just have

    @settings
        @command mycommand...
        ...
        @button mybutton ...


You might well of course choose to do this for clarity purposes, but there is (again IIUC) no need for the @...

    @settings
        commands
            @command mycommand...
            ...
        buttons
            @button mybutton ...
            ...

Again, just mentioned for (I hope) clarity.

Regards, J^n




Félix

unread,
12:36 AM (4 hours ago) 12:36 AM
to leo-editor
Thanks to all who tried it  and commented !! :)

I've corrected the scrollbar issue for firefox and also corrected two small bugs (collapse all button position and setting reasonable defaults on first use)

I've turned it into a Leo Plugin for regular use with the minibuffer and the 'Export Files' menu. I've made a new branch and pull request for this! 

https://github.com/leo-editor/leo-editor/pull/4456

For those curious to see the development (and a cleaned-up and leonized version which I ended up doing finally today) of this small self-contained HTML app, please see this repository (which contains Brians' demo, Thomas examples and a few experiments files for the curious!) at https://github.com/boltex/practice-outline

Lastly, if you have not tried it out yet, please try that latest version with the bug fixes: Just pull and switch to the felix-export-to-html-outline-viewer branch (and make sure to enable the plugin if you already have Leo installed and setup your plugins in your myLeoSettings.leo)

Or, if you're unfamiliar with git, or if you just want an @button version similar to what was posted above in the thread (with the bugs fixed) and/or see the cleaned up leonized version directly, download the attached leo-html-export.leojs Leo file. (it also contains some scripts posted in this thread for reference)

Cheers! :)

Félix
leo-html-export.leojs
Reply all
Reply to author
Forward
0 new messages