├── .gitignore
├── LICENSE
├── README.md
├── examples
└── FilePicker
│ ├── assets
│ ├── favicon.ico
│ ├── index.html
│ └── main.js
│ └── filepicker.nim
├── neel.nimble
└── src
├── chrome.nim
└── neel.nim
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | *.exe
3 | *.txt
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Leon Lysak
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Neel | HTML/JS GUI Library for Nim
2 |
3 | Neel is a Nim library for making lightweight Electron-like HTML/JS GUI apps, with full access to Nim capabilities and targets any of the C, C++, or Objective-C backends.
4 |
5 | > By default, Neel opens a new Chrome session in app mode and allows the Nim backend and HTML/JS frontend to communicate via JSON and websockets. Alternate mode available, simply opening a new tab in your system's default browser. Webview capabilities coming soon.
6 |
7 | Neel is designed to take all the hassle out of writing GUI applications. Current Features:
8 |
9 | * Eliminate 99% of boilerplate code
10 | * Automatic routes
11 | * Embeds frontend assets at compiletime (on `release` builds)
12 | * Automatic type conversions (from JSON to each procedure's parameter types)
13 | * Simple interface for backend/frontend communication
14 | * Cross-platform (tested on Mac, Windows, and Linux)
15 |
16 | Neel is inspired by [Eel](https://github.com/samuelhwilliams/Eel), its Python cousin.
17 |
18 | ----------------------
19 |
20 | ## Introduction
21 |
22 | Currently, Nim’s options for writing GUI applications are quite limited and if you wanted to use HTML/JS instead you can expect a lot of boilerplate code and headaches.
23 |
24 | Neel is still in its infancy, so as of right now I don’t think it’s suitable for making full-blown commercial applications like Slack or Twitch. It is, however, very suitable for making all kinds of other projects and tools.
25 |
26 | The best visualization libraries that exist are in Javascript and the most powerful capabilities of software can be harnessed with Nim. The goal of Neel is to combine the two languages and assist you in creating some killer applications.
27 |
28 | ## Installation
29 |
30 | Install from nimble:
31 | `nimble install neel`
32 |
33 | ## Usage
34 |
35 | ### Directory Structure
36 |
37 | Currently, Neel applications consist of various static web assets (HTML,CSS,JS, etc.) and Nim modules.
38 |
39 | All of the frontend files need to be placed within a single folder (they can be further divided into more folders within it if necessary). The starting URL must be named `index.html` and placed within the root of the web folder.
40 |
41 | ```
42 | main.nim <----\
43 | database.nim <-------- Nim files
44 | other.nim <----/
45 | /assets/ <------- Web folder containing frontend files (can be named whatever you want)
46 | index.html <-------- The starting URL for the application (**must** be named 'index.html' and located within the root of the web folder)
47 | /css/
48 | style.css
49 | /js/
50 | main.js
51 | ```
52 |
53 | ### Developing the Application
54 |
55 | #### Nim / Backend
56 |
57 | We begin with a very simple example, from there I'll explain the process and each part in detail.
58 |
59 | (main.nim)
60 | ```nim
61 | import neel #1
62 |
63 | exposeProcs: #2
64 | proc echoThis(jsMsg: string) =
65 | echo "got this from frontend: " & jsMsg
66 | callJs("logThis", "Hello from Nim!") #3
67 |
68 | startApp(webDirPath="path-to-web-assets-folder") #4
69 | ```
70 |
71 | ##### #1 import neel
72 |
73 | When you `import neel`, several modules are exported into the calling module. `exposedProcs` and `startApp` are macros that require these modules in order to work properly. The list below are all of the exported modules. It's not necessary to remember them, and even if you accidently imported the module twice Nim disregards it. This is just for your reference really.
74 | * `std/os`
75 | * `std/osproc`
76 | * `std/strutils`
77 | * `std/json`
78 | * `std/threadpool`
79 | * `std/browsers`
80 | * `std/jsonutils`
81 | * `pkg/mummy`
82 | * `pkg/routers`
83 |
84 | ##### #2 exposeProcs
85 |
86 | `exposeProcs` is a macro that *exposes* specific procedures for javascript to be able to call from the frontend. When the macro is expanded, it creates a procedure `callNim` which contains **all exposed procedures** and will call a specified procedure based on frontend data, passing in the appropriate parameters (should there be any).
87 |
88 | The data being received is initially **JSON** and needs to be converted into the appropriate types for each parameter in a procedure. This is also handled by the macro.
89 |
90 | As of Neel 1.1.0, you can use virtually any Nim type for parameters in *exposed procedures*. Neel uses `std/jsonutils` to programmatically handle the conversions. Some caveats:
91 | * Does not support default values for parameters.
92 | * Does not support generics for parameters.
93 |
94 | This above macro produces this result:
95 |
96 | ```nim
97 | proc callNim(procName: string; params: seq[JsonNode]) =
98 | proc echoThis(jsMsg: string) =
99 | echo "got this from frontend: " & jsMsg
100 | callJs("logThis", "Hello from Nim!")
101 | case procName
102 | of "echoThis": echoThis(params[0].getStr)
103 | ...
104 | ```
105 |
106 | NOTE: You *can* pass complex data in a single parameter now if you'd like to. Use Javascript objects or dictionaries and simply create a custom object type to accept it from the Nim side.
107 |
108 | I'm sure this is obvious, but it's much cleaner to have your exposed procedures call procedures from other modules.
109 |
110 | Example:
111 | ```nim
112 | # (main.nim)
113 | import neel, othermodule
114 | exposeProcs:
115 | proc proc1(param: seq[JsonNode]) =
116 | doStuff(param[0].getInt)
117 | ...
118 |
119 | # (othermodule.nim)
120 | from neel import callJs # you only need to import this macro from Neel :)
121 |
122 | proc doStuff*(param: int) =
123 | var dataForFrontEnd = param + 100
124 | callJs("myJavascriptFunc", dataForFrontEnd)
125 | ...
126 | ```
127 |
128 | ##### #3 callJs
129 |
130 | `callJs` is a macro that takes in at least one value, a `string`, and it's *the name of the javascript function you want to call*. Any other value will be passed into that javascript function call on the frontend. You may pass in any amount to satisfy your function parameters needs like so:
131 |
132 | ```nim
133 | callJs("myJavascriptFunc",1,3.14,["some stuff",1,9000])
134 | ```
135 |
136 | The above code gets converted into stringified JSON and sent to the frontend via websocket.
137 |
138 | ##### #4 startApp
139 |
140 | `startApp` is a macro that handles server logic, routing, and Chrome web browser. `startApp` currently takes 6 parameters.
141 | example:
142 |
143 | ```nim
144 | startApp(webDirPath= "path_to_web_assets_folder", portNo=5000,
145 | position= [500,150], size= [600,600], chromeFlags= @["--force-dark-mode"], appMode= true)
146 | # left, top # width, height
147 | ```
148 |
149 | * `webDirPath` : sets the path to the web directory containing all frontend assets **needs to be set**
150 | * `portNo` : specifies the port for serving your application (default is 5000)
151 | * `position` : positions the *top* and *left* side of your application window (default is 500 x 150)
152 | * `size` : sets the size of your application window by *width* and *height*(default is 600 x 600)
153 | * `chromeFlags` : passes any additional flags to chrome (default is none)
154 | * `appMode` : if "true" (default) Chrome will open a new session/window in App mode, if "false" a new tab will be opened in your *current default browser* - which can be very useful for debugging.
155 |
156 | #### Javascript / Frontend
157 |
158 | The Javascript aspect of a Neel app isn't nearly as complex. Let's build the frontend for the example above:
159 |
160 | (index.html)
161 | ```html
162 |
163 |
164 |