~arcade/nebula

ref: 9ec229907222048f1f22bcad3a7bf0c24c804277 nebula/software/helix/src/helix.cr -rw-r--r-- 5.5 KiB
9ec22990 — Arcade Wise Thanks Sophie 5 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
require "./front_matter"
require "./render"
require "option_parser"
require "html-minifier"
require "file_utils"
require "crinja"
require "markd"
require "yaml"

# The main monis engine
module Helix
  VERSION = "0.6.0"

  if Dir.exists? "out"
    puts "Cleaning old generation"
    FileUtils.rm_rf "./out"
  end

  # if this flag is true, then create the directory structure, as well as a basic theme file.
  _init = false

  # # File structure for sites
  # `/content`: Anything here gets rendered
  # `/static`: These files just get copied over to `/out/static`
  # `/theme`: Currently only `index.html.js` gets used in this, but this is the Jinja2 template for the website.
  # `/theme/static`: These are static files for a theme
  # `/out`: This is the output of the generator once it has been run !!DONT STORE ANYTHING IMPORTANT HERE IT GETS WIPED ON EACH RUN!!

  OptionParser.parse do |parser|
    parser.banner = "helix CLI"
    parser.on "init", "create the basic folder structure." do
      _init = true
    end
  end

  if _init
    FileUtils.mkdir_p ["content", "theme", "theme/static", "static"]
    File.write "theme/index.html", "{{content}}"
    # quit the program
    exit
  end

  # ---------------- Jinja template engine setup ----------------
  env = Crinja.new
  env.loader = Crinja::Loader::FileSystemLoader.new("theme/")

  # TODO: LOAD FROM CUSTOM DIR

  rawfiles = Dir.glob "content/**/*" # Files that are under content
  files = [] of String               # An empty Array of filenames without directories

  rawfiles.each do |filename|
    if filename.ends_with? ".md"
      files.push filename # Add the file if it of a type we support
    end
  end

  if File.exists? "config.yml"
    # Read config yaml from the `config.yml` file
    configfiledata = {} of String => String
    data = YAML.parse File.new("config.yml").gets_to_end

    data.as_h.each do |item|
      configfiledata[item[0].as_s] = item[1].as_s
    end
  else
    STDERR.puts "No config.yml detected in the current directory!"
    exit 1
  end

  content = "Nothing yet!"
  template = env.get_template "index.html"

  # set up renderer
  options = Markd::Options.new

  files.each do |filename|
    spawn do # Do this conncurently with other files! Performance!
      puts "Generating HTML for " + filename

      FrontMatter.open(filename) { |front_matter, content_io|
        data = YAML.parse front_matter
        permalink = data["permalink"].as_s

        rawmd = content_io.gets_to_end
        document = Markd::Parser.parse(rawmd, options)
        renderer = NebulaRenderEngine.new(options)
        content = renderer.render document

        # This allows for custom configs for themes.
        frontdata = {} of String => String

        data.as_h.each do |item|
          frontdata[item[0].as_s] = item[1].as_s
          # p! configdata
        end

        # Do something with the front matter and content.
        # Parse the front matter as YAML, JSON or something else?

        builtin = {
          "path" => filename.lstrip("content/"),
        }

        # Render the template HTML with our data
        basicconfig = {"content" => content, "config" => configfiledata, "builtin" => builtin}
        # p! basicconfig.merge(configdata)
        rendered_page = template.render(basicconfig.merge(frontdata))

        # write out rendered_page

        # create directories for page
        subs = permalink.split("/")
        count = 0

        subs.each do |dirname|
          if dirname == subs[-1]
          else
            recreateddir = "out" + subs[0..count].join('/')
            if Dir.exists? recreateddir
            else
              FileUtils.mkdir_p recreateddir
            end
          end
          count = count + 1
        end

        if Dir.exists? "out"
          File.write "out" + permalink + ".html", rendered_page
        else
          FileUtils.mkdir_p "out"
          File.write "out" + permalink + ".html", rendered_page
        end
        puts "Generated " + permalink + ".html"
      }
    end
  end

  puts "HTML Generation finished!"

  puts "Tranfering static content"
  if Dir.exists? "theme/static"
    if Dir.exists? "out/static"
    else
      FileUtils.mkdir_p "out/static"
    end

    # css minification
    css_files = Dir.glob "theme/static/*.css"
    css_files.each do |filename|
      spawn do
        File.write "out/static/" + Path[filename].basename, HtmlMinifier.minify!(File.read(filename))
      end
    end

    # JavaScript owo
    js_files = Dir.glob "theme/static/*.js"
    js_files.each do |filename|
      spawn do
        File.write "out/static/" + Path[filename].basename, File.read(filename)
      end
    end

    # Process image files into dithered files
    img_files = Dir.glob ["theme/static/*.jpg", "theme/static/*.png", "theme/static/*.gif", "theme/static/*.jpeg", "content/static/*.jpg", "content/static/*.png", "content/static/*.gif", "content/static/*.jpeg"]
    img_files.each do |filename|
      # create a new .png filename
      output_filename = "out/static/" + Path[filename].stem.to_s + ".png"
      # generate a didder command to fix images
      command = "didder -i " + filename + " -o " + output_filename + " --palette 'black gray white' --recolor '" + configfiledata["recolor"] + "' edm --serpentine FloydSteinberg"
      # puts command
      system command
    end

    # Static files that need no processing
    staticFiles = Dir.glob ["static/*.txt", "theme/static/*.txt", "content/static/nomod/*"]
    staticFiles.each do |filename|
      spawn do # ayyyyee
        FileUtils.cp filename, "out/static/"
      end
    end
  end
  puts "Static content moved"
end