Blitz aus der mitgelieferten Vorlage, weiterhin fadend
`bolt.fill` aus SF Symbols ist eine massive Fläche; die neue Datei ist eine Kontur mit kräftigem Strich und trifft die Form besser. Gezeichnet wird sie zweifach wie zuvor: einmal etwas größer in der Gegenfarbe als Rand, einmal in der fadenden Farbe darüber. Damit bleibt der Blitz in jedem Moment des Fadens lesbar — über der hellen Füllung trägt ihn der Rand, über dem leeren Teil er sich selbst. Fehlt die Datei, bleibt das Systemsymbol. Dieselbe Vorlage auch in der Akku-Kachel, damit nicht zwei verschiedene Blitze in einer App stehen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -27,6 +27,7 @@
|
|||||||
9C2E419014B7E04630FDF151 /* OnyxApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = F89CAC2A7DA89B8707D45D65 /* OnyxApp.swift */; };
|
9C2E419014B7E04630FDF151 /* OnyxApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = F89CAC2A7DA89B8707D45D65 /* OnyxApp.swift */; };
|
||||||
9EC9D57A96489F5578000822 /* NetworkProvider in Frameworks */ = {isa = PBXBuildFile; productRef = FF4E99C8BF0D8944C314A8AF /* NetworkProvider */; };
|
9EC9D57A96489F5578000822 /* NetworkProvider in Frameworks */ = {isa = PBXBuildFile; productRef = FF4E99C8BF0D8944C314A8AF /* NetworkProvider */; };
|
||||||
A529046C33E6B00C0E9508FF /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 508DECB5C05264E6130C373E /* Localizable.xcstrings */; };
|
A529046C33E6B00C0E9508FF /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 508DECB5C05264E6130C373E /* Localizable.xcstrings */; };
|
||||||
|
A89903046D47175EE68392FA /* thunder.svg in Resources */ = {isa = PBXBuildFile; fileRef = 19F96370F33A525437F6E691 /* thunder.svg */; };
|
||||||
A9617230F602C5D52F63A7E2 /* ShelfProvider in Frameworks */ = {isa = PBXBuildFile; productRef = FA6C9F90DF47DC0DFB9ED55D /* ShelfProvider */; };
|
A9617230F602C5D52F63A7E2 /* ShelfProvider in Frameworks */ = {isa = PBXBuildFile; productRef = FA6C9F90DF47DC0DFB9ED55D /* ShelfProvider */; };
|
||||||
B0FCCD92AF22F1636482EACD /* sound-waves.svg in Resources */ = {isa = PBXBuildFile; fileRef = 8BCDFD427ACD83B8AA7BA39E /* sound-waves.svg */; };
|
B0FCCD92AF22F1636482EACD /* sound-waves.svg in Resources */ = {isa = PBXBuildFile; fileRef = 8BCDFD427ACD83B8AA7BA39E /* sound-waves.svg */; };
|
||||||
B309DD8966B5348250CEC6BD /* LaunchAtLogin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41C778876BEF3D8B04F7C3C9 /* LaunchAtLogin.swift */; };
|
B309DD8966B5348250CEC6BD /* LaunchAtLogin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41C778876BEF3D8B04F7C3C9 /* LaunchAtLogin.swift */; };
|
||||||
@@ -58,6 +59,7 @@
|
|||||||
0804288DC4A8146DD9F3FC3E /* Onyx.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Onyx.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
0804288DC4A8146DD9F3FC3E /* Onyx.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Onyx.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
085D860E654E09E4CD6E535A /* chip.svg */ = {isa = PBXFileReference; path = chip.svg; sourceTree = "<group>"; };
|
085D860E654E09E4CD6E535A /* chip.svg */ = {isa = PBXFileReference; path = chip.svg; sourceTree = "<group>"; };
|
||||||
16F2B1B9A74594526F34F5C9 /* WidgetOptionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetOptionsView.swift; sourceTree = "<group>"; };
|
16F2B1B9A74594526F34F5C9 /* WidgetOptionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetOptionsView.swift; sourceTree = "<group>"; };
|
||||||
|
19F96370F33A525437F6E691 /* thunder.svg */ = {isa = PBXFileReference; path = thunder.svg; sourceTree = "<group>"; };
|
||||||
1E6A1C208C7EA56971A055E1 /* graphic-card.svg */ = {isa = PBXFileReference; path = "graphic-card.svg"; sourceTree = "<group>"; };
|
1E6A1C208C7EA56971A055E1 /* graphic-card.svg */ = {isa = PBXFileReference; path = "graphic-card.svg"; sourceTree = "<group>"; };
|
||||||
24ADD22F5CE30B27020B479B /* MenuBarIcon.svg */ = {isa = PBXFileReference; path = MenuBarIcon.svg; sourceTree = "<group>"; };
|
24ADD22F5CE30B27020B479B /* MenuBarIcon.svg */ = {isa = PBXFileReference; path = MenuBarIcon.svg; sourceTree = "<group>"; };
|
||||||
41C778876BEF3D8B04F7C3C9 /* LaunchAtLogin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchAtLogin.swift; sourceTree = "<group>"; };
|
41C778876BEF3D8B04F7C3C9 /* LaunchAtLogin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchAtLogin.swift; sourceTree = "<group>"; };
|
||||||
@@ -179,6 +181,7 @@
|
|||||||
45BD2DF1B775C733C8F75635 /* SettingsView.swift */,
|
45BD2DF1B775C733C8F75635 /* SettingsView.swift */,
|
||||||
8E43384BA603C866D148D9D8 /* SettingsWindowController.swift */,
|
8E43384BA603C866D148D9D8 /* SettingsWindowController.swift */,
|
||||||
8BCDFD427ACD83B8AA7BA39E /* sound-waves.svg */,
|
8BCDFD427ACD83B8AA7BA39E /* sound-waves.svg */,
|
||||||
|
19F96370F33A525437F6E691 /* thunder.svg */,
|
||||||
16F2B1B9A74594526F34F5C9 /* WidgetOptionsView.swift */,
|
16F2B1B9A74594526F34F5C9 /* WidgetOptionsView.swift */,
|
||||||
);
|
);
|
||||||
path = Onyx;
|
path = Onyx;
|
||||||
@@ -295,6 +298,7 @@
|
|||||||
3991CB2BF41C6C014EF4528F /* chip.svg in Resources */,
|
3991CB2BF41C6C014EF4528F /* chip.svg in Resources */,
|
||||||
F2A3AD184864422EA14A8C64 /* graphic-card.svg in Resources */,
|
F2A3AD184864422EA14A8C64 /* graphic-card.svg in Resources */,
|
||||||
B0FCCD92AF22F1636482EACD /* sound-waves.svg in Resources */,
|
B0FCCD92AF22F1636482EACD /* sound-waves.svg in Resources */,
|
||||||
|
A89903046D47175EE68392FA /* thunder.svg in Resources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
27
Onyx/thunder.svg
Normal file
27
Onyx/thunder.svg
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
version="1.1"
|
||||||
|
id="svg1281"
|
||||||
|
xml:space="preserve"
|
||||||
|
width="682.66669"
|
||||||
|
height="682.66669"
|
||||||
|
viewBox="0 0 682.66669 682.66669"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||||
|
id="defs1285"><clipPath
|
||||||
|
clipPathUnits="userSpaceOnUse"
|
||||||
|
id="clipPath1295"><path
|
||||||
|
d="M 0,512 H 512 V 0 H 0 Z"
|
||||||
|
id="path1293" /></clipPath></defs><g
|
||||||
|
id="g1287"
|
||||||
|
transform="matrix(1.3333333,0,0,-1.3333333,0,682.66667)"><g
|
||||||
|
id="g1289"><g
|
||||||
|
id="g1291"
|
||||||
|
clip-path="url(#clipPath1295)"><g
|
||||||
|
id="g1297"
|
||||||
|
transform="translate(391,301)"><path
|
||||||
|
d="M 0,0 H -139.411 L -90,196 -270,-90 h 139.411 L -180,-286 Z"
|
||||||
|
style="fill:none;stroke:#000000;stroke-width:30;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="path1299" /></g></g></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 1.0 KiB |
@@ -68,6 +68,17 @@ public enum BatteryGlyph {
|
|||||||
return (filled, empty)
|
return (filled, empty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Der Blitz als eigene Vorlage.
|
||||||
|
///
|
||||||
|
/// SF Symbols' `bolt.fill` ist eine massive Fläche; die mitgelieferte
|
||||||
|
/// Kontur trifft die Form besser und bringt schon einen kräftigen Strich
|
||||||
|
/// mit. Fehlt die Datei, bleibt das Systemsymbol.
|
||||||
|
public static let chargingGlyph: NSImage? = {
|
||||||
|
guard let url = Bundle.main.url(forResource: "thunder", withExtension: "svg")
|
||||||
|
else { return nil }
|
||||||
|
return NSImage(contentsOf: url)
|
||||||
|
}()
|
||||||
|
|
||||||
/// Wie dick der Rand um das Zeichen ist.
|
/// Wie dick der Rand um das Zeichen ist.
|
||||||
public static let outlineWidth: CGFloat = 1
|
public static let outlineWidth: CGFloat = 1
|
||||||
|
|
||||||
@@ -186,18 +197,26 @@ public enum BatteryGlyph {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Der Blitz: weiß mit dünnem dunklem Rand, und fadend.
|
// Der Blitz: mit dunklem Rand, und fadend.
|
||||||
//
|
//
|
||||||
// Der Rand ist immer die Gegenfarbe zur Füllung. Damit bleibt er in
|
// Der Rand ist immer die Gegenfarbe zum Blitz selbst. Damit bleibt er
|
||||||
// **jedem** Moment des Fadens lesbar: über der hellen Füllung trägt ihn
|
// in **jedem** Moment des Fadens lesbar: über der hellen Füllung trägt
|
||||||
// der Rand, über dem leeren Teil die Füllung selbst.
|
// ihn der Rand, über dem leeren Teil der Blitz.
|
||||||
let whiteness = boltWhiteness(phase: fadePhase)
|
let whiteness = boltWhiteness(phase: fadePhase)
|
||||||
if let outline = tint(glyph, with: NSColor(white: 1 - whiteness, alpha: 1)) {
|
let inverseColor = NSColor(white: 1 - whiteness, alpha: 1)
|
||||||
|
let boltColor = NSColor(white: whiteness, alpha: 1)
|
||||||
|
|
||||||
|
if let custom = chargingGlyph {
|
||||||
|
MenuBarText.drawTemplate(custom, color: inverseColor, in: outlineRect(glyphRect))
|
||||||
|
MenuBarText.drawTemplate(custom, color: boltColor, in: glyphRect)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if let outline = tint(glyph, with: inverseColor) {
|
||||||
outline.draw(in: outlineRect(glyphRect), from: .zero,
|
outline.draw(in: outlineRect(glyphRect), from: .zero,
|
||||||
operation: .sourceOver, fraction: 1)
|
operation: .sourceOver, fraction: 1)
|
||||||
}
|
}
|
||||||
if let body = tint(glyph, with: NSColor(white: whiteness, alpha: 1)) {
|
if let filled = tint(glyph, with: boltColor) {
|
||||||
body.draw(in: glyphRect, from: .zero, operation: .sourceOver, fraction: 1)
|
filled.draw(in: glyphRect, from: .zero, operation: .sourceOver, fraction: 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -258,11 +277,9 @@ public struct BatteryGlyphView: View {
|
|||||||
/ BatteryGlyph.fadeDuration
|
/ BatteryGlyph.fadeDuration
|
||||||
let whiteness = BatteryGlyph.boltWhiteness(phase: phase)
|
let whiteness = BatteryGlyph.boltWhiteness(phase: phase)
|
||||||
ZStack {
|
ZStack {
|
||||||
Image(systemName: name)
|
bolt(name: name, side: size + 2 * BatteryGlyph.outlineWidth)
|
||||||
.font(.system(size: size + 2 * BatteryGlyph.outlineWidth))
|
|
||||||
.foregroundStyle(Color(white: 1 - whiteness))
|
.foregroundStyle(Color(white: 1 - whiteness))
|
||||||
Image(systemName: name)
|
bolt(name: name, side: size)
|
||||||
.font(.system(size: size))
|
|
||||||
.foregroundStyle(Color(white: whiteness))
|
.foregroundStyle(Color(white: whiteness))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -282,6 +299,20 @@ public struct BatteryGlyphView: View {
|
|||||||
.frame(width: width, height: height)
|
.frame(width: width, height: height)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Dieselbe Vorlage wie in der Menüleiste, sonst das Systemsymbol.
|
||||||
|
@ViewBuilder
|
||||||
|
private func bolt(name: String, side: CGFloat) -> some View {
|
||||||
|
if let custom = BatteryGlyph.chargingGlyph {
|
||||||
|
Image(nsImage: custom)
|
||||||
|
.renderingMode(.template)
|
||||||
|
.resizable()
|
||||||
|
.aspectRatio(contentMode: .fit)
|
||||||
|
.frame(width: side, height: side)
|
||||||
|
} else {
|
||||||
|
Image(systemName: name).font(.system(size: side))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private var fillColor: Color {
|
private var fillColor: Color {
|
||||||
BatteryGlyph.isLow(charge: charge, isCharging: isCharging) ? .red : .primary
|
BatteryGlyph.isLow(charge: charge, isCharging: isCharging) ? .red : .primary
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user