galaaz 2.1.7 → 2.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +39 -0
  3. data/Rakefile +20 -2
  4. data/bin/check_gemfile_lock_version +46 -0
  5. data/bin/release_bump +26 -0
  6. data/blogs/README.md +4 -0
  7. data/blogs/galaaz_2_0/galaaz_2_0.Rmd +385 -0
  8. data/blogs/galaaz_2_0/galaaz_2_0.md +409 -0
  9. data/blogs/galaaz_2_0/galaaz_2_0.tex +756 -0
  10. data/blogs/galaaz_2_0/images/galaaz-header.png +0 -0
  11. data/blogs/galaaz_2_0/images/galaaz-lockup-stacked.png +0 -0
  12. data/blogs/galaaz_ggplot/galaaz_ggplot.Rmd +76 -58
  13. data/blogs/galaaz_ggplot/galaaz_ggplot.md +188 -161
  14. data/blogs/galaaz_ggplot/galaaz_ggplot.tex +185 -117
  15. data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-html/midwest_rb.png +0 -0
  16. data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-html/scatter_plot_rb.png +0 -0
  17. data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-markdown_github/midwest_rb.png +0 -0
  18. data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-markdown_github/scatter_plot_rb.png +0 -0
  19. data/blogs/galaaz_ggplot/images/galaaz-lockup-stacked.png +0 -0
  20. data/blogs/gknit/gknit.Rmd +48 -28
  21. data/blogs/gknit/gknit.md +60 -43
  22. data/blogs/gknit/gknit.tex +1409 -0
  23. data/blogs/gknit/gknit_files/figure-html/bubble-1.png +0 -0
  24. data/blogs/gknit/gknit_files/figure-html/diverging_bar.png +0 -0
  25. data/blogs/gknit/gknit_files/figure-latex/bubble-1.png +0 -0
  26. data/blogs/gknit/images/galaaz-lockup-stacked.png +0 -0
  27. data/blogs/manual/images/galaaz-lockup-stacked.png +0 -0
  28. data/blogs/manual/manual.Rmd +161 -71
  29. data/blogs/manual/manual.md +573 -482
  30. data/blogs/manual/manual.tex +1113 -517
  31. data/blogs/manual/manual_files/figure-html/bubble-1.png +0 -0
  32. data/blogs/manual/manual_files/figure-latex/bubble-1.png +0 -0
  33. data/blogs/manual/manual_files/figure-markdown_github/bubble-1.png +0 -0
  34. data/blogs/manual/manual_files/figure-markdown_github/diverging_bar.png +0 -0
  35. data/blogs/nse_dplyr/images/galaaz-lockup-stacked.png +0 -0
  36. data/blogs/nse_dplyr/nse_dplyr.Rmd +42 -8
  37. data/blogs/nse_dplyr/nse_dplyr.md +69 -50
  38. data/blogs/nse_dplyr/nse_dplyr.tex +1626 -0
  39. data/blogs/oh_my/images/galaaz-lockup-stacked.png +0 -0
  40. data/blogs/oh_my/oh_my.Rmd +206 -55
  41. data/blogs/oh_my/oh_my.md +247 -96
  42. data/blogs/oh_my/oh_my.tex +2038 -93
  43. data/blogs/r_on_rails_ledger/images/00_portfolio_page.png +0 -0
  44. data/blogs/r_on_rails_ledger/images/01_results_panel.png +0 -0
  45. data/blogs/r_on_rails_ledger/images/02_density_tail_risk.png +0 -0
  46. data/blogs/r_on_rails_ledger/images/03_mc_cone.png +0 -0
  47. data/blogs/r_on_rails_ledger/images/04_rolling_var.png +0 -0
  48. data/blogs/r_on_rails_ledger/images/galaaz-lockup-stacked.png +0 -0
  49. data/blogs/r_on_rails_ledger/r_on_rails_ledger.Rmd +354 -0
  50. data/blogs/r_on_rails_ledger/r_on_rails_ledger.md +365 -0
  51. data/blogs/r_on_rails_ledger/r_on_rails_ledger.tex +670 -0
  52. data/blogs/ruby_plot/images/galaaz-lockup-stacked.png +0 -0
  53. data/blogs/ruby_plot/ruby_plot.Rmd +56 -35
  54. data/blogs/ruby_plot/ruby_plot.md +63 -47
  55. data/blogs/ruby_plot/ruby_plot.tex +194 -125
  56. data/blogs/ruby_plot/ruby_plot_files/figure-html/dose_len.png +0 -0
  57. data/blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_delivery.png +0 -0
  58. data/blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_dose.png +0 -0
  59. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_by_delivery_color.png +0 -0
  60. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_by_delivery_color2.png +0 -0
  61. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_decorations.png +0 -0
  62. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_jitter.png +0 -0
  63. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_points.png +0 -0
  64. data/blogs/ruby_plot/ruby_plot_files/figure-html/final_box_plot.png +0 -0
  65. data/blogs/ruby_plot/ruby_plot_files/figure-html/final_violin_plot.png +0 -0
  66. data/blogs/ruby_plot/ruby_plot_files/figure-html/violin_with_jitter.png +0 -0
  67. data/blogs/ruby_plot/ruby_plot_files/figure-latex/dose_len.png +0 -0
  68. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facet_by_delivery.png +0 -0
  69. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facet_by_dose.png +0 -0
  70. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_by_delivery_color.png +0 -0
  71. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_by_delivery_color2.png +0 -0
  72. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_with_decorations.png +0 -0
  73. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_with_jitter.png +0 -0
  74. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_with_points.png +0 -0
  75. data/blogs/ruby_plot/ruby_plot_files/figure-latex/final_box_plot.png +0 -0
  76. data/blogs/ruby_plot/ruby_plot_files/figure-latex/final_violin_plot.png +0 -0
  77. data/blogs/ruby_plot/ruby_plot_files/figure-latex/violin_with_jitter.png +0 -0
  78. data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/dose_len.png +0 -0
  79. data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/facet_by_delivery.png +0 -0
  80. data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/facet_by_dose.png +0 -0
  81. data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/facets_by_delivery_color.png +0 -0
  82. data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/facets_by_delivery_color2.png +0 -0
  83. data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/facets_with_decorations.png +0 -0
  84. data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/facets_with_jitter.png +0 -0
  85. data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/facets_with_points.png +0 -0
  86. data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/final_box_plot.png +0 -0
  87. data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/final_violin_plot.png +0 -0
  88. data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/violin_with_jitter.png +0 -0
  89. data/lib/galaaz/cli.rb +98 -13
  90. data/logos/icon-font/README.md +27 -0
  91. data/logos/icon-font/build_font.py +130 -0
  92. data/logos/icon-font/galaaz-mark.svg +34 -0
  93. data/script/omarchy/README.md +9 -2
  94. data/script/omarchy/fonts/galaaz.ttf +0 -0
  95. data/script/omarchy/galaaz-guide.sh +1 -1
  96. data/script/omarchy/install-galaaz.sh +8 -1
  97. data/script/omarchy/omarchy-menu.jsonc +21 -9
  98. data/sty/galaaz-header.png +0 -0
  99. data/sty/galaaz-headers-from-p3.tex +4 -0
  100. data/sty/galaaz.sty +76 -23
  101. data/version.rb +1 -1
  102. metadata +46 -7
  103. data/blogs/galaaz_ggplot/galaaz_ggplot.log +0 -754
  104. data/blogs/manual/manual.log +0 -1786
  105. data/blogs/nse_dplyr/nse_dplyr.log +0 -928
  106. data/blogs/oh_my/oh_my.log +0 -804
  107. data/blogs/ruby_plot/ruby_plot.log +0 -885
data/lib/galaaz/cli.rb CHANGED
@@ -8,7 +8,9 @@ require 'tmpdir'
8
8
 
9
9
  module Galaaz
10
10
  module CLI
11
- BLOG_NAMES = %w[oh_my gknit galaaz_ggplot manual nse_dplyr ruby_plot].freeze
11
+ BLOG_NAMES = %w[
12
+ oh_my gknit galaaz_ggplot galaaz_2_0 r_on_rails_ledger manual nse_dplyr ruby_plot
13
+ ].freeze
12
14
  PROFILES = %w[knit arrow tex bio examples ledger demo].freeze
13
15
  CONFIG_DIR = File.join(Dir.home, '.config', 'galaaz')
14
16
  PROFILES_DIR = File.join(CONFIG_DIR, 'profiles')
@@ -28,6 +30,8 @@ module Galaaz
28
30
  ['debug-galaaz.sh', 'omarchy-galaaz-debug', true]
29
31
  ].freeze
30
32
  OMARCHY_MENU_FILE = 'omarchy-menu.jsonc'
33
+ OMARCHY_FONT_REL = File.join('fonts', 'galaaz.ttf')
34
+ OMARCHY_FONT_FAMILY = 'galaaz'
31
35
  BLOGS_MARKER = '.galaaz-blogs'
32
36
  EXAMPLES_MARKER = '.galaaz-examples'
33
37
  CRAN = 'https://cloud.r-project.org'
@@ -148,6 +152,7 @@ module Galaaz
148
152
  Writes:
149
153
  ~/.local/bin/omarchy-install-galaaz (and add/remove/guide/gknit/debug)
150
154
  ~/.config/omarchy/extensions/omarchy-menu.jsonc
155
+ ~/.local/share/fonts/galaaz/galaaz.ttf (menu brand mark)
151
156
 
152
157
  Then: Super+Space → Install → Development → Galaaz
153
158
  HELP
@@ -193,6 +198,8 @@ module Galaaz
193
198
  puts " #{dest}: #{File.file?(path) ? path : 'MISSING'}"
194
199
  end
195
200
  puts " menu: #{File.file?(menu) ? menu : 'MISSING'}"
201
+ font = File.expand_path('~/.local/share/fonts/galaaz/galaaz.ttf')
202
+ puts " font: #{File.file?(font) ? font : 'MISSING'}"
196
203
  bundled = File.join(root, 'script', 'omarchy')
197
204
  puts " gem overlay: #{File.directory?(bundled) ? bundled : 'MISSING (reinstall gem)'}"
198
205
  0
@@ -202,7 +209,9 @@ module Galaaz
202
209
  d = File.join(root, 'script', 'omarchy')
203
210
  abort_unless(File.directory?(d), "Omarchy overlay missing from gem (#{d}). Reinstall galaaz.")
204
211
  abort_unless(
205
- File.file?(File.join(d, 'install-galaaz.sh')) && File.file?(File.join(d, OMARCHY_MENU_FILE)),
212
+ File.file?(File.join(d, 'install-galaaz.sh')) &&
213
+ File.file?(File.join(d, OMARCHY_MENU_FILE)) &&
214
+ File.file?(File.join(d, OMARCHY_FONT_REL)),
206
215
  "incomplete Omarchy overlay in gem (#{d})"
207
216
  )
208
217
  d
@@ -213,10 +222,11 @@ module Galaaz
213
222
  tmp = Dir.mktmpdir('galaaz-omarchy-')
214
223
  base = "https://raw.githubusercontent.com/#{OMARCHY_GITHUB_REPO}/#{ref}/script/omarchy"
215
224
  puts "galaaz omarchy: fetching #{base}/…"
216
- names = OMARCHY_BIN_FILES.map(&:first) + [OMARCHY_MENU_FILE]
225
+ names = OMARCHY_BIN_FILES.map(&:first) + [OMARCHY_MENU_FILE, OMARCHY_FONT_REL]
217
226
  names.uniq.each do |name|
218
227
  url = "#{base}/#{name}"
219
228
  dest = File.join(tmp, name)
229
+ FileUtils.mkdir_p(File.dirname(dest))
220
230
  ok = system('curl', '-fsSL', '-o', dest, url)
221
231
  unless ok && File.file?(dest) && File.size(dest).positive?
222
232
  FileUtils.rm_rf(tmp)
@@ -247,6 +257,23 @@ module Galaaz
247
257
  menu_dest = File.join(ext, OMARCHY_MENU_FILE)
248
258
  FileUtils.cp(menu_src, menu_dest)
249
259
  puts "galaaz omarchy: #{menu_dest}"
260
+
261
+ install_omarchy_font_from!(src_dir)
262
+ end
263
+
264
+ def install_omarchy_font_from!(src_dir)
265
+ src = File.join(src_dir, OMARCHY_FONT_REL)
266
+ abort_unless(File.file?(src), "missing #{src} (rebuild with logos/icon-font/build_font.py)")
267
+ fonts = File.expand_path('~/.local/share/fonts/galaaz')
268
+ FileUtils.mkdir_p(fonts)
269
+ dest = File.join(fonts, 'galaaz.ttf')
270
+ FileUtils.cp(src, dest)
271
+ puts "galaaz omarchy: #{dest} (family #{OMARCHY_FONT_FAMILY}, U+E900)"
272
+ if command_present?('fc-cache')
273
+ system('fc-cache', '-f', fonts)
274
+ end
275
+ warn 'galaaz omarchy: restart the Omarchy shell so Qt picks up the galaaz font' \
276
+ if ENV['OMARCHY_PATH'] || File.directory?(File.expand_path('~/.config/omarchy'))
250
277
  end
251
278
 
252
279
  # ---- blogs ----
@@ -587,18 +614,33 @@ module Galaaz
587
614
 
588
615
  Dir.chdir(dest) do
589
616
  need_cmd!('bundle')
590
- # Lockfile often still pins path: ../galaaz @ an old version — pull latest RubyGems.
617
+ ensure_ledger_bundler!
618
+ # Fresh clone: install the full lockfile under the app's Ruby (mise .ruby-version).
619
+ # Do not run `bundle update` first — that can mix PATH Ruby with app Ruby and skip install.
620
+ puts 'galaaz add ledger: bundle install'
621
+ abort_unless(ledger_bundle('install'), 'bundle install failed')
591
622
  puts 'galaaz add ledger: bundle update galaaz'
592
- unless system('bundle', 'update', 'galaaz')
593
- abort_unless(system('bundle', 'install'), 'bundle install failed')
594
- end
595
- # Setup the gem Bundler will load (not PATH galaaz, which may differ).
623
+ ledger_bundle('update', 'galaaz') ||
624
+ warn('galaaz add ledger: bundle update galaaz returned non-zero (continuing with installed galaaz)')
596
625
  puts 'galaaz add ledger: bundle exec galaaz setup'
597
- system('bundle', 'exec', 'galaaz', 'setup') ||
598
- warn('galaaz add ledger: bundle exec galaaz setup returned non-zero; check gatekeeper')
599
- abort_unless(system('bin/rails', 'db:prepare'), 'rails db:prepare failed')
600
- abort_unless(system('bin/rails', 'db:migrate'), 'rails db:migrate failed')
601
- abort_unless(system({ 'SEED_PROFILE' => 'fast' }, 'bin/rails', 'db:seed'), 'rails db:seed failed')
626
+ unless ledger_bundle('exec', 'galaaz', 'setup')
627
+ warn('galaaz add ledger: bundle exec galaaz setup failed; trying PATH galaaz setup')
628
+ system('galaaz', 'setup') ||
629
+ warn('galaaz add ledger: galaaz setup returned non-zero; check gatekeeper')
630
+ end
631
+ abort_unless(ledger_bundle('exec', 'rails', 'db:prepare'), 'rails db:prepare failed')
632
+ abort_unless(ledger_bundle('exec', 'rails', 'db:migrate'), 'rails db:migrate failed')
633
+ abort_unless(
634
+ ledger_bundle_env({ 'SEED_PROFILE' => 'fast' }, 'exec', 'rails', 'db:seed'),
635
+ 'rails db:seed failed'
636
+ )
637
+ # builds/tailwind.css is gitignored — Propshaft needs a one-shot build for rails s
638
+ # (bin/dev runs tailwindcss:watch and would also create it).
639
+ puts 'galaaz add ledger: rails tailwindcss:build'
640
+ abort_unless(
641
+ ledger_bundle('exec', 'rails', 'tailwindcss:build'),
642
+ 'rails tailwindcss:build failed (tailwind.css missing for Propshaft)'
643
+ )
602
644
  end
603
645
 
604
646
  mark_profile!('ledger')
@@ -608,6 +650,39 @@ module Galaaz
608
650
  0
609
651
  end
610
652
 
653
+ # Run bundle under mise so .ruby-version / .tool-versions match Omarchy PATH ruby.
654
+ def ledger_bundle(*args)
655
+ if command_present?('mise')
656
+ system('mise', 'x', '--', 'bundle', *args)
657
+ else
658
+ system('bundle', *args)
659
+ end
660
+ end
661
+
662
+ def ledger_bundle_env(env, *args)
663
+ if command_present?('mise')
664
+ system(env, 'mise', 'x', '--', 'bundle', *args)
665
+ else
666
+ system(env, 'bundle', *args)
667
+ end
668
+ end
669
+
670
+ def ensure_ledger_bundler!
671
+ locked = nil
672
+ if File.file?('Gemfile.lock')
673
+ locked = File.read('Gemfile.lock')[/BUNDLED WITH\s+(\d+\.\d+(?:\.\d+)?)/, 1]
674
+ end
675
+ puts "galaaz add ledger: ensure bundler#{locked ? " #{locked}" : ''}"
676
+ if command_present?('mise')
677
+ cmd = ['mise', 'x', '--', 'gem', 'install', 'bundler', '--no-document']
678
+ cmd.insert(-2, '-v', locked) if locked
679
+ system(*cmd) || warn('galaaz add ledger: gem install bundler returned non-zero')
680
+ elsif locked
681
+ system('gem', 'install', 'bundler', '-v', locked, '--no-document') ||
682
+ warn('galaaz add ledger: gem install bundler returned non-zero')
683
+ end
684
+ end
685
+
611
686
  # Ledger repo may ship `gem "galaaz", path: "..."`. Standalone installs use RubyGems
612
687
  # (CRuby or JRuby), unpinned, so `bundle update galaaz` takes the newest published gem.
613
688
  def ensure_ledger_galaaz_gemfile!(gemfile)
@@ -772,6 +847,16 @@ module Galaaz
772
847
  dest = File.join(sty_dir, 'galaaz.sty')
773
848
  FileUtils.cp(src, dest)
774
849
  puts "galaaz sty: #{dest}"
850
+ header = File.join(root, 'sty', 'galaaz-header.png')
851
+ if File.file?(header)
852
+ FileUtils.cp(header, File.join(sty_dir, 'galaaz-header.png'))
853
+ puts "galaaz sty header: #{File.join(sty_dir, 'galaaz-header.png')}"
854
+ end
855
+ from_p3 = File.join(root, 'sty', 'galaaz-headers-from-p3.tex')
856
+ if File.file?(from_p3)
857
+ FileUtils.cp(from_p3, File.join(sty_dir, 'galaaz-headers-from-p3.tex'))
858
+ puts "galaaz sty headers: #{File.join(sty_dir, 'galaaz-headers-from-p3.tex')}"
859
+ end
775
860
  dest
776
861
  end
777
862
 
@@ -0,0 +1,27 @@
1
+ # Galaaz Omarchy menu icon font
2
+
3
+ Private TrueType font (`family: galaaz`) with one private-use glyph:
4
+
5
+ | Codepoint | Name | Role |
6
+ |-----------|------|------|
7
+ | `U+E900` | `galaaz` | Monochrome R + gem cutout for Install menu rows |
8
+
9
+ ## Sources
10
+
11
+ | File | Role |
12
+ |------|------|
13
+ | `galaaz-mark.svg` | Editable monochrome silhouette (straight segments) |
14
+ | `build_font.py` | Builds `../../script/omarchy/fonts/galaaz.ttf` (needs `fonttools`) |
15
+ | `../../script/omarchy/fonts/galaaz.ttf` | Shipped with the Omarchy overlay |
16
+
17
+ Rebuild after editing the SVG:
18
+
19
+ ```bash
20
+ python3 -m venv /tmp/galaaz-font-venv
21
+ /tmp/galaaz-font-venv/bin/pip install fonttools
22
+ /tmp/galaaz-font-venv/bin/python logos/icon-font/build_font.py
23
+ ```
24
+
25
+ `galaaz omarchy` installs the TTF to `~/.local/share/fonts/galaaz/` and the menu
26
+ uses `"iconFont": "galaaz"`. Restart the Omarchy shell after install so Qt
27
+ reloads fonts (`omarchy menu refresh` alone is not enough for a new family).
@@ -0,0 +1,130 @@
1
+ #!/usr/bin/env python3
2
+ """Build script/omarchy/fonts/galaaz.ttf from logos/icon-font/galaaz-mark.svg."""
3
+ from __future__ import annotations
4
+
5
+ import re
6
+ import sys
7
+ from pathlib import Path
8
+
9
+ from fontTools.fontBuilder import FontBuilder
10
+ from fontTools.misc.transform import Transform
11
+ from fontTools.pens.ttGlyphPen import TTGlyphPen
12
+ from fontTools.svgLib.path import SVGPath
13
+ from fontTools.ttLib import TTFont
14
+ from fontTools.ttLib.tables._g_l_y_f import Glyph as TTGlyph
15
+ from fontTools.ttLib.tables._g_l_y_f import GlyphCoordinates
16
+ from fontTools.ttLib.tables._g_l_y_f import flagOnCurve
17
+
18
+ ROOT = Path(__file__).resolve().parents[2]
19
+ SVG = ROOT / "logos" / "icon-font" / "galaaz-mark.svg"
20
+ OUT = ROOT / "script" / "omarchy" / "fonts" / "galaaz.ttf"
21
+ CODEPOINT = 0xE900
22
+
23
+
24
+ def extract_path_d(svg_text: str) -> str:
25
+ m = re.search(r'<path[^>]*\sd="([^"]+)"', svg_text, re.DOTALL)
26
+ if not m:
27
+ raise SystemExit("no <path d=...> in SVG")
28
+ return re.sub(r"\s+", " ", m.group(1)).strip()
29
+
30
+
31
+ def signed_area(pts) -> float:
32
+ a = 0.0
33
+ n = len(pts)
34
+ for i in range(n):
35
+ x1, y1 = pts[i]
36
+ x2, y2 = pts[(i + 1) % n]
37
+ a += x1 * y2 - x2 * y1
38
+ return 0.5 * a
39
+
40
+
41
+ def fix_hole_windings(glyph: TTGlyph) -> None:
42
+ """TrueType: outer CW (area < 0), holes CCW (area > 0)."""
43
+ if glyph.numberOfContours <= 0:
44
+ return
45
+ coords = list(glyph.coordinates)
46
+ ends = list(glyph.endPtsOfContours)
47
+ flags = list(glyph.flags)
48
+ start = 0
49
+ new_coords = []
50
+ new_flags = []
51
+ new_ends = []
52
+ for i, end in enumerate(ends):
53
+ pts = coords[start : end + 1]
54
+ fl = flags[start : end + 1]
55
+ area = signed_area(pts)
56
+ # First contour = outer; rest = holes (rails are positive fills — keep CW)
57
+ # Contours after first that are nested holes need opposite winding.
58
+ # Heuristic: second contour in our SVG is the gem hole; rails stay CW.
59
+ if i == 1 and area < 0:
60
+ pts = list(reversed(pts))
61
+ fl = list(reversed(fl))
62
+ new_coords.extend(pts)
63
+ new_flags.extend(fl)
64
+ new_ends.append(len(new_coords) - 1)
65
+ start = end + 1
66
+ glyph.coordinates = GlyphCoordinates(new_coords)
67
+ glyph.flags = new_flags
68
+ glyph.endPtsOfContours = new_ends
69
+ glyph.numberOfContours = len(new_ends)
70
+
71
+
72
+ def main() -> int:
73
+ d = extract_path_d(SVG.read_text(encoding="utf-8"))
74
+ transform = Transform(1, 0, 0, -1, 0, 1000)
75
+
76
+ pen = TTGlyphPen(glyphSet=None)
77
+ SVGPath.fromstring(
78
+ f'<path d="{d}" fill-rule="evenodd"/>', transform=transform
79
+ ).draw(pen)
80
+ glyph = pen.glyph()
81
+ fix_hole_windings(glyph)
82
+
83
+ fb = FontBuilder(1000, isTTF=True)
84
+ fb.setupGlyphOrder([".notdef", "galaaz"])
85
+ fb.setupCharacterMap({CODEPOINT: "galaaz"})
86
+ fb.setupGlyf({".notdef": TTGlyph(), "galaaz": glyph})
87
+ fb.setupHorizontalMetrics({".notdef": (600, 0), "galaaz": (1000, 0)})
88
+ fb.setupHorizontalHeader(ascent=1000, descent=0)
89
+ fb.setupOS2(
90
+ sTypoAscender=1000,
91
+ sTypoDescender=0,
92
+ sTypoLineGap=0,
93
+ usWinAscent=1000,
94
+ usWinDescent=0,
95
+ sxHeight=500,
96
+ sCapHeight=700,
97
+ )
98
+ fb.setupPost()
99
+ fb.setupNameTable(
100
+ {
101
+ "familyName": "galaaz",
102
+ "styleName": "Regular",
103
+ "uniqueFontIdentifier": "galaaz Regular",
104
+ "fullName": "galaaz Regular",
105
+ "psName": "galaaz-Regular",
106
+ "version": "Version 1.000",
107
+ "manufacturer": "Galaaz",
108
+ "description": "Monochrome Galaaz mark for Omarchy menu rows (U+E900).",
109
+ }
110
+ )
111
+ OUT.parent.mkdir(parents=True, exist_ok=True)
112
+ fb.save(OUT)
113
+
114
+ tt = TTFont(OUT)
115
+ assert tt["cmap"].getBestCmap().get(CODEPOINT) == "galaaz"
116
+ g = tt["glyf"]["galaaz"]
117
+ coords = list(g.coordinates)
118
+ ends = list(g.endPtsOfContours)
119
+ start = 0
120
+ for i, end in enumerate(ends):
121
+ pts = coords[start : end + 1]
122
+ a = signed_area(pts)
123
+ print(f" contour {i}: {'CW' if a < 0 else 'CCW'} area={a:.0f}")
124
+ start = end + 1
125
+ print(f"wrote {OUT} glyph U+{CODEPOINT:04X} family=galaaz")
126
+ return 0
127
+
128
+
129
+ if __name__ == "__main__":
130
+ sys.exit(main())
@@ -0,0 +1,34 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!--
3
+ Monochrome Galaaz mark for the Omarchy menu icon font (menu-size silhouette).
4
+ Solid R with left top spur + diamond gem cutout (minimum-size spirit).
5
+ Straight segments only. Optical box ~150..880 in a 1000 viewBox.
6
+ -->
7
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000" fill="#000">
8
+ <path fill-rule="evenodd" d="
9
+ M 160 150
10
+ H 500
11
+ L 620 150
12
+ L 700 230
13
+ L 720 340
14
+ L 700 450
15
+ L 620 520
16
+ L 530 545
17
+ L 760 880
18
+ H 580
19
+ L 400 560
20
+ H 320
21
+ V 880
22
+ H 200
23
+ V 280
24
+ H 160
25
+ V 150
26
+ Z
27
+
28
+ M 460 280
29
+ L 380 350
30
+ L 460 420
31
+ L 540 350
32
+ Z
33
+ "/>
34
+ </svg>
@@ -31,6 +31,10 @@ Then Super+Space → Install → Development → **Galaaz**.
31
31
  | `debug-galaaz.sh` | Snapshot doctor/PATH/gem/bridge |
32
32
  | `remove-galaaz.sh` | Uninstall gem + marked blogs; leave R |
33
33
  | `omarchy-menu.jsonc` | Menu overlay submenu under Install → Development |
34
+ | `fonts/galaaz.ttf` | Monochrome brand mark (`iconFont: galaaz`, U+E900) |
35
+
36
+ Menu rows use the Galaaz icon font (not the Ruby-on-Rails Nerd Font gem). Source SVG
37
+ and rebuild script live under `logos/icon-font/`.
34
38
 
35
39
  After core, the menu includes **Guide (what's next)**, **Documentation (website)**, and **GitHub repository**. After Knit, **Knit demo (oh_my)** runs an example blog.
36
40
 
@@ -38,7 +42,7 @@ Docs: https://rbotafogo.github.io/galaaz/ · https://github.com/rbotafogo/galaaz
38
42
 
39
43
  Heavy CRAN installs (`R.install_and_loads`) and long R (`R::Job.eval` / `script`) run in a
40
44
  child `Rscript` so the bridge stays free — see **Background R jobs (`R::Job`)** in the
41
- README / manual (gem **2.1.7+**).
45
+ README / manual (gem **2.1.8+**).
42
46
 
43
47
  ## Manual copy (legacy)
44
48
 
@@ -53,8 +57,11 @@ cp galaaz-guide.sh ~/.local/bin/omarchy-galaaz-guide
53
57
  cp galaaz-gknit.sh ~/.local/bin/omarchy-galaaz-gknit
54
58
  cp debug-galaaz.sh ~/.local/bin/omarchy-galaaz-debug
55
59
  cp omarchy-menu.jsonc ~/.config/omarchy/extensions/omarchy-menu.jsonc
60
+ mkdir -p ~/.local/share/fonts/galaaz
61
+ cp fonts/galaaz.ttf ~/.local/share/fonts/galaaz/
62
+ fc-cache -f ~/.local/share/fonts/galaaz
56
63
  chmod +x ~/.local/bin/omarchy-*
57
- ```
64
+ # Restart the Omarchy shell so the galaaz font is visible in the menu.```
58
65
 
59
66
  ## TryOmarchy steps
60
67
 
Binary file
@@ -65,7 +65,7 @@ Other add-ons
65
65
  Check: galaaz doctor
66
66
  Menu: Super+Space → Install → Development → Galaaz
67
67
 
68
- Heavy CRAN installs / long R (gem 2.1.7+): R::Job keeps the bridge free.
68
+ Heavy CRAN installs / long R (gem 2.1.8+): R::Job keeps the bridge free.
69
69
  See README → “Background R jobs (R::Job)” (${DOCS_README})
70
70
 
71
71
  EOF
@@ -271,10 +271,17 @@ fi
271
271
  "${HOME}/.local/bin/galaaz" doctor 2>&1 | tee -a "${LOG}" || true
272
272
 
273
273
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
274
- mkdir -p "${HOME}/.config/omarchy/extensions" "${HOME}/.local/bin"
274
+ mkdir -p "${HOME}/.config/omarchy/extensions" "${HOME}/.local/bin" "${HOME}/.local/share/fonts/galaaz"
275
275
  if [[ -f "${SCRIPT_DIR}/omarchy-menu.jsonc" ]]; then
276
276
  cp "${SCRIPT_DIR}/omarchy-menu.jsonc" "${HOME}/.config/omarchy/extensions/omarchy-menu.jsonc"
277
277
  fi
278
+ if [[ -f "${SCRIPT_DIR}/fonts/galaaz.ttf" ]]; then
279
+ cp "${SCRIPT_DIR}/fonts/galaaz.ttf" "${HOME}/.local/share/fonts/galaaz/galaaz.ttf"
280
+ if command -v fc-cache >/dev/null 2>&1; then
281
+ fc-cache -f "${HOME}/.local/share/fonts/galaaz" >/dev/null 2>&1 || true
282
+ fi
283
+ log "menu font: ${HOME}/.local/share/fonts/galaaz/galaaz.ttf"
284
+ fi
278
285
  cp "${BASH_SOURCE[0]}" "${HOME}/.local/bin/omarchy-install-galaaz"
279
286
  chmod +x "${HOME}/.local/bin/omarchy-install-galaaz"
280
287
  if [[ -f "${SCRIPT_DIR}/remove-galaaz.sh" ]]; then
@@ -4,14 +4,19 @@
4
4
  //
5
5
  // Use ~/.local/bin/galaaz (installer wrapper). Do not quote the whole
6
6
  // "galaaz add …" as one word — omarchy-launch-tui then does nothing useful.
7
+ //
8
+ // Brand mark: private-use U+E900 in family "galaaz"
9
+ // (script/omarchy/fonts/galaaz.ttf → ~/.local/share/fonts/galaaz/).
7
10
 
8
11
  "install.development.galaaz": {
9
- "icon": "󰫏",
12
+ "icon": "",
13
+ "iconFont": "galaaz",
10
14
  "label": "Galaaz",
11
15
  "description": "R on Rails"
12
16
  },
13
17
  "install.development.galaaz.core": {
14
- "icon": "󰫏",
18
+ "icon": "",
19
+ "iconFont": "galaaz",
15
20
  "label": "Galaaz (core)",
16
21
  "description": "gem + setup + blogs (not just gem install)",
17
22
  "action": "omarchy-launch-tui omarchy-install-galaaz",
@@ -39,7 +44,8 @@
39
44
  "when": "test -f ~/.config/galaaz/profiles/core"
40
45
  },
41
46
  "install.development.galaaz.knit": {
42
- "icon": "󰫏",
47
+ "icon": "",
48
+ "iconFont": "galaaz",
43
49
  "label": "Knit (HTML blogs)",
44
50
  "description": "pandoc + knitr/rmarkdown",
45
51
  "action": "omarchy-launch-tui omarchy-galaaz-add knit",
@@ -53,38 +59,44 @@
53
59
  "when": "test -f ~/.config/galaaz/profiles/knit"
54
60
  },
55
61
  "install.development.galaaz.arrow": {
56
- "icon": "󰫏",
62
+ "icon": "",
63
+ "iconFont": "galaaz",
57
64
  "label": "Arrow",
58
65
  "action": "omarchy-launch-tui omarchy-galaaz-add arrow",
59
66
  "disabled": "test -f ~/.config/galaaz/profiles/arrow"
60
67
  },
61
68
  "install.development.galaaz.tex": {
62
- "icon": "󰫏",
69
+ "icon": "",
70
+ "iconFont": "galaaz",
63
71
  "label": "TeX (PDF blogs)",
64
72
  "action": "omarchy-launch-tui omarchy-galaaz-add tex",
65
73
  "disabled": "test -f ~/.config/galaaz/profiles/tex"
66
74
  },
67
75
  "install.development.galaaz.bio": {
68
- "icon": "󰫏",
76
+ "icon": "",
77
+ "iconFont": "galaaz",
69
78
  "label": "Bioconductor (DESeq2)",
70
79
  "action": "omarchy-launch-tui omarchy-galaaz-add bio",
71
80
  "disabled": "test -f ~/.config/galaaz/profiles/bio"
72
81
  },
73
82
  "install.development.galaaz.examples": {
74
- "icon": "󰫏",
83
+ "icon": "",
84
+ "iconFont": "galaaz",
75
85
  "label": "Examples",
76
86
  "action": "omarchy-launch-tui omarchy-galaaz-add examples",
77
87
  "disabled": "test -f ~/.config/galaaz/profiles/examples"
78
88
  },
79
89
  "install.development.galaaz.ledger": {
80
- "icon": "󰫏",
90
+ "icon": "",
91
+ "iconFont": "galaaz",
81
92
  "label": "Ledger (R-on-Rails demo)",
82
93
  "description": "Clone app, seed, bin/dev",
83
94
  "action": "omarchy-launch-tui omarchy-galaaz-add ledger",
84
95
  "disabled": "test -f ~/.config/galaaz/profiles/ledger"
85
96
  },
86
97
  "remove.development.galaaz": {
87
- "icon": "󰫏",
98
+ "icon": "",
99
+ "iconFont": "galaaz",
88
100
  "label": "Galaaz",
89
101
  "description": "Core gem (add-on R packages stay)",
90
102
  "action": "omarchy-launch-tui omarchy-remove-galaaz"
Binary file
@@ -0,0 +1,4 @@
1
+ % No header on title/TOC (p.1) or splash logo page (p.2);
2
+ % logo + page number + section title from page 3 onward.
3
+ % Load after galaaz.sty.
4
+ \renewcommand{\galaazheaderfrompage}{3}