Tema surreal + logo koala baru

- assets/logo.svg (dream sky koala) + assets/icon.png hasil render 512x512
  (skrip render: oksvg/rasterx, sparkle di-inline karena <use> tidak didukung)
- tema: langit malam ungu (#140E24), kartu violet, primer dusk pink, aksen
  amber<->magenta yang berdenyut; varian terang jadi lavender lembut
- ikon monokrom dari Iconify ikut diwarnai dusk pink (#c25c9e), bukan indigo lama
- screenshot README diperbarui
This commit is contained in:
oxpoe committed 2026-10-13 09:02:09 +07:00
1 parent 25a979f24c
commit c1aed1e286
13 files changed
+120 -26

No files matched your search

+3
View File
@@ -10,6 +10,9 @@ Desktop app (Go + Fyne) that creates application shortcuts on Linux in a few cli
from an executable file, or from a web URL as a PWA. Ships as a single-file from an executable file, or from a web URL as a PWA. Ships as a single-file
AppImage, no terminal needed. AppImage, no terminal needed.
*Dream-sky theme: night violet, dusk pink and a moon-coloured accent that subtly
breathes while the app is open (the koala in `assets/logo.svg` is the mascot).*
![LazyRun main window](docs/main-dark.png) ![LazyRun main window](docs/main-dark.png)
<p align="center"> <p align="center">
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 102 KiB

+85
View File
@@ -0,0 +1,85 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 272" width="256" height="272" role="img" aria-label="lazyrun koala logo">
<title>lazyrun</title>
<defs>
<!-- dream sky -->
<linearGradient id="sky" x1="0" y1="0" x2="0.3" y2="1">
<stop offset="0" stop-color="#241247"/>
<stop offset="0.45" stop-color="#6a3d9a"/>
<stop offset="0.78" stop-color="#c25c9e"/>
<stop offset="1" stop-color="#ff9a76"/>
</linearGradient>
<!-- soft sun halo -->
<radialGradient id="sun" cx="0.5" cy="0.5" r="0.5">
<stop offset="0" stop-color="#fff3c4" stop-opacity="0.95"/>
<stop offset="0.6" stop-color="#ffd166" stop-opacity="0.45"/>
<stop offset="1" stop-color="#ffd166" stop-opacity="0"/>
</radialGradient>
<!-- glow behind koala -->
<radialGradient id="glow" cx="0.5" cy="0.5" r="0.5">
<stop offset="0" stop-color="#ffffff" stop-opacity="0.28"/>
<stop offset="1" stop-color="#ffffff" stop-opacity="0"/>
</radialGradient>
</defs>
<!-- surreal background -->
<rect x="0" y="0" width="256" height="272" rx="46" fill="url(#sky)"/>
<circle cx="128" cy="148" r="96" fill="url(#sun)"/>
<circle cx="66" cy="196" r="52" fill="url(#glow)"/>
<circle cx="196" cy="96" r="44" fill="url(#glow)"/>
<!-- floating ringed planet -->
<g opacity="0.95">
<circle cx="212" cy="62" r="13" fill="#ffd166"/>
<ellipse cx="212" cy="62" rx="24" ry="7" fill="none" stroke="#fff3c4" stroke-width="2" opacity="0.8" transform="rotate(-20 212 62)"/>
</g>
<!-- floating orbs -->
<circle cx="34" cy="150" r="7" fill="#ffd166" opacity="0.85"/>
<circle cx="224" cy="150" r="4" fill="#ffffff" opacity="0.6"/>
<circle cx="46" cy="96" r="3.5" fill="#ffffff" opacity="0.55"/>
<circle cx="206" cy="188" r="5" fill="#c25c9e" opacity="0.7"/>
<!-- sparkles -->
<g fill="#ffffff" opacity="0.85">
<path d="M44 37 C44.9 43.3 46.7 45.1 53 46 C46.7 46.9 44.9 48.7 44 55 C43.1 48.7 41.3 46.9 35 46 C41.3 45.1 43.1 43.3 44 37 Z"/>
<path d="M208 23 C208.7 27.9 210.1 29.3 215 30 C210.1 30.7 208.7 32.1 208 37 C207.3 32.1 205.9 30.7 201 30 C205.9 29.3 207.3 27.9 208 23 Z"/>
<path d="M30 202 C30.6 206.2 31.8 207.4 36 208 C31.8 208.6 30.6 209.8 30 214 C29.4 209.8 28.2 208.6 24 208 C28.2 207.4 29.4 206.2 30 202 Z"/>
<path d="M226 206 C226.8 211.6 228.4 213.2 234 214 C228.4 214.8 226.8 216.4 226 222 C225.2 216.4 223.6 214.8 218 214 C223.6 213.2 225.2 211.6 226 206 Z"/>
<path d="M128 16.5 C128.55 20.35 129.65 21.45 133.5 22 C129.65 22.55 128.55 23.65 128 27.5 C127.45 23.65 126.35 22.55 122.5 22 C126.35 21.45 127.45 20.35 128 16.5 Z"/>
<path d="M96 189.5 C96.45 192.65 97.35 193.55 100.5 194 C97.35 194.45 96.45 195.35 96 198.5 C95.55 195.35 94.65 194.45 91.5 194 C94.65 193.55 95.55 192.65 96 189.5 Z"/>
</g>
<!-- koala -->
<g>
<!-- ears -->
<circle cx="74" cy="72" r="30" fill="#9aa5b1"/>
<circle cx="74" cy="72" r="16" fill="#d9dee3"/>
<circle cx="182" cy="72" r="30" fill="#9aa5b1"/>
<circle cx="182" cy="72" r="16" fill="#d9dee3"/>
<!-- head -->
<ellipse cx="128" cy="118" rx="68" ry="62" fill="#a7b2bd"/>
<!-- eyes -->
<circle cx="104" cy="110" r="8" fill="#2b2f36"/>
<circle cx="101.5" cy="107" r="2.6" fill="#ffffff"/>
<circle cx="152" cy="110" r="8" fill="#2b2f36"/>
<circle cx="149.5" cy="107" r="2.6" fill="#ffffff"/>
<!-- nose -->
<ellipse cx="128" cy="140" rx="16" ry="11" fill="#2b2f36"/>
<ellipse cx="123" cy="137" rx="4" ry="3" fill="#4b5058"/>
<!-- mouth -->
<path d="M128 151 v6 q0 6 -9 6" fill="none" stroke="#2b2f36" stroke-width="3" stroke-linecap="round"/>
<path d="M128 157 q0 6 9 6" fill="none" stroke="#2b2f36" stroke-width="3" stroke-linecap="round"/>
</g>
<!-- wordmark -->
<text x="128" y="240" text-anchor="middle"
font-family="'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
font-size="42" font-weight="700" letter-spacing="-1"
fill="#ffffff">lazyrun</text>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 54 KiB

+3 -2
View File
@@ -11,8 +11,9 @@ import (
"github.com/srwiley/rasterx" "github.com/srwiley/rasterx"
) )
// currentColor diisi ke SVG yang memakai fill="currentColor". // currentColor diisi ke SVG yang memakai fill="currentColor"
const currentColor = "#4f46e5" // (warna brand: dusk pink, terlihat di background terang maupun gelap).
const currentColor = "#c25c9e"
// Rasterize mengubah SVG menjadi PNG persegi `size`x`size`. // Rasterize mengubah SVG menjadi PNG persegi `size`x`size`.
// //
+3 -3
View File
@@ -76,9 +76,9 @@ func TestRasterizeColorsCurrentColorIcons(t *testing.T) {
if a == 0 { if a == 0 {
t.Fatal("ikon currentColor tidak terwarnai (transparan)") t.Fatal("ikon currentColor tidak terwarnai (transparan)")
} }
// brand indigo #4F46E5: biru > merah > hijau // brand dusk pink #C25C9E: merah > biru > hijau
if !(b > r && r > g) { if !(r > b && b > g) {
t.Errorf("warna pengganti bukan brand indigo: r=%d g=%d b=%d", r>>8, g>>8, b>>8) t.Errorf("warna pengganti bukan warna brand: r=%d g=%d b=%d", r>>8, g>>8, b>>8)
} }
} }
+1 -1
View File
@@ -17,7 +17,7 @@ import (
// pulseGradient membuat garis aksen bergerak bolak-balik antara indigo dan cyan. // pulseGradient membuat garis aksen bergerak bolak-balik antara indigo dan cyan.
func pulseGradient(bar *canvas.LinearGradient) { func pulseGradient(bar *canvas.LinearGradient) {
anim := canvas.NewColorRGBAAnimation(brandIndigo, brandCyan, 3*time.Second, func(c color.Color) { anim := canvas.NewColorRGBAAnimation(brandAmber, brandMagenta, 3*time.Second, func(c color.Color) {
bar.EndColor = c bar.EndColor = c
canvas.Refresh(bar) canvas.Refresh(bar)
}) })
+4 -3
View File
@@ -32,6 +32,7 @@ type app struct {
icons *iconCache icons *iconCache
count *canvas.Text // angka jumlah shortcut di header daftar count *canvas.Text // angka jumlah shortcut di header daftar
versionText *canvas.Text // versi di footer; berubah kalau ada update versionText *canvas.Text // versi di footer; berubah kalau ada update
accent *canvas.LinearGradient
version string version string
} }
@@ -87,9 +88,9 @@ func build(a fyne.App, version string) (*app, error) {
ui.versionText, ui.versionText,
) )
accent := accentBar() ui.accent = accentBar()
pulseGradient(accent) pulseGradient(ui.accent)
top := container.NewVBox(header, accent, top := container.NewVBox(header, ui.accent,
container.NewHBox(sectionLabel(T("installed")), countChip)) container.NewHBox(sectionLabel(T("installed")), countChip))
body := container.NewBorder( body := container.NewBorder(
top, top,
+1 -1
View File
@@ -78,7 +78,7 @@ func chipLabel(text string, bg fyne.ThemeColorName) (fyne.CanvasObject, *canvas.
// accentBar adalah garis gradien brand di bawah header. // accentBar adalah garis gradien brand di bawah header.
func accentBar() *canvas.LinearGradient { func accentBar() *canvas.LinearGradient {
bar := canvas.NewLinearGradient(brandIndigo, brandCyan, 90) bar := canvas.NewLinearGradient(brandAmber, brandMagenta, 90)
bar.SetMinSize(fyne.NewSize(0, 3)) bar.SetMinSize(fyne.NewSize(0, 3))
return bar return bar
} }
+20 -16
View File
@@ -7,10 +7,11 @@ import (
"fyne.io/fyne/v2/theme" "fyne.io/fyne/v2/theme"
) )
// Palet brand LazyRun, diambil dari ikon aplikasi. // Palet brand LazyRun, diambil dari logo (dream sky: ungu malam, senja pink, bulan amber).
var ( var (
brandIndigo = color.NRGBA{R: 0x4F, G: 0x46, B: 0xE5, A: 0xFF} brandPurple = color.NRGBA{R: 0x6A, G: 0x3D, B: 0x9A, A: 0xFF}
brandCyan = color.NRGBA{R: 0x06, G: 0xB6, B: 0xD4, A: 0xFF} brandMagenta = color.NRGBA{R: 0xC2, G: 0x5C, B: 0x9E, A: 0xFF}
brandAmber = color.NRGBA{R: 0xFF, G: 0xD1, B: 0x66, A: 0xFF}
) )
// Nama warna tambahan di luar tema standar Fyne. // Nama warna tambahan di luar tema standar Fyne.
@@ -31,31 +32,34 @@ func (b brand) Color(name fyne.ThemeColorName, variant fyne.ThemeVariant) color.
dark := variant == theme.VariantDark dark := variant == theme.VariantDark
switch name { switch name {
case theme.ColorNamePrimary: case theme.ColorNamePrimary:
return pick(dark, color.NRGBA{R: 0x7C, G: 0x7A, B: 0xFF, A: 0xFF}, brandIndigo) // senja pink di malam hari, ungu tua di tema terang
return pick(dark, brandMagenta, color.NRGBA{R: 0x8E, G: 0x3F, B: 0xA8, A: 0xFF})
case theme.ColorNameBackground: case theme.ColorNameBackground:
return pick(dark, color.NRGBA{R: 0x13, G: 0x13, B: 0x1B, A: 0xFF}, color.NRGBA{R: 0xF5, G: 0xF5, B: 0xFA, A: 0xFF}) // langit malam surreal
return pick(dark, color.NRGBA{R: 0x14, G: 0x0E, B: 0x24, A: 0xFF}, color.NRGBA{R: 0xF5, G: 0xEF, B: 0xF9, A: 0xFF})
case colorNameCard: case colorNameCard:
return pick(dark, color.NRGBA{R: 0x1D, G: 0x1D, B: 0x28, A: 0xFF}, color.NRGBA{R: 0xFF, G: 0xFF, B: 0xFF, A: 0xFF}) return pick(dark, color.NRGBA{R: 0x1E, G: 0x16, B: 0x36, A: 0xFF}, color.NRGBA{R: 0xFF, G: 0xFF, B: 0xFF, A: 0xFF})
case colorNameCardHover: case colorNameCardHover:
return withAlpha(brandIndigo, pick[uint8](dark, 0x2E, 0x14)) return withAlpha(brandAmber, pick[uint8](dark, 0x1F, 0x18))
case theme.ColorNameInputBackground: case theme.ColorNameInputBackground:
return pick(dark, color.NRGBA{R: 0x1A, G: 0x1A, B: 0x24, A: 0xFF}, color.NRGBA{R: 0xFF, G: 0xFF, B: 0xFF, A: 0xFF}) return pick(dark, color.NRGBA{R: 0x19, G: 0x11, B: 0x35, A: 0xFF}, color.NRGBA{R: 0xFF, G: 0xFF, B: 0xFF, A: 0xFF})
case theme.ColorNameButton, theme.ColorNameMenuBackground: case theme.ColorNameButton, theme.ColorNameMenuBackground:
return pick(dark, color.NRGBA{R: 0x22, G: 0x22, B: 0x2E, A: 0xFF}, color.NRGBA{R: 0xEC, G: 0xEC, B: 0xF4, A: 0xFF}) return pick(dark, color.NRGBA{R: 0x26, G: 0x1B, B: 0x45, A: 0xFF}, color.NRGBA{R: 0xED, G: 0xE3, B: 0xF5, A: 0xFF})
case theme.ColorNameOverlayBackground: case theme.ColorNameOverlayBackground:
return pick(dark, color.NRGBA{R: 0x1B, G: 0x1B, B: 0x25, A: 0xFF}, color.NRGBA{R: 0xFF, G: 0xFF, B: 0xFF, A: 0xFF}) return pick(dark, color.NRGBA{R: 0x1B, G: 0x13, B: 0x33, A: 0xFF}, color.NRGBA{R: 0xFF, G: 0xFF, B: 0xFF, A: 0xFF})
case theme.ColorNameInputBorder, theme.ColorNameSeparator: case theme.ColorNameInputBorder, theme.ColorNameSeparator:
return pick(dark, color.NRGBA{R: 0x32, G: 0x32, B: 0x44, A: 0xFF}, color.NRGBA{R: 0xDC, G: 0xDC, B: 0xE8, A: 0xFF}) return pick(dark, color.NRGBA{R: 0x3A, G: 0x2A, B: 0x63, A: 0xFF}, color.NRGBA{R: 0xDC, G: 0xCF, B: 0xE9, A: 0xFF})
case colorNameMuted: case colorNameMuted:
return pick(dark, color.NRGBA{R: 0x9C, G: 0x9C, B: 0xB4, A: 0xFF}, color.NRGBA{R: 0x6B, G: 0x6B, B: 0x80, A: 0xFF}) return pick(dark, color.NRGBA{R: 0xA7, G: 0x9A, B: 0xC8, A: 0xFF}, color.NRGBA{R: 0x6E, G: 0x61, B: 0x83, A: 0xFF})
case colorNameChipMenu: case colorNameChipMenu:
return withAlpha(brandIndigo, pick[uint8](dark, 0x44, 0x26)) return withAlpha(brandPurple, pick[uint8](dark, 0x66, 0x2E))
case colorNameChipDesk: case colorNameChipDesk:
return withAlpha(brandCyan, pick[uint8](dark, 0x3D, 0x2C)) return withAlpha(brandMagenta, pick[uint8](dark, 0x4E, 0x30))
case colorNameChipKind: case colorNameChipKind:
return pick(dark, color.NRGBA{R: 0xFF, G: 0xFF, B: 0xFF, A: 0x1C}, color.NRGBA{R: 0x00, G: 0x00, B: 0x00, A: 0x12}) return withAlpha(color.NRGBA{R: 0xFF, G: 0xD1, B: 0x66, A: 0xFF}, pick[uint8](dark, 0x24, 0x30))
case colorNameChipBroken: case colorNameChipBroken:
return withAlpha(color.NRGBA{R: 0xE0, G: 0x4F, B: 0x4F, A: 0xFF}, pick[uint8](dark, 0x4A, 0x2E)) // merah senja: peringatan yang tetap terasa "seram" tapi terbaca
return withAlpha(color.NRGBA{R: 0xD9, G: 0x46, B: 0x3C, A: 0xFF}, pick[uint8](dark, 0x50, 0x30))
} }
return b.Theme.Color(name, variant) return b.Theme.Color(name, variant)
} }