├── .github
└── FUNDING.yml
├── .gitignore
├── .startproject
├── LICENSE
├── README.md
├── app.go
├── build
├── README.md
├── appicon.png
├── darwin
│ ├── Info.dev.plist
│ └── Info.plist
└── windows
│ ├── icon.ico
│ ├── info.json
│ ├── installer
│ └── project.nsi
│ └── wails.exe.manifest
├── frontend
├── README.md
├── config.codekit3
├── dist
│ └── index.html
├── index.html
├── jsconfig.json
├── package-lock.json
├── package.json
├── package.json.md5
├── src
│ ├── Main.svelte
│ ├── components
│ │ ├── AddComponent.svelte
│ │ ├── BirthdayCounter.svelte
│ │ ├── BirthdayCounterConfig.svelte
│ │ ├── EditComponent.svelte
│ │ ├── EditSpanField.svelte
│ │ ├── FlowVariable.svelte
│ │ ├── FlowVariableConfig.svelte
│ │ ├── IPAddress.svelte
│ │ ├── IPAddressConfig.svelte
│ │ ├── Script.svelte
│ │ ├── ScriptBar.svelte
│ │ ├── ScriptConfig.svelte
│ │ ├── Separator.svelte
│ │ ├── SeparatorConfig.svelte
│ │ ├── ViewComponent.svelte
│ │ ├── WebLink.svelte
│ │ ├── WebLinkConfig.svelte
│ │ └── WebView.svelte
│ ├── main.js
│ ├── stores
│ │ ├── config.js
│ │ ├── headerPosition.js
│ │ ├── preferences.js
│ │ ├── resizeWindow.js
│ │ ├── styles.js
│ │ ├── timer.js
│ │ ├── variables.js
│ │ └── width.js
│ ├── style.css
│ └── vite-env.d.ts
├── vite.config.js
└── wailsjs
│ ├── go
│ └── main
│ │ ├── App.d.ts
│ │ └── App.js
│ └── runtime
│ ├── package.json
│ ├── runtime.d.ts
│ └── runtime.js
├── go.mod
├── go.sum
├── main.go
├── maskfile.md
├── server.go
└── wails.json
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [raguay]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Wails bin directory
2 | build/bin
3 | # Wails Windows NSIS support files
4 | build/windows/installer/wails_tools.nsh
5 | build/windows/installer/tmp/
6 | ExternalScriptTest
7 |
8 | frontend/dist
9 | # IDEs
10 | .idea
11 | .vscode
12 |
13 | # The black hole that is...
14 | node_modules
15 | package-lock.json
16 |
--------------------------------------------------------------------------------
/.startproject:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/raguay/ScriptBarApp/fb283cd80a97714f89e912f77b84bb603d201075/.startproject
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Richard Guay
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 | 
2 |
3 | [](https://github.com/anuraghazra/github-readme-stats)
4 |
5 | # Script Bar
6 |
7 | 
8 |
9 | An application to show results from scripts and Node-Red in the menubar. It is currently in the Alpha stage, but very usable. You can display results from the Node-Red server in [EmailIt Server](https://github.com/raguay/EmailItServer), command line scripts for either [TextBar](http://richsomerfield.com/apps/textbar/) (mostly working), [xBar](https://github.com/matryer/xbar) (not working - still in development), or some of the builtin components include web sites and IP addresses both local and external. You have to have the [EmailIt Server](https://github.com/raguay/EmailItServer) running to use this program. Currently, EmailItServer is now apart of [EmailIt](https://GitHub.com/raguay/EmailIt).
10 |
11 | The program is built with a [Svelte](https://svelte.dev/) JavaScript frontend and [Wails](https://wails.app/) backend and packager. The goal is to make this project usable on Windows, macOS, and Linux. I'm currently developing it on macOS and will be working of the other versions after the macOS is stable and Wails version 2 is ready for that platform.
12 |
13 | ## Note:
14 |
15 | This program isn't a replacement for xBar. xBar puts script outputs into individual menubar items. ScriptBar places all script output into a single interface for easy viewing when activated. I have a very cluttered menubar with many application that I use. So, I wanted some scripts to show in it's own menubar using xBar, and some grouped together in a single interface for convience. Pick the program that best suites your needs or use both like I do! This program also get output from a Node-Red server in the EmailIt Server program.
16 |
17 | ## Building
18 |
19 | To build the application, first go to the `frontend` directory and build it using:
20 |
21 | ```sh
22 | npm install
23 | npm run build
24 | ```
25 | The first line installs the libraries used to build the application. The second line compiles the Svelte front end. Next, you need to build the Wails app. First, install Wails by installing the prerequisites mentioned on their webiste and then run:
26 |
27 | ```sh
28 | go get -u github.com/wailsapp/wails/cmd/wails
29 | ```
30 |
31 | Then build the application or your platform with:
32 |
33 | ```sh
34 | wails build
35 | ```
36 |
37 | or, to build a macOS universal program, use this command line:
38 |
39 | ```sh
40 | wails build --platform "darwin/universal"
41 | ```
42 |
43 | To run the program, simply run the executable in the `build/bin` directory:
44 |
45 | ```sh
46 | open ./build/bin/ScriptBar.app
47 | ```
48 |
49 | You must have the [EmailIt Server](https://github.com/raguay/EmailItServer) running first. Currently, EmailItServer is embedded inside of [EmailIt](https://GitHub.com/raguay/EmailIt).
50 |
51 | ## Documentation
52 |
53 | The ScriptBar application is launched along with EmailIt. It relies upon the EmailIt Server for all of it's information. Just like EmailIt, it is a Wails application using Svelte for the frontend framework.
54 |
55 | 
56 |
57 | This shows my ScriptBar. The `+` in the upper left corner allows you to add new items to each tab. The tab with a `+` in it allows you to add a new tab. By double clicking the tab names, you can change text shown for each tab. You can have as many tabs as you want and as many items in each tab as you want. But, if you get too many, it will go past your screen edges! You can click and drag the top area to move the application around.
58 |
59 | 
60 |
61 | If you double click on the name of an entry, you can click `Up` to move it up the list or `Down` to move it down the list. By double clicking the entry name, you can edit it's parameters.
62 |
63 | There are seven types of entries that you can use. They are described below:
64 |
65 | #### Birthday Counter
66 |
67 | 
68 |
69 | The birthday counter takes the output of a birthday counter flow in Node-Red. It will show the time to the person's next birthday and their current age. The script for the birthday node in Node-Red is:
70 |
71 | ```javascript
72 | //
73 | // Get the current date and the count down
74 | // date.
75 | //
76 | var now = new Date();
77 |
78 |
79 | var dmon = msg.payload.month - 1;
80 | var dday = msg.payload.day;
81 | var dyear = msg.payload.year;
82 | var bd = new Date();
83 | bd.setFullYear(now.getFullYear());
84 | bd.setMonth(dmon);
85 | bd.setDate(dday);
86 |
87 | //
88 | // Calculate the number of milliseconds until
89 | // the date.
90 | //
91 | var diff = 0;
92 | if(now.getMonth() <= dmon) {
93 | diff = bd.getTime() - now.getTime();
94 | if((now.getMonth() === dmon)&&(now.getDate() > dday)) {
95 | diff = 0;
96 | }
97 | }
98 |
99 | if(diff === 0) {
100 | var yearEnd = new Date();
101 | yearEnd.setMonth(11);
102 | yearEnd.setDate(31);
103 | diff = yearEnd.getTime() - now.getTime();
104 | bd.setFullYear(now.getFullYear()+1);
105 | diff += bd.getTime() - yearEnd.getTime();
106 | }
107 |
108 | //
109 | // Convert the difference to months, weeks, days.
110 | //
111 | ddays = Math.floor(diff / (1000*60*60*24));
112 | dweeks = Math.floor(ddays / 7);
113 | ddays -= dweeks * 7;
114 |
115 | //
116 | // Create the answer and send it on.
117 | //
118 | var result = dweeks.toString() + ' weeks, ' + ddays.toString() + ' days';
119 | var ans = {
120 | payload: result,
121 | topic: 'days'
122 | }
123 | return ans;
124 | ```
125 |
126 | You put this code into a function node. Then create another function node with this code to calculate the current age:
127 |
128 | ```javascript
129 | //
130 | // Get the current date and the count down
131 | // date.
132 | //
133 | var now = new Date();
134 |
135 | var dmon = msg.payload.month - 1;
136 | var dday = msg.payload.day;
137 | var dyear = msg.payload.year;
138 |
139 | //
140 | // Create the answer and send it on.
141 | //
142 | var result = now.getFullYear() - dyear;
143 | var ans = {
144 | payload: result,
145 | topic: 'age'
146 | }
147 | return ans;
148 | ```
149 |
150 | You feed these two function nodes with an inject node with a payload like this:
151 |
152 | ```json
153 | {"year":1969,"month":8,"day":1}
154 | ```
155 |
156 | You need to change the `year`, `month`, and `day` fields to match the person's birthday. Then add a join node with these properties:
157 |
158 | 
159 |
160 | The last node is a `SPVariables` node set to the name of the Node-Red variable you want to use. The full flow looks like this:
161 |
162 | 
163 |
164 | #### Flow Variable
165 |
166 | 
167 |
168 | The flowvariable entry takes the text in a Node-Red flow variable and simply displays it.
169 |
170 | #### Internal IP Address
171 |
172 | 
173 |
174 | The Internal IP Address entry will display the internal IP address of your computer. That is the IP of your local network, not the IP used on the Internet. If you give a port number and check the link checkbox, you can click the IP address shown in ScriptBar and it will open a webpage to that address and port number. This entry type uses an API from the EmailItServer.
175 |
176 | #### External IP Address
177 |
178 | 
179 |
180 | The External IP Address is the same as the Internal IP address except that it takes a Node-Red flow variable name. You have to create a flow that fills in the external IP address of your system. There are several nodes that can supply that information, so I leave up to you. The one I use is an HTTP request node with the url set to `https://api.ipify.org?format=json`.
181 |
182 | #### Script
183 |
184 | 
185 |
186 | The Script entry allows you to call an External Script from EmailIt and display it's output. The output types can be: Generic, TextBar, BitBar (which is now xBar), and HTML. The Generic setting just displays the output as plain text. The TextBar setting processes the output as a TextBar script. The BitBar setting processes the output as a BitBar script (not currently working), and the HTML setting displays the output as HTML. The `What is the command line?` isn't currently used. I plan to have it just run the command line and display the results.
187 |
188 | 
189 |
190 | The picture above shows an TextBar script output called TaskPaperTodo.rb. This is a ruby script that displays the tasks I have in the TaskPaper program.
191 |
192 | #### Separator
193 |
194 | 
195 |
196 | This is a simple line separator to separate entry types.
197 |
198 | #### Web Link
199 |
200 | 
201 |
202 | The Web Link entry type allows you to give a website address. By clicking on the glob on the ScriptBar program, it will open that web link in the default browser. I use this type a whole lot to keep up with websites that I go to often.
203 |
204 |
--------------------------------------------------------------------------------
/app.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "bytes"
5 | "context"
6 | "errors"
7 | "fmt"
8 | "io"
9 | "io/ioutil"
10 | "net/http"
11 | "os"
12 | "os/exec"
13 | "path/filepath"
14 | goruntime "runtime"
15 | "strings"
16 | "time"
17 |
18 | clip "github.com/atotto/clipboard"
19 | cp "github.com/otiai10/copy"
20 | rt "github.com/wailsapp/wails/v2/pkg/runtime"
21 | )
22 |
23 | // App struct
24 | type App struct {
25 | ctx context.Context
26 | err string
27 | }
28 |
29 | // NewApp creates a new App application struct
30 | func NewApp() *App {
31 | return &App{}
32 | }
33 |
34 | // startup is called at application startup
35 | func (a *App) startup(ctx context.Context) {
36 | // Perform your setup here
37 | a.ctx = ctx
38 | }
39 |
40 | // domReady is called after front-end resources have been loaded
41 | func (a App) domReady(ctx context.Context) {
42 | //
43 | // Run the server for getting variable information.
44 | //
45 | go RunServer(&a, ctx)
46 | }
47 |
48 | // beforeClose is called when the application is about to quit,
49 | // either by clicking the window close button or calling runtime.Quit.
50 | // Returning true will cause the application to continue, false will continue shutdown as normal.
51 | func (a *App) beforeClose(ctx context.Context) (prevent bool) {
52 | return false
53 | }
54 |
55 | // shutdown is called at application termination
56 | func (a *App) shutdown(ctx context.Context) {
57 | // Perform your teardown here
58 | }
59 |
60 | func (a *App) Quit() {
61 | rt.Quit(a.ctx)
62 | }
63 |
64 | type FileParts struct {
65 | Dir string
66 | Name string
67 | Extension string
68 | }
69 |
70 | type FileInfo struct {
71 | Dir string
72 | Name string
73 | Extension string
74 | IsDir bool
75 | Size int64
76 | Modtime string
77 | }
78 |
79 | type Environment struct {
80 | Name string `json:"name" binding:"required"`
81 | EnvVar []string `json:"envVar" binding:"required"`
82 | }
83 |
84 | type ServerResponce struct {
85 | Error string `json:"error"`
86 | Result string `json:"result"`
87 | }
88 |
89 | func (a *App) SendHTTPQuery(method string, uri string, body string) string {
90 | var result string
91 | switch strings.Trim(method, " ") {
92 | case "GET":
93 | {
94 | resp, err := http.Get(uri)
95 | if err != nil {
96 | print(err)
97 | }
98 | defer resp.Body.Close()
99 | body, err := ioutil.ReadAll(resp.Body)
100 | if err != nil {
101 | print(err)
102 | }
103 | result = string(body)
104 | }
105 |
106 | case "POST":
107 | {
108 | resp, err := http.Post(uri, "application/json", bytes.NewBuffer([]byte(body+"\n")))
109 | if err != nil {
110 | print(err)
111 | }
112 | defer resp.Body.Close()
113 | repBody, errdec := ioutil.ReadAll(resp.Body)
114 | if errdec != nil {
115 | print(errdec)
116 | }
117 | result = string(repBody)
118 | }
119 | case "PUT":
120 | {
121 | client := http.Client{}
122 |
123 | // regardless of GET or POST, we can safely add the body
124 | req, err := http.NewRequest("PUT", uri, bytes.NewBuffer([]byte(body+"\n")))
125 | if err != nil {
126 | return err.Error()
127 | }
128 | headers := map[string]string{}
129 | headers["Method"] = "PUT"
130 | headers["Content-Type"] = "application/json"
131 |
132 | // for each header passed, add the header value to the request
133 | for k, v := range headers {
134 | req.Header.Set(k, v)
135 | }
136 |
137 | // finally, do the request
138 | res, err := client.Do(req)
139 | if err != nil {
140 | return err.Error()
141 | }
142 |
143 | if res == nil {
144 | return fmt.Sprint("error: calling %s returned empty response", uri)
145 | }
146 |
147 | responseData, err := io.ReadAll(res.Body)
148 | if err != nil {
149 | return err.Error()
150 | }
151 |
152 | defer res.Body.Close()
153 |
154 | if res.StatusCode != http.StatusOK {
155 | return fmt.Sprintf("error calling %s:\nstatus: %s\nresponseData: %s", uri, res.Status, responseData)
156 | }
157 |
158 | result = string(responseData)
159 | }
160 | }
161 | return result
162 | }
163 |
164 | func (a *App) SystemOpenFile(prog string) {
165 | if a.FileExists(prog) {
166 | var ArgsArray [2]string
167 | var sar []string
168 | ArgsArray[1] = prog
169 | a.RunCommandLine("/usr/bin/open", ArgsArray[:], sar, "")
170 | }
171 | }
172 |
173 | func (a *App) GetExecutable() string {
174 | ex, err := os.Executable()
175 | if err != nil {
176 | a.err = err.Error()
177 | }
178 | return ex
179 | }
180 |
181 | func (a *App) Getwd() string {
182 | wd, err := os.Getwd()
183 | if err != nil {
184 | a.err = err.Error()
185 | }
186 | return wd
187 | }
188 |
189 | func (a *App) ReadFile(path string) string {
190 | a.err = ""
191 | contents, err := os.ReadFile(path)
192 | if err != nil {
193 | a.err = err.Error()
194 | }
195 | return string(contents[:])
196 | }
197 |
198 | func (a *App) GetHomeDir() string {
199 | a.err = ""
200 | hdir, err := os.UserHomeDir()
201 | if err != nil {
202 | a.err = err.Error()
203 | }
204 | return hdir
205 | }
206 |
207 | func (a *App) WriteFile(path string, data string) {
208 | err := os.WriteFile(path, []byte(data), 0666)
209 | if err != nil {
210 | a.err = err.Error()
211 | }
212 | }
213 |
214 | func (a *App) FileExists(path string) bool {
215 | a.err = ""
216 | _, err := os.Stat(path)
217 | return !errors.Is(err, os.ErrNotExist)
218 | }
219 |
220 | func (a *App) DirExists(path string) bool {
221 | a.err = ""
222 | dstat, err := os.Stat(path)
223 | if err != nil {
224 | a.err = err.Error()
225 | return false
226 | }
227 | return dstat.IsDir()
228 | }
229 |
230 | func (a *App) SplitFile(path string) FileParts {
231 | a.err = ""
232 | var parts FileParts
233 | parts.Dir, parts.Name = filepath.Split(path)
234 | parts.Extension = filepath.Ext(path)
235 | return parts
236 | }
237 |
238 | func (a *App) ReadDir(path string) []FileInfo {
239 | a.err = ""
240 | var result []FileInfo
241 | result = make([]FileInfo, 0, 0)
242 | files, err := ioutil.ReadDir(path)
243 | if err != nil {
244 | a.err = err.Error()
245 | } else {
246 | for _, file := range files {
247 | var fileInfo FileInfo
248 | fileInfo.Name = file.Name()
249 | fileInfo.Size = file.Size()
250 | fileInfo.IsDir = file.IsDir()
251 | fileInfo.Modtime = file.ModTime().Format(time.ANSIC)
252 | fileInfo.Dir = path
253 | fileInfo.Extension = filepath.Ext(file.Name())
254 | result = append(result, fileInfo)
255 | }
256 | }
257 | return result
258 | }
259 |
260 | func (a *App) MakeDir(path string) {
261 | a.err = ""
262 | err := os.MkdirAll(path, 0755)
263 | if err != nil {
264 | a.err = err.Error()
265 | }
266 | }
267 |
268 | func (a *App) MakeFile(path string) {
269 | a.err = ""
270 | a.WriteFile(path, "")
271 | }
272 |
273 | func (a *App) MoveEntries(from string, to string) {
274 | a.err = ""
275 | err := os.Rename(from, to)
276 | if err != nil {
277 | a.err = err.Error()
278 | }
279 | }
280 |
281 | func (a *App) RenameEntry(from string, to string) {
282 | a.err = ""
283 | err := os.Rename(from, to)
284 | if err != nil {
285 | a.err = err.Error()
286 | }
287 | }
288 |
289 | func (a *App) GetError() string {
290 | return a.err
291 | }
292 |
293 | func (a *App) CopyEntries(from string, to string) {
294 | a.err = ""
295 | info, err := os.Stat(from)
296 | if os.IsNotExist(err) {
297 | a.err = err.Error()
298 | return
299 | }
300 | if info.IsDir() {
301 | //
302 | // It's a directory! Do a deap copy.
303 | //
304 | err := cp.Copy(from, to)
305 | if err != nil {
306 | a.err = err.Error()
307 | return
308 | }
309 | } else {
310 | //
311 | // It's a file. Just copy it.
312 | //
313 | source, err := os.Open(from)
314 | if err != nil {
315 | a.err = err.Error()
316 | return
317 | }
318 | defer source.Close()
319 |
320 | destination, err := os.Create(to)
321 | if err != nil {
322 | a.err = err.Error()
323 | return
324 | }
325 | defer destination.Close()
326 | _, err = io.Copy(destination, source)
327 |
328 | if err != nil {
329 | a.err = err.Error()
330 | }
331 | }
332 | }
333 |
334 | func (a *App) DeleteEntries(path string) {
335 | a.err = ""
336 | err := os.RemoveAll(path)
337 | if err != nil {
338 | a.err = err.Error()
339 | }
340 | }
341 |
342 | func (a *App) RunCommandLine(cmd string, args []string, env []string, dir string) string {
343 | a.err = ""
344 | cmdline := exec.Command(cmd)
345 | cmdline.Args = args
346 | cmdline.Env = env
347 | cmdline.Dir = dir
348 | result, err := cmdline.CombinedOutput()
349 | if err != nil {
350 | a.err = err.Error()
351 | }
352 |
353 | return string(result[:])
354 | }
355 |
356 | func (a *App) GetClip() string {
357 | result, err := clip.ReadAll()
358 | if err != nil {
359 | a.err = err.Error()
360 | }
361 | return result
362 | }
363 |
364 | func (a *App) SetClip(msg string) {
365 | err := clip.WriteAll(msg)
366 | if err != nil {
367 | a.err = err.Error()
368 | }
369 | }
370 |
371 | func (a *App) GetEnvironment() []string {
372 | return os.Environ()
373 | }
374 |
375 | func (a *App) GetEnv(name string) string {
376 | return os.Getenv(name)
377 | }
378 |
379 | func (a *App) AppendPath(dir string, name string) string {
380 | return filepath.Join(dir, name)
381 | }
382 |
383 | func (a *App) GetOSName() string {
384 | os := goruntime.GOOS
385 | result := ""
386 | switch os {
387 | case "windows":
388 | result = "windows"
389 | break
390 | case "darwin":
391 | result = "macos"
392 | case "linux":
393 | result = "linux"
394 | default:
395 | result = fmt.Sprintf("%s", os)
396 | }
397 | return result
398 | }
399 |
--------------------------------------------------------------------------------
/build/README.md:
--------------------------------------------------------------------------------
1 | # Build Directory
2 |
3 | The build directory is used to house all the build files and assets for your application.
4 |
5 | The structure is:
6 |
7 | * bin - Output directory
8 | * darwin - macOS specific files
9 | * windows - Windows specific files
10 |
11 | ## Mac
12 |
13 | The `darwin` directory holds files specific to Mac builds.
14 | These may be customised and used as part of the build. To return these files to the default state, simply delete them
15 | and
16 | build with `wails build`.
17 |
18 | The directory contains the following files:
19 |
20 | - `Info.plist` - the main plist file used for Mac builds. It is used when building using `wails build`.
21 | - `Info.dev.plist` - same as the main plist file but used when building using `wails dev`.
22 |
23 | ## Windows
24 |
25 | The `windows` directory contains the manifest and rc files used when building with `wails build`.
26 | These may be customised for your application. To return these files to the default state, simply delete them and
27 | build with `wails build`.
28 |
29 | - `icon.ico` - The icon used for the application. This is used when building using `wails build`. If you wish to
30 | use a different icon, simply replace this file with your own. If it is missing, a new `icon.ico` file
31 | will be created using the `appicon.png` file in the build directory.
32 | - `installer/*` - The files used to create the Windows installer. These are used when building using `wails build`.
33 | - `info.json` - Application details used for Windows builds. The data here will be used by the Windows installer,
34 | as well as the application itself (right click the exe -> properties -> details)
35 | - `wails.exe.manifest` - The main application manifest file.
--------------------------------------------------------------------------------
/build/appicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/raguay/ScriptBarApp/fb283cd80a97714f89e912f77b84bb603d201075/build/appicon.png
--------------------------------------------------------------------------------
/build/darwin/Info.dev.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | CFBundlePackageType
5 | APPL
6 | CFBundleName
7 | {{.Info.ProductName}}
8 | CFBundleExecutable
9 | {{.Name}}
10 | CFBundleIdentifier
11 | com.wails.{{.Name}}
12 | CFBundleVersion
13 | {{.Info.ProductVersion}}
14 | CFBundleGetInfoString
15 | {{.Info.Comments}}
16 | CFBundleShortVersionString
17 | {{.Info.ProductVersion}}
18 | CFBundleIconFile
19 | iconfile
20 | LSMinimumSystemVersion
21 | 10.13.0
22 | NSHighResolutionCapable
23 | true
24 | NSHumanReadableCopyright
25 | {{.Info.Copyright}}
26 | NSAppTransportSecurity
27 |
28 | NSAllowsLocalNetworking
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/build/darwin/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | CFBundlePackageType
5 | APPL
6 | CFBundleName
7 | {{.Info.ProductName}}
8 | CFBundleExecutable
9 | {{.Name}}
10 | CFBundleIdentifier
11 | com.wails.{{.Name}}
12 | CFBundleVersion
13 | {{.Info.ProductVersion}}
14 | CFBundleGetInfoString
15 | {{.Info.Comments}}
16 | CFBundleShortVersionString
17 | {{.Info.ProductVersion}}
18 | CFBundleIconFile
19 | iconfile
20 | LSMinimumSystemVersion
21 | 10.13.0
22 | NSHighResolutionCapable
23 | true
24 | NSHumanReadableCopyright
25 | {{.Info.Copyright}}
26 |
27 |
--------------------------------------------------------------------------------
/build/windows/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/raguay/ScriptBarApp/fb283cd80a97714f89e912f77b84bb603d201075/build/windows/icon.ico
--------------------------------------------------------------------------------
/build/windows/info.json:
--------------------------------------------------------------------------------
1 | {
2 | "fixed": {
3 | "file_version": "{{.Info.ProductVersion}}"
4 | },
5 | "info": {
6 | "0000": {
7 | "ProductVersion": "{{.Info.ProductVersion}}",
8 | "CompanyName": "{{.Info.CompanyName}}",
9 | "FileDescription": "{{.Info.ProductName}}",
10 | "LegalCopyright": "{{.Info.Copyright}}",
11 | "ProductName": "{{.Info.ProductName}}",
12 | "Comments": "{{.Info.Comments}}"
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/build/windows/installer/project.nsi:
--------------------------------------------------------------------------------
1 | Unicode true
2 |
3 | ####
4 | ## Please note: Template replacements don't work in this file. They are provided with default defines like
5 | ## mentioned underneath.
6 | ## If the keyword is not defined, "wails_tools.nsh" will populate them with the values from ProjectInfo.
7 | ## If they are defined here, "wails_tools.nsh" will not touch them. This allows to use this project.nsi manually
8 | ## from outside of Wails for debugging and development of the installer.
9 | ##
10 | ## For development first make a wails nsis build to populate the "wails_tools.nsh":
11 | ## > wails build --target windows/amd64 --nsis
12 | ## Then you can call makensis on this file with specifying the path to your binary:
13 | ## For a AMD64 only installer:
14 | ## > makensis -DARG_WAILS_AMD64_BINARY=..\..\bin\app.exe
15 | ## For a ARM64 only installer:
16 | ## > makensis -DARG_WAILS_ARM64_BINARY=..\..\bin\app.exe
17 | ## For a installer with both architectures:
18 | ## > makensis -DARG_WAILS_AMD64_BINARY=..\..\bin\app-amd64.exe -DARG_WAILS_ARM64_BINARY=..\..\bin\app-arm64.exe
19 | ####
20 | ## The following information is taken from the ProjectInfo file, but they can be overwritten here.
21 | ####
22 | ## !define INFO_PROJECTNAME "MyProject" # Default "{{.Name}}"
23 | ## !define INFO_COMPANYNAME "MyCompany" # Default "{{.Info.CompanyName}}"
24 | ## !define INFO_PRODUCTNAME "MyProduct" # Default "{{.Info.ProductName}}"
25 | ## !define INFO_PRODUCTVERSION "1.0.0" # Default "{{.Info.ProductVersion}}"
26 | ## !define INFO_COPYRIGHT "Copyright" # Default "{{.Info.Copyright}}"
27 | ###
28 | ## !define PRODUCT_EXECUTABLE "Application.exe" # Default "${INFO_PROJECTNAME}.exe"
29 | ## !define UNINST_KEY_NAME "UninstKeyInRegistry" # Default "${INFO_COMPANYNAME}${INFO_PRODUCTNAME}"
30 | ####
31 | ## !define REQUEST_EXECUTION_LEVEL "admin" # Default "admin" see also https://nsis.sourceforge.io/Docs/Chapter4.html
32 | ####
33 | ## Include the wails tools
34 | ####
35 | !include "wails_tools.nsh"
36 |
37 | # The version information for this two must consist of 4 parts
38 | VIProductVersion "${INFO_PRODUCTVERSION}.0"
39 | VIFileVersion "${INFO_PRODUCTVERSION}.0"
40 |
41 | VIAddVersionKey "CompanyName" "${INFO_COMPANYNAME}"
42 | VIAddVersionKey "FileDescription" "${INFO_PRODUCTNAME} Installer"
43 | VIAddVersionKey "ProductVersion" "${INFO_PRODUCTVERSION}"
44 | VIAddVersionKey "FileVersion" "${INFO_PRODUCTVERSION}"
45 | VIAddVersionKey "LegalCopyright" "${INFO_COPYRIGHT}"
46 | VIAddVersionKey "ProductName" "${INFO_PRODUCTNAME}"
47 |
48 | !include "MUI.nsh"
49 |
50 | !define MUI_ICON "..\icon.ico"
51 | !define MUI_UNICON "..\icon.ico"
52 | # !define MUI_WELCOMEFINISHPAGE_BITMAP "resources\leftimage.bmp" #Include this to add a bitmap on the left side of the Welcome Page. Must be a size of 164x314
53 | !define MUI_FINISHPAGE_NOAUTOCLOSE # Wait on the INSTFILES page so the user can take a look into the details of the installation steps
54 | !define MUI_ABORTWARNING # This will warn the user if they exit from the installer.
55 |
56 | !insertmacro MUI_PAGE_WELCOME # Welcome to the installer page.
57 | # !insertmacro MUI_PAGE_LICENSE "resources\eula.txt" # Adds a EULA page to the installer
58 | !insertmacro MUI_PAGE_DIRECTORY # In which folder install page.
59 | !insertmacro MUI_PAGE_INSTFILES # Installing page.
60 | !insertmacro MUI_PAGE_FINISH # Finished installation page.
61 |
62 | !insertmacro MUI_UNPAGE_INSTFILES # Uinstalling page
63 |
64 | !insertmacro MUI_LANGUAGE "English" # Set the Language of the installer
65 |
66 | ## The following two statements can be used to sign the installer and the uninstaller. The path to the binaries are provided in %1
67 | #!uninstfinalize 'signtool --file "%1"'
68 | #!finalize 'signtool --file "%1"'
69 |
70 | Name "${INFO_PRODUCTNAME}"
71 | OutFile "..\..\bin\${INFO_PROJECTNAME}-${ARCH}-installer.exe" # Name of the installer's file.
72 | InstallDir "$PROGRAMFILES64\${INFO_COMPANYNAME}\${INFO_PRODUCTNAME}" # Default installing folder ($PROGRAMFILES is Program Files folder).
73 | ShowInstDetails show # This will always show the installation details.
74 |
75 | Function .onInit
76 | !insertmacro wails.checkArchitecture
77 | FunctionEnd
78 |
79 | Section
80 | !insertmacro wails.webview2runtime
81 |
82 | SetOutPath $INSTDIR
83 |
84 | !insertmacro wails.files
85 |
86 | CreateShortcut "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}"
87 | CreateShortCut "$DESKTOP\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}"
88 |
89 | !insertmacro wails.writeUninstaller
90 | SectionEnd
91 |
92 | Section "uninstall"
93 | RMDir /r "$AppData\${PRODUCT_EXECUTABLE}" # Remove the WebView2 DataPath
94 |
95 | RMDir /r $INSTDIR
96 |
97 | Delete "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk"
98 | Delete "$DESKTOP\${INFO_PRODUCTNAME}.lnk"
99 |
100 | !insertmacro wails.deleteUninstaller
101 | SectionEnd
102 |
--------------------------------------------------------------------------------
/build/windows/wails.exe.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | true/pm
12 | permonitorv2,permonitor
13 |
14 |
15 |
--------------------------------------------------------------------------------
/frontend/README.md:
--------------------------------------------------------------------------------
1 | # Svelte + Vite
2 |
3 | This template should help get you started developing with Svelte in Vite.
4 |
5 | ## Recommended IDE Setup
6 |
7 | [VS Code](https://code.visualstudio.com/)
8 |
9 | + [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode).
10 |
11 | ## Need an official Svelte framework?
12 |
13 | Check out [SvelteKit](https://github.com/sveltejs/kit#readme), which is also powered by Vite. Deploy anywhere with its
14 | serverless-first approach and adapt to various platforms, with out of the box support for TypeScript, SCSS, and Less,
15 | and easily-added support for mdsvex, GraphQL, PostCSS, Tailwind CSS, and more.
16 |
17 | ## Technical considerations
18 |
19 | **Why use this over SvelteKit?**
20 |
21 | - It brings its own routing solution which might not be preferable for some users.
22 | - It is first and foremost a framework that just happens to use Vite under the hood, not a Vite app.
23 | `vite dev` and `vite build` wouldn't work in a SvelteKit environment, for example.
24 |
25 | This template contains as little as possible to get started with Vite + Svelte, while taking into account the developer
26 | experience with regards to HMR and intellisense. It demonstrates capabilities on par with the other `create-vite`
27 | templates and is a good starting point for beginners dipping their toes into a Vite + Svelte project.
28 |
29 | Should you later need the extended capabilities and extensibility provided by SvelteKit, the template has been
30 | structured similarly to SvelteKit so that it is easy to migrate.
31 |
32 | **Why `global.d.ts` instead of `compilerOptions.types` inside `jsconfig.json` or `tsconfig.json`?**
33 |
34 | Setting `compilerOptions.types` shuts out all other types not explicitly listed in the configuration. Using triple-slash
35 | references keeps the default TypeScript setting of accepting type information from the entire workspace, while also
36 | adding `svelte` and `vite/client` type information.
37 |
38 | **Why include `.vscode/extensions.json`?**
39 |
40 | Other templates indirectly recommend extensions via the README, but this file allows VS Code to prompt the user to
41 | install the recommended extension upon opening the project.
42 |
43 | **Why enable `checkJs` in the JS template?**
44 |
45 | It is likely that most cases of changing variable types in runtime are likely to be accidental, rather than deliberate.
46 | This provides advanced typechecking out of the box. Should you like to take advantage of the dynamically-typed nature of
47 | JavaScript, it is trivial to change the configuration.
48 |
49 | **Why is HMR not preserving my local component state?**
50 |
51 | HMR state preservation comes with a number of gotchas! It has been disabled by default in both `svelte-hmr`
52 | and `@sveltejs/vite-plugin-svelte` due to its often surprising behavior. You can read the
53 | details [here](https://github.com/rixo/svelte-hmr#svelte-hmr).
54 |
55 | If you have state that's important to retain within a component, consider creating an external store which would not be
56 | replaced by HMR.
57 |
58 | ```js
59 | // store.js
60 | // An extremely simple external store
61 | import { writable } from 'svelte/store'
62 | export default writable(0)
63 | ```
64 |
--------------------------------------------------------------------------------
/frontend/dist/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |