Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .rdoc_options
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
op_dir: _site # for GitHub Pages and should match the config of RDoc task in Rakefile
title: rdoc Documentation
title: RDoc Documentation
main_page: README.md
autolink_excluded_words:
- RDoc
1 change: 1 addition & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ task rdoc: :generate
RDoc::Task.new do |doc|
# RDoc task defaults to /html and overrides the op_dir option in .rdoc_options
doc.rdoc_dir = "_site" # for GitHub Pages
doc.template = "aliki"
end

task "coverage" do
Expand Down
1 change: 1 addition & 0 deletions lib/rdoc/generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ module RDoc::Generator

autoload :Markup, "#{__dir__}/generator/markup"

autoload :Aliki, "#{__dir__}/generator/aliki"
autoload :Darkfish, "#{__dir__}/generator/darkfish"
autoload :JsonIndex, "#{__dir__}/generator/json_index"
autoload :RI, "#{__dir__}/generator/ri"
Expand Down
78 changes: 78 additions & 0 deletions lib/rdoc/generator/aliki.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# frozen_string_literal: true

##
# Aliki RDoc HTML Generator - A modern documentation theme
#
# Based on Darkfish by Michael Granger ([email protected])
#
# == Description
#
# Aliki brings modern design patterns to RDoc documentation with:
#
# * Three-column responsive layout (navigation, content, table of contents)
# * Dark mode support with theme toggle and localStorage persistence
# * Auto-generated right sidebar TOC with scroll spy (Intersection Observer)
# * Mobile-optimized search modal with keyboard shortcuts
# * Enhanced syntax highlighting for light and dark themes
# * Responsive design with mobile navigation
# * Zero additional JavaScript dependencies
# * Modern CSS Grid and Flexbox layout
#
# == Usage
#
# rdoc --format=aliki --op=doc/
#
# == Author
#
# Based on Darkfish by Michael Granger
# Modernized as Aliki theme by Stan Lo
#

class RDoc::Generator::Aliki < RDoc::Generator::Darkfish

RDoc::RDoc.add_generator self

##
# Version of the Aliki generator

VERSION = '1'

##
# Description of this generator

DESCRIPTION = 'Modern HTML generator based on Darkfish'

##
# Initialize the Aliki generator with the aliki template directory

def initialize(store, options)
super
aliki_template_dir = File.expand_path(File.join(__dir__, 'template', 'aliki'))
@template_dir = Pathname.new(aliki_template_dir)
end

##
# Copy only the static assets required by the Aliki theme. Unlike Darkfish we
# don't ship embedded fonts or image sprites, so limit the asset list to keep
# generated documentation lightweight.

def write_style_sheet
debug_msg "Copying Aliki static files"
options = { verbose: $DEBUG_RDOC, noop: @dry_run }

install_rdoc_static_file @template_dir + 'css/rdoc.css', "./css/rdoc.css", options

unless @options.template_stylesheets.empty?
FileUtils.cp @options.template_stylesheets, '.', **options
end

Dir[(@template_dir + 'js/**/*').to_s].each do |path|
next if File.directory?(path)
next if File.basename(path).start_with?('.')

dst = Pathname.new(path).relative_path_from(@template_dir)

install_rdoc_static_file @template_dir + path, dst, options
end
end
end
Empty file.
8 changes: 8 additions & 0 deletions lib/rdoc/generator/template/aliki/_aside_toc.rhtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<aside class="table-of-contents" role="complementary" aria-label="Table of Contents">
<div class="toc-sticky">
<h3 class="toc-heading">On This Page</h3>
<nav class="toc-nav" id="toc-nav" aria-label="Page sections">
<!-- Generated by JavaScript based on page headings -->
</nav>
</div>
</aside>
25 changes: 25 additions & 0 deletions lib/rdoc/generator/template/aliki/_footer.rhtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<footer class="site-footer">
<div class="footer-content">
<div>
<h3>Documentation</h3>
<ul>
<li><a href="<%= h asset_rel_path %>/index.html">Home</a></li>
</ul>
</div>

<div>
<h3>Resources</h3>
<ul>
<li><a href="https://ruby.github.io/rdoc/">RDoc Documentation</a></li>
<li><a href="https://github.com/ruby/rdoc">RDoc GitHub</a></li>
</ul>
</div>
</div>

<div class="footer-bottom">
<p>
Generated by <a href="https://ruby.github.io/rdoc/">RDoc <%= RDoc::VERSION %></a>
using the Aliki theme by <a href="http://st0012.dev">Stan Lo</a>
</p>
</div>
</footer>
48 changes: 48 additions & 0 deletions lib/rdoc/generator/template/aliki/_head.rhtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<meta charset="<%= @options.charset %>">
<meta name="viewport" content="width=device-width, initial-scale=1" />

<title><%= h @title %></title>

<%- if defined?(klass) -%>
<meta name="keywords" content="ruby,<%= h "#{klass.type},#{klass.full_name}" %>">

<%- if klass.comment.empty? -%>
<meta name="description" content="Documentation for the <%= h "#{klass.full_name} #{klass.type}" %>">
<%- else -%>
<meta name="description" content="<%= h "#{klass.type} #{klass.full_name}: #{excerpt(klass.comment)}" %>">
<%- end -%>
<%- elsif defined?(file) -%>
<meta name="keywords" content="ruby,documentation,<%= h file.page_name %>">
<meta name="description" content="<%= h "#{file.page_name}: #{excerpt(file.comment)}" %>">
<%- elsif @title -%>
<meta name="keywords" content="ruby,documentation,<%= h @title %>">

<%- if @options.main_page and
main_page = @files.find { |f| f.full_name == @options.main_page } then %>
<meta name="description" content="<%= h "#{@title}: #{excerpt(main_page.comment)}" %>">
<%- else -%>
<meta name="description" content="Documentation for <%= h @title %>">
<%- end -%>
<%- end -%>

<%- if canonical_url = @options.canonical_root -%>
<% canonical_url = current.canonical_url if defined?(current) %>
<link rel="canonical" href="<%= canonical_url %>">
<%- end -%>

<script type="text/javascript">
var rdoc_rel_prefix = "<%= h asset_rel_prefix %>/";
var index_rel_prefix = "<%= h rel_prefix %>/";
</script>

<script src="<%= h asset_rel_prefix %>/js/theme-toggle.js"></script>
<script src="<%= h asset_rel_prefix %>/js/navigation.js" defer></script>
<script src="<%= h asset_rel_prefix %>/js/search.js" defer></script>
<script src="<%= h asset_rel_prefix %>/js/search_index.js" defer></script>
<script src="<%= h asset_rel_prefix %>/js/searcher.js" defer></script>
<script src="<%= h asset_rel_prefix %>/js/aliki.js" defer></script>

<link href="<%= h asset_rel_prefix %>/css/rdoc.css" rel="stylesheet">
<%- @options.template_stylesheets.each do |stylesheet| -%>
<link href="<%= h asset_rel_prefix %>/<%= File.basename stylesheet %>" rel="stylesheet">
<%- end -%>
55 changes: 55 additions & 0 deletions lib/rdoc/generator/template/aliki/_header.rhtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<header class="top-navbar">
<a href="<%= rel_prefix %>/index.html" class="navbar-brand">
<%= h @options.title %>
</a>

<!-- Desktop search bar -->
<div class="navbar-search navbar-search-desktop" role="search">
<form action="#" method="get" accept-charset="utf-8">
<input id="search-field" role="combobox" aria-label="Search"
aria-autocomplete="list" aria-controls="search-results"
type="text" name="search" placeholder="Search (/) for a class, method..."
spellcheck="false" title="Type to search, Up and Down to navigate, Enter to load">
<ul id="search-results" aria-label="Search Results"
aria-busy="false" aria-expanded="false"
aria-atomic="false" class="initially-hidden"></ul>
</form>
</div>

<!-- Mobile search icon button -->
<button id="search-toggle" class="navbar-search-mobile" aria-label="Open search" type="button">
<span aria-hidden="true">🔍</span>
</button>

<!-- Theme toggle button -->
<button id="theme-toggle" class="theme-toggle" aria-label="Switch to dark mode" type="button">
<span class="theme-toggle-icon" aria-hidden="true">🌙</span>
</button>
</header>

<!-- Search Modal (Mobile) -->
<div id="search-modal" class="search-modal" hidden aria-modal="true" role="dialog" aria-label="Search">
<div class="search-modal-backdrop"></div>
<div class="search-modal-content">
<div class="search-modal-header">
<form class="search-modal-form" action="#" method="get" accept-charset="utf-8">
<span class="search-modal-icon" aria-hidden="true">🔍</span>
<input id="search-field-mobile" role="combobox" aria-label="Search"
aria-autocomplete="list" aria-controls="search-results-mobile"
type="text" name="search" placeholder="Search documentation"
spellcheck="false" autocomplete="off">
<button type="button" class="search-modal-close" aria-label="Close search" id="search-modal-close">
<span aria-hidden="true">esc</span>
</button>
</form>
</div>
<div class="search-modal-body">
<ul id="search-results-mobile" aria-label="Search Results"
aria-busy="false" aria-expanded="false"
aria-atomic="false" class="search-modal-results initially-hidden"></ul>
<div class="search-modal-empty">
<p>No recent searches</p>
</div>
</div>
</div>
</div>
6 changes: 6 additions & 0 deletions lib/rdoc/generator/template/aliki/_sidebar_ancestors.rhtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<%- if klass.type == 'class' && (ancestors = klass.super_classes).any? -%>
<div id="parent-class-section" class="nav-section">
<h3>Ancestors</h3>
<%= generate_ancestor_list(ancestors, klass) %>
</div>
<%- end -%>
5 changes: 5 additions & 0 deletions lib/rdoc/generator/template/aliki/_sidebar_classes.rhtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<div id="classindex-section" class="nav-section">
<h3>Class and Module Index</h3>

<%= generate_class_index_content(@classes, rel_prefix) %>
</div>
15 changes: 15 additions & 0 deletions lib/rdoc/generator/template/aliki/_sidebar_extends.rhtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<%- unless klass.extends.empty? then %>
<div id="extends-section" class="nav-section">
<h3>Extended With Modules</h3>

<ul class="link-list">
<%- klass.extends.each do |ext| -%>
<%- unless String === ext.module then -%>
<li><a class="extend" href="<%= klass.aref_to ext.module.path %>"><%= ext.module.full_name %></a>
<%- else -%>
<li><span class="extend"><%= ext.name %></span>
<%- end -%>
<%- end -%>
</ul>
</div>
<%- end -%>
15 changes: 15 additions & 0 deletions lib/rdoc/generator/template/aliki/_sidebar_includes.rhtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<%- unless klass.includes.empty? then %>
<div id="includes-section" class="nav-section">
<h3>Included Modules</h3>

<ul class="link-list">
<%- klass.includes.each do |inc| -%>
<%- unless String === inc.module then -%>
<li><a class="include" href="<%= klass.aref_to inc.module.path %>"><%= inc.module.full_name %></a>
<%- else -%>
<li><span class="include"><%= inc.name %></span>
<%- end -%>
<%- end -%>
</ul>
</div>
<%- end -%>
15 changes: 15 additions & 0 deletions lib/rdoc/generator/template/aliki/_sidebar_installed.rhtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<div id="home-section" class="nav-section">
<h3>Documentation</h3>

<ul>
<%- installed.each do |name, href, exists, type, _| -%>
<%- next if type == :extra -%>
<li class="folder">
<%- if exists then -%>
<a href="<%= href %>"><%= h name %></a>
<%- else -%>
<%= h name %>
<%- end -%>
<%- end -%>
</ul>
</div>
21 changes: 21 additions & 0 deletions lib/rdoc/generator/template/aliki/_sidebar_methods.rhtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<% if (class_methods = klass.class_method_list.sort).any? %>
<div class="nav-section">
<h3>Class Methods</h3>
<ul class="link-list" role="directory">
<%- class_methods.each do |meth| -%>
<li <%- if meth.calls_super %>class="calls-super" <%- end %>><a href="#<%= meth.aref %>"><%= h meth.name -%></a></li>
<%- end -%>
</ul>
</div>
<% end %>

<% if (instance_methods = klass.instance_methods.sort).any? %>
<div class="nav-section">
<h3>Instance Methods</h3>
<ul class="link-list" role="directory">
<%- instance_methods.each do |meth| -%>
<li <%- if meth.calls_super %>class="calls-super" <%- end %>><a href="#<%= meth.aref %>"><%= h meth.name -%></a></li>
<%- end -%>
</ul>
</div>
<% end %>
32 changes: 32 additions & 0 deletions lib/rdoc/generator/template/aliki/_sidebar_pages.rhtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<%- simple_files = @files.select { |f| f.text? } %>
<%- if defined?(current) && current.respond_to?(:page_name) -%>
<%- dir = current.full_name[%r{\A[^/]+(?=/)}] || current.page_name -%>
<%- end -%>
<%- unless simple_files.empty? then -%>
<div id="fileindex-section" class="nav-section">
<h3>Pages</h3>

<ul class="link-list">
<%- simple_files.group_by do |f| -%>
<%- f.full_name[%r{\A[^/]+(?=/)}] || f.page_name -%>
<%- end.each do |n, files| -%>
<%- f = files.shift -%>
<%- if files.empty? -%>
<li><a href="<%= rel_prefix %>/<%= h f.path %>"><%= h f.page_name %></a>
<%- next -%>
<%- end -%>
<li><details<% if dir == n %> open<% end %>><summary><%
if n == f.page_name
%><a href="<%= rel_prefix %>/<%= h f.path %>"><%= h n %></a><%
else
%><%= h n %><% files.unshift(f)
end %></summary>
<ul class="link-list">
<%- files.each do |f| -%>
<li><a href="<%= rel_prefix %>/<%= h f.path %>"><%= h f.page_name %></a>
<%- end -%>
</ul></details>
<%- end -%>
</ul>
</div>
<%- end -%>
14 changes: 14 additions & 0 deletions lib/rdoc/generator/template/aliki/_sidebar_search.rhtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<div id="search-section" role="search" class="project-section initially-hidden">
<form action="#" method="get" accept-charset="utf-8">
<div id="search-field-wrapper">
<input id="search-field" role="combobox" aria-label="Search"
aria-autocomplete="list" aria-controls="search-results"
type="text" name="search" placeholder="Search (/) for a class, method, ..." spellcheck="false"
title="Type to search, Up and Down to navigate, Enter to load">
</div>

<ul id="search-results" aria-label="Search Results"
aria-busy="false" aria-expanded="false"
aria-atomic="false" class="initially-hidden"></ul>
</form>
</div>
11 changes: 11 additions & 0 deletions lib/rdoc/generator/template/aliki/_sidebar_sections.rhtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<%- unless klass.sections.length == 1 then %>
<div id="sections-section" class="nav-section">
<h3>Sections</h3>

<ul class="link-list" role="directory">
<%- klass.sort_sections.each do |section| -%>
<li><a href="#<%= section.aref %>"><%= h section.title %></a></li>
<%- end -%>
</ul>
</div>
<%- end -%>
3 changes: 3 additions & 0 deletions lib/rdoc/generator/template/aliki/_sidebar_toggle.rhtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div id="navigation-toggle" role="button" tabindex="0" aria-label="Toggle sidebar" aria-expanded="true" aria-controls="navigation">
<span aria-hidden="true">&#9776;</span>
</div>
Loading
Loading