Almirah 0.4.4 → 0.4.6

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.
@@ -94,9 +94,10 @@ class SourceFile < PersistentDocument
94
94
  file.puts s.gsub! '{{DOCUMENT_TITLE}}', @title
95
95
  elsif s.include?('{{STYLES_AND_SCRIPTS}}')
96
96
  file.puts "<link rel=\"stylesheet\" href=\"#{css_path}\">"
97
+ file.puts font_size_style if BaseDocument.font_size
97
98
  file.puts "<script src=\"#{js_path}\"></script>"
98
99
  elsif s.include?('{{HOME_BUTTON}}')
99
- file.puts "<a id=\"index_menu_item\" href=\"#{index_path}\"><span><i class=\"fa fa-info\" aria-hidden=\"true\"></i></span>&nbsp;Index</a>"
100
+ file.puts "<a id=\"index_menu_item\" href=\"#{index_path}\"><span><i class=\"fa fa-home\" aria-hidden=\"true\"></i></span>&nbsp;Documents</a>"
100
101
  elsif s.include?('{{GEM_VERSION}}')
101
102
  file.puts "(#{Gem.loaded_specs['Almirah'].version.version})"
102
103
  else
@@ -4,7 +4,7 @@ class ProjectData
4
4
  attr_reader :specifications, :protocols, :traceability_matrices, :coverage_matrices, :source_files,
5
5
  :specifications_dictionary, :covered_specifications_dictionary, :implemented_specifications_dictionary,
6
6
  :implementation_matrices, :decisions, :decision_groups, :risk_records, :risk_registries,
7
- :risk_registry_prefaces, :work_items, :link_registry
7
+ :risk_registry_prefaces, :link_registry
8
8
 
9
9
  def initialize
10
10
  @specifications = []
@@ -25,9 +25,6 @@ class ProjectData
25
25
  # the registry (first-level risks/ folder) name. A registry without an
26
26
  # overview.md has no entry; its page simply starts at the register table.
27
27
  @risk_registry_prefaces = {}
28
- # Every Scope-row WorkItem across all decision records, keyed by its canonical
29
- # "<record>.<step>.<activity>" id (see ADR-194), populated by link_work_items.
30
- @work_items = {}
31
28
 
32
29
  @specifications_dictionary = {}
33
30
  @covered_specifications_dictionary = {}
@@ -2,7 +2,6 @@
2
2
 
3
3
  require 'fileutils'
4
4
  require_relative 'doc_fabric'
5
- require_relative 'doc_items/work_item'
6
5
  require_relative 'navigation_pane'
7
6
  require_relative 'doc_types/traceability'
8
7
  require_relative 'doc_types/index'
@@ -19,6 +18,7 @@ class Project
19
18
  def initialize(configuration)
20
19
  @configuration = configuration
21
20
  @project_data = ProjectData.new
21
+ BaseDocument.font_size = @configuration.get_font_size
22
22
 
23
23
  @index = nil
24
24
  @project = self
@@ -53,7 +53,6 @@ class Project
53
53
  link_all_risks
54
54
  check_wrong_specification_referenced
55
55
  build_link_registry
56
- link_work_items
57
56
  create_index
58
57
  render_all_specifications(@project_data.specifications)
59
58
  render_all_specifications(@project_data.traceability_matrices)
@@ -61,8 +60,8 @@ class Project
61
60
  render_all_protocols
62
61
  render_all_source_files
63
62
  render_all_specifications(@project_data.implementation_matrices) # intentionally after source file rendering
63
+ copy_decision_and_risk_images
64
64
  render_decisions_overview
65
- render_critical_chain_page
66
65
  render_all_decisions
67
66
  render_all_risk_records
68
67
  render_risk_registry_pages
@@ -70,7 +69,6 @@ class Project
70
69
  render_index
71
70
  create_search_data
72
71
  report_broken_links
73
- report_kit_violations
74
72
  report_rendered
75
73
  end
76
74
 
@@ -87,7 +85,6 @@ class Project
87
85
  link_all_risks
88
86
  check_wrong_specification_referenced
89
87
  build_link_registry
90
- link_work_items
91
88
  create_index
92
89
  render_all_specifications(@project_data.specifications)
93
90
  render_all_specifications(@project_data.traceability_matrices)
@@ -95,8 +92,8 @@ class Project
95
92
  render_all_protocols
96
93
  render_all_source_files
97
94
  render_all_specifications(@project_data.implementation_matrices) # intentionally after source file rendering
95
+ copy_decision_and_risk_images
98
96
  render_decisions_overview
99
- render_critical_chain_page
100
97
  render_all_decisions
101
98
  render_all_risk_records
102
99
  render_risk_registry_pages
@@ -104,7 +101,6 @@ class Project
104
101
  render_index
105
102
  create_search_data
106
103
  report_broken_links
107
- report_kit_violations
108
104
  report_rendered
109
105
  end
110
106
 
@@ -124,111 +120,6 @@ class Project
124
120
  broken.each { |b| puts ConsoleReporter.warn_detail(" #{b[:document] || '?'}: #{b[:target]}") }
125
121
  end
126
122
 
127
- # Builds the per-row WorkItem dependency network (ADR-194): registers every
128
- # Scope-row work item, fills the intra-record step-order edges, then resolves
129
- # each Depends On reference globally (LinkRegistry) to the activity-type-aligned
130
- # work item of the target record, tagging each cross-record edge in-group or
131
- # cross-group against the decision_groups boundary (ADR-197). Unresolved
132
- # references are collected for report_kit_violations. Runs after
133
- # build_link_registry (so every record resolves) and before rendering (so the
134
- # overview Kit column is ready).
135
- def link_work_items
136
- @kit_unresolved = []
137
- @project_data.decisions.each do |d|
138
- d.scope_work_items.each { |wi| @project_data.work_items[wi.id] = wi }
139
- end
140
- link_intra_record_steps
141
- link_cross_record_dependencies
142
- end
143
-
144
- # Each row's lower-numbered same-record steps are its predecessors; equal step
145
- # numbers are concurrent (no edge). These edges are in-group by definition.
146
- def link_intra_record_steps
147
- @project_data.decisions.each do |d|
148
- items = d.scope_work_items
149
- items.each do |wi|
150
- items.each do |other|
151
- next if other.equal?(wi) || other.step >= wi.step
152
-
153
- wi.add_predecessor(other, cross_group: false)
154
- other.add_successor(wi)
155
- end
156
- end
157
- end
158
- end
159
-
160
- def link_cross_record_dependencies
161
- @project_data.decisions.each do |d|
162
- d.scope_work_items.each do |wi|
163
- wi.depends_on_refs.each { |ref| link_dependency(d, wi, ref) }
164
- end
165
- end
166
- end
167
-
168
- def link_dependency(record, work_item, ref)
169
- target = @project_data.link_registry.find_by_id(ref)
170
- unless target.is_a?(Decision)
171
- @kit_unresolved << { record: record.id, target: ref }
172
- return
173
- end
174
- prereq = aligned_work_item(target, work_item.activity)
175
- return if prereq.nil? || prereq.equal?(work_item)
176
-
177
- cross = decision_group_name(record) != decision_group_name(target)
178
- work_item.add_predecessor(prereq, cross_group: cross)
179
- prereq.add_successor(work_item)
180
- anchor = target.scope_table&.step_column? ? prereq.row_anchor : nil
181
- work_item.add_resolved_dependency(ref, target, anchor, prereq.id)
182
- end
183
-
184
- # The target record's work item whose activity (Item) matches `activity`,
185
- # falling back to the nearest earlier activity by canonical phase order, then
186
- # (when the target has only later activities) to its earliest row. nil only
187
- # when the target has no Scope rows.
188
- def aligned_work_item(target, activity)
189
- items = target.scope_work_items
190
- return nil if items.empty?
191
-
192
- exact = items.select { |t| t.activity == activity }.min_by(&:step)
193
- return exact if exact
194
-
195
- rank = WorkItem::ACTIVITY_ORDER.index(activity) || WorkItem::ACTIVITY_ORDER.length
196
- earlier = items.select { |t| t.activity_rank <= rank }
197
- return items.min_by { |t| [t.activity_rank, t.step] } if earlier.empty?
198
-
199
- earlier.min_by { |t| [-t.activity_rank, t.step] }
200
- end
201
-
202
- # The planning-group name (first-level decisions/ folder) a record belongs to,
203
- # read from the decision_groups collection (ADR-197).
204
- def decision_group_name(doc)
205
- group = @project_data.decision_groups.find { |g| g.values.first.include?(doc) }
206
- group&.keys&.first
207
- end
208
-
209
- # Reports the two kit gates and unresolved Depends On references (ADR-194), all
210
- # as non-failing console warnings alongside report_broken_links.
211
- def report_kit_violations
212
- @kit_unresolved ||= []
213
- phase = @project_data.work_items.each_value.select(&:phase_order_violation?)
214
- cross = @project_data.work_items.each_value.select(&:cross_record_violation?)
215
- total = phase.length + cross.length + @kit_unresolved.length
216
- return if total.zero?
217
-
218
- ConsoleReporter.warn('kit violations', total)
219
- phase.each do |wi|
220
- blocking = wi.intra_record_predecessors.reject(&:done?).map(&:id).join(', ')
221
- puts ConsoleReporter.warn_detail(" phase order: #{wi.id} started before #{blocking}")
222
- end
223
- cross.each do |wi|
224
- blocking = wi.cross_record_predecessors.reject(&:done?).map(&:id).join(', ')
225
- puts ConsoleReporter.warn_detail(" not kitted: #{wi.id} needs #{blocking}")
226
- end
227
- @kit_unresolved.each do |u|
228
- puts ConsoleReporter.warn_detail(" unresolved Depends On: #{u[:record]} -> #{u[:target]}")
229
- end
230
- end
231
-
232
123
  # Assigns each document its generated output path (relative to the build root)
233
124
  # and registers it for cross-document link resolution (ADR-186). Runs after all
234
125
  # documents are parsed and before any rendering, so link targets are known.
@@ -585,6 +476,25 @@ class Project
585
476
  end
586
477
  end
587
478
 
479
+ # Every folder named img under decisions/ and risks/ is copied to the same
480
+ # relative location under build/ (ADR-227, SRS-176), so relative image
481
+ # references in decision records, risk records, and registry prefaces
482
+ # resolve in the rendered HTML. Folder-based rather than doc-id-based like
483
+ # the specification and protocol copies, because these records share their
484
+ # release and registry folders.
485
+ def copy_decision_and_risk_images
486
+ root = @configuration.project_root_directory
487
+ %w[decisions risks].each do |subroot|
488
+ Dir.glob("#{root}/#{subroot}/**/img").each do |src|
489
+ next unless File.directory?(src)
490
+
491
+ dst = "#{root}/build/#{src.sub("#{root}/", '')}"
492
+ FileUtils.mkdir_p(File.dirname(dst))
493
+ FileUtils.copy_entry(src, dst)
494
+ end
495
+ end
496
+ end
497
+
588
498
  def render_all_source_files
589
499
  path = @configuration.project_root_directory
590
500
  FileUtils.mkdir_p("#{path}/build/source_files")
@@ -611,16 +521,6 @@ class Project
611
521
  doc.to_html("#{path}/build/decisions/")
612
522
  end
613
523
 
614
- def render_critical_chain_page
615
- return if @project_data.decisions.empty?
616
-
617
- path = @configuration.project_root_directory
618
- FileUtils.mkdir_p("#{path}/build/decisions")
619
-
620
- doc = DocFabric.create_critical_chain_page(@project)
621
- doc.to_html("#{path}/build/decisions/")
622
- end
623
-
624
524
  def render_all_decisions
625
525
  return if @project_data.decisions.empty?
626
526
 
@@ -1,11 +1,6 @@
1
1
  require 'yaml'
2
- require 'date'
3
2
 
4
3
  class ProjectConfiguration
5
- DEFAULT_WIP_LIMIT = 2
6
- DEFAULT_BUFFER_RATIO = 0.5
7
- DEFAULT_HOURS_PER_DAY = 8
8
-
9
4
  attr_accessor :project_root_directory, :parameters
10
5
 
11
6
  def initialize(path)
@@ -34,76 +29,11 @@ class ProjectConfiguration
34
29
  []
35
30
  end
36
31
 
37
- def get_wip_limit
38
- return DEFAULT_WIP_LIMIT unless @parameters.is_a?(Hash)
39
-
40
- planning = @parameters['planning']
41
- return DEFAULT_WIP_LIMIT unless planning.is_a?(Hash)
42
-
43
- value = planning['wip_limit']
44
- return DEFAULT_WIP_LIMIT unless value.is_a?(Integer) && value.positive?
45
-
46
- value
47
- end
48
-
49
- # The CCPM project-buffer ratio (ADR-195): a fraction in (0, 1] cutting the
50
- # aggregated chain safety. Absent or out-of-range falls back to the 0.5 default.
51
- def get_buffer_ratio
52
- return DEFAULT_BUFFER_RATIO unless @parameters.is_a?(Hash)
53
-
54
- planning = @parameters['planning']
55
- return DEFAULT_BUFFER_RATIO unless planning.is_a?(Hash)
56
-
57
- value = planning['buffer_ratio']
58
- return DEFAULT_BUFFER_RATIO unless value.is_a?(Numeric) && value.positive? && value <= 1
59
-
60
- value
61
- end
62
-
63
- # The calendar anchor for working day 1 (ADR-205), a Date parsed from a
64
- # DD-MM-YYYY planning.start_date. Absent or unparseable falls back to today,
65
- # so an unconfigured project still renders (a moving anchor).
66
- def get_start_date
67
- date = parse_planning_date(planning_value('start_date'))
68
- date || Date.today
69
- end
70
-
71
- # Per-group planning start dates (ADR-211): a map from a decision group's
72
- # first-level folder name (under decisions/) to its start Date, read from
73
- # planning.groups as DD-MM-YYYY entries. Non-string or unparseable values are
74
- # dropped; empty when unset. A group absent from the map sequences after the
75
- # previous group rather than carrying a declared start.
76
- def get_group_start_dates
77
- value = planning_value('groups')
78
- return {} unless value.is_a?(Hash)
79
-
80
- value.each_with_object({}) do |(name, raw), acc|
81
- date = parse_planning_date(raw)
82
- acc[name.to_s] = date if date
83
- end
84
- end
85
-
86
- # The non-working holiday dates (ADR-205) from planning.holidays, each a
87
- # DD-MM-YYYY entry; unparseable entries are dropped. Empty when unset.
88
- def get_holidays
89
- value = planning_value('holidays')
90
- return [] unless value.is_a?(Array)
91
-
92
- value.filter_map { |entry| parse_planning_date(entry) }
93
- end
94
-
95
- # Working hours per day (ADR-196): converts logged effort hours into the
96
- # working-day unit the estimates use. Absent or non-positive falls back to 8.
97
- def get_hours_per_day
98
- return DEFAULT_HOURS_PER_DAY unless @parameters.is_a?(Hash)
99
-
100
- planning = @parameters['planning']
101
- return DEFAULT_HOURS_PER_DAY unless planning.is_a?(Hash)
102
-
103
- value = planning['hours_per_day']
104
- return DEFAULT_HOURS_PER_DAY unless value.is_a?(Numeric) && value.positive?
105
-
106
- value
32
+ # The optional base text size in pixels (ADR-224), from the top-level
33
+ # font_size: number. nil when absent or not a positive number.
34
+ def get_font_size
35
+ value = @parameters.is_a?(Hash) ? @parameters['font_size'] : nil
36
+ value.is_a?(Numeric) && value.positive? ? value : nil
107
37
  end
108
38
 
109
39
  # The ordered register-column list for a risk registry folder (ADR-216),
@@ -164,26 +94,4 @@ class ProjectConfiguration
164
94
  def numeric_threshold(value)
165
95
  value.is_a?(Numeric) ? value : nil
166
96
  end
167
-
168
- # A value under the planning: key, or nil when planning is absent.
169
- def planning_value(key)
170
- return nil unless @parameters.is_a?(Hash)
171
-
172
- planning = @parameters['planning']
173
- planning.is_a?(Hash) ? planning[key] : nil
174
- end
175
-
176
- # Parse a planning date that may already be a Date (YAML ISO form) or a
177
- # DD-MM-YYYY string; nil when neither.
178
- def parse_planning_date(value)
179
- return value if value.is_a?(Date)
180
- return nil unless value.is_a?(String)
181
-
182
- match = /\A(\d{2})-(\d{2})-(\d{4})\z/.match(value.strip)
183
- return nil unless match
184
-
185
- Date.new(match[3].to_i, match[2].to_i, match[1].to_i)
186
- rescue ArgumentError
187
- nil
188
- end
189
97
  end
@@ -5,7 +5,10 @@ html {
5
5
  }
6
6
  body {
7
7
  font-family: Verdana, sans-serif;
8
- font-size: 12px;
8
+ /* Base text size, overridable per project via font_size in project.yml
9
+ (ADR-224). Headings, top menu and footer are pinned in px below so the
10
+ setting scales only the reading text and the navigation pane. */
11
+ font-size: var(--almirah-font-size, 12px);
9
12
  color: #333;
10
13
  margin: 0;
11
14
  padding: 0;
@@ -30,24 +33,24 @@ body {
30
33
  margin: 0 0 10px 0;
31
34
  }
32
35
  h1 {
33
- font-size: 2em;
36
+ font-size: 24px;
34
37
  }
35
38
  h2 {
36
- font-size: 1.8em;
39
+ font-size: 21.6px;
37
40
  }
38
41
  h3 {
39
- font-size: 1.5em;
42
+ font-size: 18px;
40
43
  }
41
44
  h4 {
42
- font-size: 1.2em;
45
+ font-size: 14.4px;
43
46
  border: none;
44
47
  font-weight: bold;
45
48
  }
46
49
  h5 {
47
- font-size: 1em;
50
+ font-size: 12px;
48
51
  }
49
52
  h6 {
50
- font-size: 1em; color: #8e8e8e;
53
+ font-size: 12px; color: #8e8e8e;
51
54
  }
52
55
  a.heading_anchor {
53
56
  display: none;
@@ -147,163 +150,6 @@ table.controlled td.item_text{
147
150
  max-width: 100%;
148
151
  max-height: 300px;
149
152
  }
150
- .workitem_gantt {
151
- --gantt-owner-width: 120px;
152
- --gantt-day-width: 26px;
153
- --gantt-month-h: 18px;
154
- overflow: auto;
155
- max-height: 420px;
156
- margin-bottom: 16px;
157
- border: 1px solid #e1e4e8;
158
- }
159
- .workitem_gantt .gantt_grid {
160
- display: grid;
161
- gap: 0;
162
- width: max-content;
163
- padding: 4px;
164
- }
165
- .workitem_gantt .gantt_corner,
166
- .workitem_gantt .gantt_owner,
167
- .workitem_gantt .gantt_owner_tracking,
168
- .workitem_gantt .gantt_band_corner,
169
- .workitem_gantt .gantt_buffer {
170
- position: sticky;
171
- left: 0;
172
- background: #fff;
173
- padding: 2px 8px;
174
- font-weight: 600;
175
- white-space: nowrap;
176
- border-right: 1px solid #e1e4e8;
177
- z-index: 2;
178
- }
179
- .workitem_gantt .gantt_corner {
180
- top: 0;
181
- border-bottom: 1px solid #bbb;
182
- z-index: 3;
183
- }
184
- .workitem_gantt .gantt_month_head {
185
- position: sticky;
186
- top: 0;
187
- background: #fff;
188
- text-align: center;
189
- font-size: 11px;
190
- font-weight: 600;
191
- color: #57606a;
192
- border-bottom: 1px solid #e1e4e8;
193
- border-left: 1px solid #d0d7de;
194
- white-space: nowrap;
195
- overflow: hidden;
196
- z-index: 1;
197
- }
198
- .workitem_gantt .gantt_day_head {
199
- position: sticky;
200
- top: var(--gantt-month-h);
201
- background: #fff;
202
- text-align: center;
203
- font-size: 11px;
204
- color: #57606a;
205
- border-bottom: 1px solid #bbb;
206
- z-index: 1;
207
- }
208
- /* Weekday-holiday highlight in the Chart.js palette red (ADR-205 amendment):
209
- the column carries the buffer bar's diagonal stripe texture, in red; the
210
- header stays a solid tint so the day number reads. */
211
- .workitem_gantt .gantt_day_head.gantt_nonworking { background: rgba(255, 99, 132, 0.22); color: #b23a52; }
212
- .workitem_gantt .gantt_day_head.gantt_friday { background: rgb(225, 241, 250); }
213
- .workitem_gantt .gantt_nonworking_col {
214
- background: repeating-linear-gradient(45deg,
215
- rgba(255, 99, 132, 0.20), rgba(255, 99, 132, 0.20) 5px,
216
- rgba(255, 99, 132, 0.07) 5px, rgba(255, 99, 132, 0.07) 10px);
217
- }
218
- .workitem_gantt .gantt_friday_col { background: rgb(225, 241, 250); }
219
- .workitem_gantt .gantt_bar,
220
- .workitem_gantt .gantt_track_bar {
221
- font-size: 11px;
222
- line-height: 1.5;
223
- margin: 1px;
224
- padding: 1px 5px;
225
- border-radius: 3px;
226
- overflow: hidden;
227
- white-space: nowrap;
228
- text-overflow: ellipsis;
229
- color: #fff;
230
- cursor: default;
231
- }
232
- .workitem_gantt .gantt_todo { background: #9aa5b1; }
233
- .workitem_gantt .gantt_inprogress { background: #ffffdd; color: #333; box-shadow: inset 0 0 0 1px #bbb; }
234
- .workitem_gantt .gantt_done { background: #cfc; color: #57606a; box-shadow: inset 0 0 0 1px #e1e4e8; }
235
- .workitem_gantt .gantt_blocked { box-shadow: inset 0 0 0 1px #bbb; }
236
- .workitem_gantt .gantt_critical { outline: 1px solid #9a6700; outline-offset: -1px; } /* buffer-bar amber (dark) */
237
- .workitem_gantt .gantt_release_band {
238
- text-align: center;
239
- font-size: 11px;
240
- font-weight: 600;
241
- color: #57606a;
242
- background: #eef1f4;
243
- border-bottom: 1px solid #e1e4e8;
244
- border-left: 1px solid #d0d7de;
245
- padding: 2px 4px;
246
- white-space: nowrap;
247
- overflow: hidden;
248
- text-overflow: ellipsis;
249
- }
250
- .workitem_gantt .gantt_buffer { color: #9a6700; }
251
- .critical_chain { margin-bottom: 16px; }
252
- .critical_chain h2 { font-size: 1.1em; margin-bottom: 6px; }
253
- .critical_chain .cc_group { margin: 8px 0; }
254
- .critical_chain .cc_group h3 { font-size: 0.95em; margin: 4px 0; }
255
- .critical_chain table.cc_chain { border-collapse: collapse; margin: 4px 0; }
256
- .critical_chain table.cc_chain th,
257
- .critical_chain table.cc_chain td { border: 1px solid #e1e4e8; padding: 2px 8px; text-align: left; font-size: 12px; }
258
- .critical_chain .cc_buffer,
259
- .critical_chain .cc_consumed,
260
- .critical_chain .cc_projected,
261
- .critical_chain .cc_finish { margin: 2px 0; font-size: 12px; }
262
- .critical_chain .cc_consumed { color: #57606a; }
263
- .critical_chain .cc_finish { font-weight: 600; }
264
- .critical_chain .cc_unestimated { color: #9a6700; font-style: italic; font-size: 12px; }
265
- .critical_chain .cc_group_body { display: flex; flex-wrap: wrap; gap: 24px; align-items: flex-start; }
266
- .critical_chain .cc_plan { flex: 1 1 320px; }
267
- .critical_chain .cc_fever { flex: 1 1 360px; max-width: 480px; height: 320px; position: relative; }
268
- .critical_chain .cc_fever .fever_canvas { width: 100%; height: 100%; }
269
- .workitem_gantt .gantt_buffer_bar {
270
- font-size: 11px;
271
- line-height: 1.5;
272
- margin: 1px;
273
- padding: 1px 5px;
274
- border-radius: 3px;
275
- text-align: center;
276
- overflow: hidden;
277
- white-space: nowrap;
278
- text-overflow: ellipsis;
279
- color: #9a6700;
280
- background: repeating-linear-gradient(45deg, #ffe9b3, #ffe9b3 5px, #fff3d4 5px, #fff3d4 10px);
281
- box-shadow: inset 0 0 0 1px #e0c068;
282
- cursor: default;
283
- }
284
- .workitem_gantt .gantt_today { border-left: 2px solid #d33; z-index: 5; pointer-events: none; }
285
- /* Plan-vs-actual tracking lanes (ADR-213): hidden until the toolbar toggle adds
286
- show-actuals; a hidden lane's grid tracks collapse to zero height. */
287
- .workitem_gantt .gantt_tracking_lane { display: none; }
288
- .workitem_gantt.show-actuals .gantt_tracking_lane { display: block; }
289
- .workitem_gantt .gantt_owner_tracking { font-weight: 400; font-style: italic; color: #57606a; }
290
- .workitem_gantt .gantt_track_committed { background: #b0b6bd; }
291
- .workitem_gantt .gantt_track_logged { background: #36a2eb; }
292
- .gantt_container .gantt_toolbar {
293
- display: flex;
294
- justify-content: flex-end;
295
- gap: 6px;
296
- padding: 4px 0;
297
- }
298
- .gantt_container .gantt_actuals_toggle {
299
- font-size: 12px;
300
- padding: 3px 10px;
301
- border: 1px solid #d0d7de;
302
- border-radius: 4px;
303
- background: #f6f8fa;
304
- cursor: pointer;
305
- }
306
- .gantt_container .gantt_actuals_toggle:hover { background: #eef1f4; }
307
153
  table.controlled:not(.odd-even) tbody tr:nth-child(odd) { background-color:#f6f7f8; }
308
154
  table.controlled:not(.odd-even) tbody tr:nth-child(even) { background-color: #fff; }
309
155
  table.controlled:not(.odd-even) tbody tr:nth-child(odd):hover,
@@ -417,7 +263,7 @@ img{
417
263
  text-align: center;
418
264
  padding: 4px 6px;
419
265
  text-decoration: none;
420
- font-size: 1.5em;
266
+ font-size: 18px;
421
267
  font-family: "Trebuchet MS", Verdana, sans-serif;
422
268
  }
423
269
  #top_nav a.split {
@@ -426,7 +272,7 @@ img{
426
272
  text-align: center;
427
273
  padding: 4px 6px;
428
274
  text-decoration: none;
429
- font-size: 1.5em;
275
+ font-size: 18px;
430
276
  font-family: "Trebuchet MS", Verdana, sans-serif;
431
277
  }
432
278
  #top_nav a:hover {
@@ -500,7 +346,7 @@ img{
500
346
  #footer {
501
347
  clear: both;
502
348
  border-top: 1px solid #bbb;
503
- font-size: 0.9em;
349
+ font-size: 10.8px;
504
350
  color: #aaa;
505
351
  padding: 5px;
506
352
  text-align:center;
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: Almirah
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.4
4
+ version: 0.4.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oleksandr Ivanov
@@ -77,13 +77,10 @@ files:
77
77
  - lib/almirah/doc_items/source_code_paragraph.rb
78
78
  - lib/almirah/doc_items/text_line.rb
79
79
  - lib/almirah/doc_items/todo_block.rb
80
- - lib/almirah/doc_items/work_item.rb
81
80
  - lib/almirah/doc_parser.rb
82
81
  - lib/almirah/doc_types/base_document.rb
83
82
  - lib/almirah/doc_types/coverage.rb
84
- - lib/almirah/doc_types/critical_chain_page.rb
85
83
  - lib/almirah/doc_types/decision.rb
86
- - lib/almirah/doc_types/decision_grouping.rb
87
84
  - lib/almirah/doc_types/decisions_overview.rb
88
85
  - lib/almirah/doc_types/implementation.rb
89
86
  - lib/almirah/doc_types/index.rb
@@ -103,12 +100,8 @@ files:
103
100
  - lib/almirah/link_registry.rb
104
101
  - lib/almirah/navigation_pane.rb
105
102
  - lib/almirah/project.rb
106
- - lib/almirah/project/critical_chain.rb
107
103
  - lib/almirah/project/doc_linker.rb
108
- - lib/almirah/project/fever_chart.rb
109
104
  - lib/almirah/project/project_data.rb
110
- - lib/almirah/project/work_item_scheduler.rb
111
- - lib/almirah/project/working_calendar.rb
112
105
  - lib/almirah/project_configuration.rb
113
106
  - lib/almirah/project_template.rb
114
107
  - lib/almirah/project_utility.rb