refactor to use argparsing and add animation

This commit is contained in:
Daylin Morgan 2024-02-19 16:05:52 -06:00
parent 590de5a507
commit a6e1093c0e
Signed by: daylin
GPG key ID: C1E52E7DD81DF79F
7 changed files with 128 additions and 42 deletions

View file

@ -10,7 +10,8 @@ all:
@$(MAKE) pngs @$(MAKE) pngs
svgs: ## generate all svgs svgs: ## generate all svgs
nimble run nimble run -- --background none,square,circle --style light,dark --border --output docs/svg
nimble run -- --background none,square,circle --style light,dark --output docs/svg
pngs: ## generate all of the logo pngs pngs: ## generate all of the logo pngs
nimble pngs nimble pngs
@ -25,6 +26,9 @@ docs/png/index.html: docs/index.html
sed s'/My Logos/My Logos but PNG/g' \ sed s'/My Logos/My Logos but PNG/g' \
> docs/png/index.html > docs/png/index.html
assets/logo.svg:
nimble run -- --background circle --style dark --animate --border --output assets/logo.svg
clean: ## remove old files clean: ## remove old files
rm -f *.svg *.png rm -f *.svg *.png
rm -f docs/*.svg rm -f docs/*.svg

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- © 2023 Daylin Morgan | rev. da2aae4 --> <!-- © 2023 Daylin Morgan | rev. 590de5a -->
<svg height="800" width="800" xmlns="http://www.w3.org/2000/svg" version="1.1"> <svg height="800" width="800" xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs> <defs>
<style type="text/css"> <style type="text/css">
@ -10,11 +10,11 @@
} }
.fg { .fg {
fill:#f5e0dc; fill: #f5e0dc;
stroke:#f5e0dc; stroke: #f5e0dc;
} }
.border { .border {
fill:none; fill: none;
stroke-width: 5; stroke-width: 5;
} }
@ -28,6 +28,17 @@
.d { .d {
stroke-width: 15; stroke-width: 15;
} }
.m {
stroke-dasharray: 2000;
stroke-dashoffset: 2000;
animation: draw 2.5s linear forwards;
}
@keyframes draw {
to {
stroke-dashoffset: 0;
}
}
</style> </style>
</defs> </defs>
@ -36,7 +47,7 @@
<circle class="fg border" cx="400.0" cy="400.0" r="380.0"/> <circle class="fg border" cx="400.0" cy="400.0" r="380.0"/>
</g> </g>
<g class="fg logo"> <g class="fg logo">
<path d=" M 280.4,548.0 <path class="m" d=" M 280.4,548.0
l -160.0,0 l -160.0,0
l 80.0,-280.0 l 80.0,-280.0
l 199.6,400.0 l 199.6,400.0
@ -45,6 +56,7 @@
l -160.0, 0 l -160.0, 0
"/> "/>
<g class="d"> <g class="d">
<animateTransform attributeName="transform" begin="0s" dur="2.25s" type="rotate" from="0 400.0 268.0" to="360 400.0 268.0"/>
<circle cx="400.0" cy="268.0" r="136.0"/> <circle cx="400.0" cy="268.0" r="136.0"/>
<path class="fg" d="M 264.0,268.0 a 1 1 0 0 0 272.0 0 z"/> <path class="fg" d="M 264.0,268.0 a 1 1 0 0 0 272.0 0 z"/>
</g> </g>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

11
src/css/animation.css Normal file
View file

@ -0,0 +1,11 @@
.m {
stroke-dasharray: 2000;
stroke-dashoffset: 2000;
animation: draw 2.5s linear forwards;
}
@keyframes draw {
to {
stroke-dashoffset: 0;
}
}

View file

@ -1,5 +1,5 @@
.border { .border {
fill:none; fill: none;
stroke-width: 5; stroke-width: 5;
} }

View file

@ -4,6 +4,6 @@
} }
.fg { .fg {
fill:#f5e0dc; fill: #f5e0dc;
stroke:#f5e0dc; stroke: #f5e0dc;
} }

View file

@ -1,6 +1,6 @@
/* light css */ /* light css */
.background { .background {
fill:#f5e0dc; fill: #f5e0dc;
} }
.fg { .fg {

View file

@ -1,26 +1,35 @@
import std/[os, strformat, strutils] import std/[os, strformat, strutils, sugar]
import nimsvg import nimsvg
const const
baseCSS = slurp "css/base.css" baseCSS = slurp "css/base.css"
lightCSS = slurp "css/light.css" lightCSS = slurp "css/light.css"
darkCSS = slurp "css/dark.css" darkCSS = slurp "css/dark.css"
animateCss = slurp "css/animation.css"
version = staticExec "git describe --tags HEAD --always" version = staticExec "git describe --tags HEAD --always"
scale = 800
type type
Style = enum Style = enum
stLight, stDark stLight = "light"
stDark = "dark"
Background = enum Background = enum
bgNone, bgCircle, bgSquare bgNone = "none"
bgCircle = "circle"
bgSquare ="square"
Point = object Point = object
x, y: float64 x, y: float64
Logo = object Logo = object
background: Background background: Background
border: bool animate, border: bool
style: Style style: Style
LogoContext = object
const scale = 800 border, animate: bool
output: string
backgrounds: seq[Background]
styles: seq[Style]
proc calcCoordinates(my1, my2, mx1, mx2, dr, gap: float64): tuple[my1, my2, mx1, proc calcCoordinates(my1, my2, mx1, mx2, dr, gap: float64): tuple[my1, my2, mx1,
@ -56,9 +65,10 @@ proc drawM(): Nodes =
let startEndOffset = 0.15 * (coord.mx1) let startEndOffset = 0.15 * (coord.mx1)
let moveTo = Point(x: coord.mc.x - coord.mx1 - startEndOffset, y: coord.mc.y) let moveTo = Point(x: coord.mc.x - coord.mx1 - startEndOffset, y: coord.mc.y)
# path(
buildSvg: buildSvg:
path(d = &""" path(
`class` ="m",
d = &"""
M {moveTo.x},{moveTo.y} M {moveTo.x},{moveTo.y}
l -{coord.mx2},0 l -{coord.mx2},0
l {coord.mx2/2},-{coord.my2} l {coord.mx2/2},-{coord.my2}
@ -70,10 +80,13 @@ proc drawM(): Nodes =
) )
proc drawD(): Nodes = proc drawD(animate: bool): Nodes =
let start = Point(x: coord.dc.x - coord.dr, y: coord.dc.y) let start = Point(x: coord.dc.x - coord.dr, y: coord.dc.y)
buildSvg: buildSvg:
g(class = "d"): g(class = "d"):
if animate:
let coords = $coord.dc.x & " " & $coord.dc.y
animateTransform(attributeName="transform", begin="0s" ,dur="2.25s", type="rotate", `from`="0 " & coords, to="360 " & coords)
circle(cx = coord.dc.x, cy = coord.dc.y, r = coord.dr) circle(cx = coord.dc.x, cy = coord.dc.y, r = coord.dr)
path(class = "fg", d = &"M {start.x},{start.y} a 1 1 0 0 0 {coord.dr*2} 0 z") path(class = "fg", d = &"M {start.x},{start.y} a 1 1 0 0 0 {coord.dr*2} 0 z")
@ -91,12 +104,14 @@ proc addBackground(bg: Background, border: bool = true): Nodes =
rect(class = "fg border", height = scale-2*coord.gap, rect(class = "fg border", height = scale-2*coord.gap,
width = scale-2*coord.gap, x = coord.gap, y = coord.gap) width = scale-2*coord.gap, x = coord.gap, y = coord.gap)
proc addStyle(s: Style): Nodes = proc addStyle(l: Logo): Nodes =
var css: string var css: string
case s: case l.style:
of stDark: css &= darkCSS of stDark: css &= darkCSS
of stLight: css &= lightCSS of stLight: css &= lightCSS
css &= baseCSS css &= baseCSS
if l.animate:
css &= animateCss
buildSvg: buildSvg:
style(type = "text/css"): style(type = "text/css"):
t: css t: css
@ -119,33 +134,77 @@ proc fname(l: Logo): string =
proc makeLogo(l: Logo, prefix = "docs/svg", fileName = "") = proc makeLogo(l: Logo, prefix = "docs/svg", fileName = "") =
if not dirExists(prefix): createDir(prefix) if not dirExists(prefix): createDir(prefix)
let fname = prefix / (if fileName == "": l.fname() else: fileName) let fname = prefix / (if fileName == "": l.fname() else: fileName)
echo "generating logo at: ", fname
buildSvgFile(fname): buildSvgFile(fname):
t: &"<!-- © 2023 Daylin Morgan | rev. {version} -->" t: &"<!-- © 2024 Daylin Morgan | rev. {version} -->"
svg(height = scale, width = scale): svg(height = scale, width = scale):
defs: embed addStyle(l.style) defs: embed addStyle(l)
if l.background != bgNone: embed addBackground(l.background, l.border) if l.background != bgNone: embed addBackground(l.background, l.border)
g(class = "fg logo"): g(class = "fg logo"):
embed drawM() embed drawM()
embed drawD() embed drawD(l.animate)
when isMainModule: when isMainModule:
for bg in @[bgNone, bgSquare, bgCircle]: import std/parseopt
for style in @[stLight, stDark]: const usage = """
for border in @[true, false]: logo [opts]
options:
-h, --help
show this help
-a, --animate
add animation to logo
-o, --output
output file or path
-b, --background
comma-seperated list of backgrounds [none,square,circle]
-s, --style
comma-seperated list of styles [light,dark]
--border
add border
"""
var c = LogoContext()
for kind, key, val in getopt(shortNoVal = {'h','a'}, longNoVal = @["help","animate","border"]):
case kind
of cmdArgument: echo "unexpected positional arg: " & key; quit 1
of cmdShortOption, cmdLongOption:
case key
of "h", "help":
echo usage; quit 0;
of "a","animate":
c.animate = true
of "o", "output":
c.output = val
of "b","background":
for bg in val.split(","):
c.backgrounds.add parseEnum[Background](bg)
of "s","style":
for s in val.split(","):
c.styles.add parseEnum[Style](s)
of "border":
c.border = true
else:
echo "unknown key-value flag: " & key & "," & val
of cmdEnd: discard
if c.backgrounds.len == 0 or c.styles.len == 0:
echo "must provide at least one value for background/style"
quit 1
let logos = collect:
for bg in c.backgrounds:
for style in c.styles:
Logo( Logo(
background: bg, background: bg,
border: border, border: c.border,
style: style style: style,
).makeLogo() animate: c.animate
)
if logos.len == 1:
echo "treating output as filename"
makeLogo(logos[0], prefix = "", fileName = c.output)
else:
for logo in logos:
makeLogo(logo, prefix = c.output)
let defaults = @[
(Logo(background: bgCircle, border: true, style: stDark), "light.svg"),
(Logo(background: bgCircle, border: true, style: stLight), "dark.svg")
]
for (logo, fname) in defaults:
logo.makeLogo(fileName = fname, prefix = "docs")
when defined(makeDefault):
Logo(background: bgCircle, border: true, style: stDark).makeLogo(
prefix = "assets", "logo.svg")