6 Commits
v1.0.0 ... main

Author SHA1 Message Date
relikd
8242a64a5d feat: changelog 2026-01-28 12:58:59 +01:00
relikd
355cf0ded1 feat: svg status icon 2026-01-28 12:48:07 +01:00
relikd
fa5551f272 fix: svg transparent fill color 2026-01-28 12:45:33 +01:00
relikd
b6eaa8d3c4 ref: move files to dedicated res folder 2026-01-28 12:44:43 +01:00
relikd
1af81e5b4a fix: file path on macOS 10.13 2026-01-28 12:43:09 +01:00
relikd
05714ef69e fix: remove unused SwiftUI import 2026-01-27 23:53:34 +01:00
22 changed files with 55 additions and 23 deletions

19
CHANGELOG.md Normal file
View File

@@ -0,0 +1,19 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project does adhere to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.0.1] 2026-01-28
Fixed:
- Crash on macOS 10.13 if path contains space character
- Larger status icon glyph
## [1.0.0] 2026-01-27
Initial release
[1.0.1]: https://github.com/relikd/Menuscript/compare/v1.0.0...v1.0.1
[1.0.0]: https://github.com/relikd/Menuscript/compare/1eca425c5f453bc0ed47f780d491656549d3ab53...v1.0.0

View File

@@ -11,7 +11,7 @@ HAS_SIGN_IDENTITY=$(shell security find-identity -v -p codesigning | grep -q "Ap
Menuscript.app: SDK_PATH=$(shell xcrun --show-sdk-path --sdk macosx)
Menuscript.app: src/* examples/*
Menuscript.app: src/* res/**
@mkdir -p Menuscript.app/Contents/MacOS/
swiftc ${CFLAGS} src/main.swift -target x86_64-apple-macos10.13 \
-emit-executable -sdk ${SDK_PATH} -o bin_x64
@@ -20,11 +20,10 @@ Menuscript.app: src/* examples/*
lipo -create bin_x64 bin_arm64 -o Menuscript.app/Contents/MacOS/Menuscript
@rm bin_x64 bin_arm64
@echo 'APPL????' > Menuscript.app/Contents/PkgInfo
@mkdir -p Menuscript.app/Contents/Resources/
@cp src/AppIcon.icns Menuscript.app/Contents/Resources/AppIcon.icns
@rm -rf Menuscript.app/Contents/Resources/examples/
@cp -R examples/ Menuscript.app/Contents/Resources/examples/
@cp src/Info.plist Menuscript.app/Contents/Info.plist
@find res -name .DS_Store -delete
@rm -rf Menuscript.app/Contents/Resources/
@cp -R res/ Menuscript.app/Contents/Resources/
@touch Menuscript.app
@echo
ifeq ($(HAS_SIGN_IDENTITY),1)

View File

@@ -12,7 +12,7 @@ A menu bar script executor.
Menuscript adds a status bar menu to call custom (user defined) scripts.
The app reads the content of a directory and adds all executable files to the status menu.
The screenshot above represents the content of the [examples](examples/) directory.
The screenshot above represents the content of the [res/examples](res/examples/) directory.
## Usage

View File

@@ -21,7 +21,7 @@
<rect id="blue" x="500" width="600" height="470" fill="url(#lg2)"/>
<rect id="blue_line" x="500" y="470" width="600" height="30" fill="#2847C5"/>
<g transform="translate(562.5,62)scale(0.35)">
<path id="_x2318_" d="M335,335m-145,0a145,145,0,1,1,145,-145v620a145,145,0,1,1,-145,-145h620a145,145,0,1,1,-145,145v-620a145,145,0,1,1,145,145Z" stroke="#fff" stroke-width="90" fill="transparent"/>
<path id="_x2318_" d="M335,335m-145,0a145,145,0,1,1,145,-145v620a145,145,0,1,1,-145,-145h620a145,145,0,1,1,-145,145v-620a145,145,0,1,1,145,145Z" stroke="#fff" stroke-width="90" fill="none"/>
</g>
<text x="75" y="840">run.sh</text>
</g>

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -21,7 +21,7 @@
<rect id="blue" x="512" width="402" height="331" fill="url(#lg2)"/>
<rect id="blue_line" x="512" y="331" width="402" height="20" fill="#2847C5"/>
<g transform="translate(587,40) scale(0.251)">
<path id="_x2318_" d="M335,335m-145,0a145,145,0,1,1,145,-145v620a145,145,0,1,1,-145,-145h620a145,145,0,1,1,-145,145v-620a145,145,0,1,1,145,145Z" stroke="#fff" stroke-width="90" fill="transparent"/>
<path id="_x2318_" d="M335,335m-145,0a145,145,0,1,1,145,-145v620a145,145,0,1,1,-145,-145h620a145,145,0,1,1,-145,145v-620a145,145,0,1,1,145,145Z" stroke="#fff" stroke-width="90" fill="none"/>
</g>
<text x="72" y="590">run.sh</text>
<rect id="sep" y="672" width="1024" height="20" fill="#ccc"/>

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 214 B

After

Width:  |  Height:  |  Size: 214 B

3
res/status.svg Normal file
View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000">
<path id="_x2318_" d="M335,335m-145,0a145,145,0,1,1,145,-145v620a145,145,0,1,1,-145,-145h620a145,145,0,1,1,-145,145v-620a145,145,0,1,1,145,145Z" stroke="black" stroke-width="90" fill="none"/>
</svg>

After

Width:  |  Height:  |  Size: 263 B

View File

@@ -15,9 +15,9 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<string>1.0.1</string>
<key>CFBundleVersion</key>
<string>1</string>
<string>2</string>
<key>LSMinimumSystemVersion</key>
<string>10.13</string>
<key>LSBackgroundOnly</key>

View File

@@ -1,7 +1,6 @@
#!/usr/bin/env swift
import AppKit
import Cocoa
import SwiftUI
class FlippedView: NSView {
override var isFlipped: Bool { true }
@@ -21,12 +20,22 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate {
private func initStatusIcon() {
self.statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
self.statusItem.button?.title = ""
// self.statusItem.button?.image = NSImage.statusIcon
if let img = statusIcon() {
self.statusItem.button?.image = img
} else {
self.statusItem.button?.title = "" // cant load svg (<10.15)
}
self.statusItem.menu = NSMenu(title: resolvedStorageURL().path)
self.statusItem.menu?.delegate = self
}
private func statusIcon() -> NSImage? {
let img = NSImage(contentsOf: resFile("status", "svg"))
img?.isTemplate = true
img?.size = NSMakeSize(14, 14)
return img
}
func menuDidClose(_ menu: NSMenu) {
if menu == self.statusItem.menu {
self.statusItem.menu = NSMenu(title: menu.title)
@@ -67,17 +76,19 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate {
(sender.representedObject as! Entry).run()
}
// MARK: - Helper
private func resFile(_ name: String, _ ext: String?) -> URL {
// if run via .app bundle
return Bundle.main.url(forResource: name, withExtension: ext)
// if calling swift directly
?? URL(fileURLWithPath: #file + "/../../res/" + name + (ext == nil ? "" : ("." + ext!)))
}
// MARK: - Manage storage path
private func resolvedStorageURL() -> URL {
userStorageURL()
// if run via .app bundle
?? Bundle.main.url(forResource: "examples", withExtension: nil)
// if calling swift directly
?? URL(string: "file://" + FileManager.default.currentDirectoryPath + "/" + #file)!
.deletingLastPathComponent()
.deletingLastPathComponent()
.appendingPathComponent("examples")
userStorageURL() ?? resFile("examples", nil)
}
private func userStorageURL() -> URL? {
@@ -205,7 +216,7 @@ struct Entry {
var rv: [Entry] = []
for url
in (try? FileManager.default.contentsOfDirectory(
at: URL(string: path)!,
at: URL(fileURLWithPath: path),
includingPropertiesForKeys: [.isDirectoryKey, .isExecutableKey])) ?? []
{
if url.hasDirectoryPath || FileManager.default.isExecutableFile(atPath: url.path) {
@@ -267,7 +278,7 @@ struct Entry {
}
}
extension Entry : Comparable {
extension Entry: Comparable {
static func < (lhs: Entry, rhs: Entry) -> Bool {
return (lhs.order, lhs.title) < (rhs.order, rhs.title)
}