highlite 0.1.0
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.
- checksums.yaml +7 -0
- data/.claude/commands/publish.md +45 -0
- data/README.md +176 -0
- data/Rakefile +12 -0
- data/app/assets/stylesheets/highlite/viewer.css +607 -0
- data/app/helpers/highlite/application_helper.rb +20 -0
- data/app/javascript/highlite/controllers/.keep +0 -0
- data/app/javascript/highlite/controllers/highlight_controller.js +829 -0
- data/app/javascript/highlite/controllers/highlights_panel_controller.js +313 -0
- data/app/javascript/highlite/controllers/sidebar_controller.js +465 -0
- data/app/javascript/highlite/controllers/viewer_controller.js +373 -0
- data/app/javascript/highlite/index.js +30 -0
- data/app/javascript/highlite/lib/.keep +0 -0
- data/app/javascript/highlite/lib/highlight_store.js +235 -0
- data/app/javascript/highlite/lib/pdf_renderer.js +212 -0
- data/app/views/highlite/_floating_toolbar.html.erb +79 -0
- data/app/views/highlite/_left_sidebar.html.erb +43 -0
- data/app/views/highlite/_right_sidebar.html.erb +56 -0
- data/app/views/highlite/_toolbar.html.erb +63 -0
- data/app/views/highlite/_viewer.html.erb +63 -0
- data/config/importmap.rb +17 -0
- data/lib/generators/highlite/install/install_generator.rb +44 -0
- data/lib/generators/highlite/install/templates/_right_sidebar.html.erb.tt +16 -0
- data/lib/generators/highlite/install/templates/initializer.rb.tt +20 -0
- data/lib/highlite/configuration.rb +27 -0
- data/lib/highlite/engine.rb +26 -0
- data/lib/highlite/version.rb +5 -0
- data/lib/highlite.rb +17 -0
- data/sig/highlite.rbs +4 -0
- data/tasks/todo.md +129 -0
- data/test/dummy/Rakefile +3 -0
- data/test/dummy/app/controllers/application_controller.rb +2 -0
- data/test/dummy/app/controllers/documents_controller.rb +6 -0
- data/test/dummy/app/javascript/application.js +1 -0
- data/test/dummy/app/views/documents/show.html.erb +1 -0
- data/test/dummy/app/views/layouts/application.html.erb +13 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/config/application.rb +15 -0
- data/test/dummy/config/boot.rb +2 -0
- data/test/dummy/config/environment.rb +2 -0
- data/test/dummy/config/importmap.rb +3 -0
- data/test/dummy/config/routes.rb +3 -0
- data/test/dummy/config.ru +2 -0
- data/test/dummy/public/convention-over-configuration.pdf +0 -0
- metadata +117 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Highlite
|
|
4
|
+
class Engine < ::Rails::Engine
|
|
5
|
+
isolate_namespace Highlite
|
|
6
|
+
|
|
7
|
+
initializer "highlite.assets" do |app|
|
|
8
|
+
if app.config.respond_to?(:assets)
|
|
9
|
+
app.config.assets.paths << root.join("app/assets/stylesheets")
|
|
10
|
+
app.config.assets.paths << root.join("app/javascript")
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
initializer "highlite.importmap", before: "importmap" do |app|
|
|
15
|
+
if app.config.respond_to?(:importmap)
|
|
16
|
+
app.config.importmap.paths << root.join("config/importmap.rb")
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
initializer "highlite.helpers" do
|
|
21
|
+
ActiveSupport.on_load(:action_controller_base) do
|
|
22
|
+
helper Highlite::ApplicationHelper
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
data/lib/highlite.rb
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "highlite/version"
|
|
4
|
+
require_relative "highlite/configuration"
|
|
5
|
+
require_relative "highlite/engine" if defined?(Rails)
|
|
6
|
+
|
|
7
|
+
module Highlite
|
|
8
|
+
class Error < StandardError; end
|
|
9
|
+
|
|
10
|
+
def self.configure
|
|
11
|
+
yield Configuration.instance
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.configuration
|
|
15
|
+
Configuration.instance
|
|
16
|
+
end
|
|
17
|
+
end
|
data/sig/highlite.rbs
ADDED
data/tasks/todo.md
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# Highlite Gem — Build Plan
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
A Ruby gem (Rails engine) that provides a full-featured PDF viewer with highlighting, modeled after [react-pdf-highlighter-plus](https://react-pdf-highlighter-plus-demo.vercel.app/pdf-demo). Built for Rails 8 + Hotwire (Stimulus) + Tailwind CSS + Import Maps.
|
|
6
|
+
|
|
7
|
+
## Architecture
|
|
8
|
+
|
|
9
|
+
### Three-panel layout
|
|
10
|
+
- **Left sidebar** (gem-owned): Outline tab (TOC from PDF metadata) + Pages tab (thumbnails)
|
|
11
|
+
- **Center** (gem-owned): PDF.js canvas rendering + text layer + highlight overlay
|
|
12
|
+
- **Right sidebar** (default + overridable): Highlights list with search, grouped by page. Users can replace with their own partial.
|
|
13
|
+
|
|
14
|
+
### Key design decisions
|
|
15
|
+
- **Stimulus controllers** dispatch custom events (`highlite:highlight-created`, etc.) so host apps can react
|
|
16
|
+
- **Right sidebar override** — ships a default highlights panel, but host apps can provide their own partial at `app/views/highlite/_right_sidebar.html.erb` which takes precedence (Rails engine view override convention)
|
|
17
|
+
- **PDF.js via CDN** (jsdelivr) — pinned in engine's importmap config, no npm required
|
|
18
|
+
- **localStorage by default** for highlight persistence, with an optional `Highlightable` model concern for server-side storage
|
|
19
|
+
- **tailwindcss-ruby** (`flavorjones/tailwindcss-ruby`) — compiles Tailwind CSS within the gem so the host app doesn't need Tailwind installed (but works great if they do)
|
|
20
|
+
- **CSS strategy** — gem ships a pre-compiled CSS file built with tailwindcss-ruby during development; the host app includes it via `stylesheet_link_tag "highlite/viewer"`
|
|
21
|
+
|
|
22
|
+
### Stimulus event API (dispatched on the viewer element)
|
|
23
|
+
```
|
|
24
|
+
highlite:document-loaded { detail: { pageCount, title, outline } }
|
|
25
|
+
highlite:page-changed { detail: { page, totalPages } }
|
|
26
|
+
highlite:highlight-created { detail: { id, page, type, color, text, rects } }
|
|
27
|
+
highlite:highlight-removed { detail: { id } }
|
|
28
|
+
highlite:highlight-selected { detail: { id, page } }
|
|
29
|
+
highlite:highlights-cleared { detail: { page } } // null page = all
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Directory structure
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
highlite/
|
|
36
|
+
├── highlite.gemspec
|
|
37
|
+
├── Gemfile
|
|
38
|
+
├── Rakefile
|
|
39
|
+
├── README.md
|
|
40
|
+
├── lib/
|
|
41
|
+
│ ├── highlite.rb # Main entry + autoload
|
|
42
|
+
│ ├── highlite/
|
|
43
|
+
│ │ ├── version.rb
|
|
44
|
+
│ │ ├── engine.rb # Rails engine config + importmap
|
|
45
|
+
│ │ └── configuration.rb # Config DSL (pdf.js version, colors, etc.)
|
|
46
|
+
│ └── generators/
|
|
47
|
+
│ └── highlite/
|
|
48
|
+
│ └── install/
|
|
49
|
+
│ ├── install_generator.rb # rails g highlite:install
|
|
50
|
+
│ └── templates/
|
|
51
|
+
│ ├── initializer.rb.tt
|
|
52
|
+
│ └── _right_sidebar.html.erb.tt # Override template
|
|
53
|
+
├── app/
|
|
54
|
+
│ ├── assets/
|
|
55
|
+
│ │ └── stylesheets/
|
|
56
|
+
│ │ └── highlite/
|
|
57
|
+
│ │ └── viewer.css # Minimal required styles (text layer, etc.)
|
|
58
|
+
│ ├── javascript/
|
|
59
|
+
│ │ └── highlite/
|
|
60
|
+
│ │ ├── index.js # Registers all controllers with Stimulus
|
|
61
|
+
│ │ ├── controllers/
|
|
62
|
+
│ │ │ ├── viewer_controller.js # PDF.js rendering, zoom, scroll
|
|
63
|
+
│ │ │ ├── highlight_controller.js # Drawing + managing highlights
|
|
64
|
+
│ │ │ ├── sidebar_controller.js # Left sidebar (outline + pages tabs)
|
|
65
|
+
│ │ │ └── highlights_panel_controller.js # Right sidebar (default highlight list)
|
|
66
|
+
│ │ └── lib/
|
|
67
|
+
│ │ ├── pdf_renderer.js # PDF.js wrapper (load, render, text layer)
|
|
68
|
+
│ │ └── highlight_store.js # State management + localStorage
|
|
69
|
+
│ ├── helpers/
|
|
70
|
+
│ │ └── highlite/
|
|
71
|
+
│ │ └── application_helper.rb # highlite_viewer helper method
|
|
72
|
+
│ └── views/
|
|
73
|
+
│ └── highlite/
|
|
74
|
+
│ ├── _viewer.html.erb # Main 3-panel layout
|
|
75
|
+
│ ├── _toolbar.html.erb # Top bar (zoom, export, change PDF)
|
|
76
|
+
│ ├── _left_sidebar.html.erb # Outline + Pages tabs
|
|
77
|
+
│ ├── _right_sidebar.html.erb # Default highlights panel
|
|
78
|
+
│ └── _floating_toolbar.html.erb # Annotation tool buttons
|
|
79
|
+
└── spec/
|
|
80
|
+
├── spec_helper.rb
|
|
81
|
+
└── lib/
|
|
82
|
+
└── highlite_spec.rb
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Build tasks
|
|
86
|
+
|
|
87
|
+
### Phase 1: Foundation
|
|
88
|
+
- [ ] 1.1 Set up gemspec with correct dependencies (rails >= 7.1, importmap-rails)
|
|
89
|
+
- [ ] 1.2 Create Rails engine (Highlite::Engine) with importmap config
|
|
90
|
+
- [ ] 1.3 Create Configuration class (pdf_js_version, default_colors, toolbar_tools, right_sidebar_partial)
|
|
91
|
+
- [ ] 1.4 Create install generator (initializer + optional sidebar override template)
|
|
92
|
+
- [ ] 1.5 Create viewer helper method: `highlite_viewer(url:, document_id:, **options)`
|
|
93
|
+
|
|
94
|
+
### Phase 2: Core JavaScript — PDF Viewer
|
|
95
|
+
- [ ] 2.1 Build pdf_renderer.js — PDF.js wrapper (load document, render page to canvas, text layer, get outline, render thumbnail)
|
|
96
|
+
- [ ] 2.2 Build viewer_controller.js — Stimulus controller (renders PDF, handles zoom [Auto/fit/%, +, -], page scroll tracking, keyboard nav)
|
|
97
|
+
- [ ] 2.3 Build highlight_store.js — State manager (add/remove/update/query highlights, localStorage read/write, event dispatch)
|
|
98
|
+
|
|
99
|
+
### Phase 3: Highlighting
|
|
100
|
+
- [ ] 3.1 Build highlight_controller.js — Text selection highlighting (capture Selection API ranges → rects, apply color)
|
|
101
|
+
- [ ] 3.2 Add area/rectangle highlighting mode (mousedown→drag→mouseup drawing)
|
|
102
|
+
- [ ] 3.3 Highlight rendering (colored overlay divs with mix-blend-mode: multiply)
|
|
103
|
+
- [ ] 3.4 Highlight interaction (click to select, right-click to remove, hover effect)
|
|
104
|
+
- [ ] 3.5 Multiple highlight colors (toolbar color picker)
|
|
105
|
+
|
|
106
|
+
### Phase 4: Left Sidebar
|
|
107
|
+
- [ ] 4.1 Build sidebar_controller.js — Tab switching (Outline / Pages)
|
|
108
|
+
- [ ] 4.2 Outline tab — Extract TOC from PDF metadata, render hierarchical tree, click-to-navigate, blue dots for pages with highlights
|
|
109
|
+
- [ ] 4.3 Pages tab — Render page thumbnails (small canvas), active page border, click-to-navigate, page counter
|
|
110
|
+
|
|
111
|
+
### Phase 5: Right Sidebar (Default + Override)
|
|
112
|
+
- [ ] 5.1 Build highlights_panel_controller.js — Lists highlights grouped by page, search/filter, clear all
|
|
113
|
+
- [ ] 5.2 Build _right_sidebar.html.erb — Default partial with highlight cards (type badge, quoted text, page link)
|
|
114
|
+
- [ ] 5.3 Implement override mechanism — check for app/views/highlite/_right_sidebar.html.erb in host app, fall back to gem default
|
|
115
|
+
|
|
116
|
+
### Phase 6: Toolbar & Polish
|
|
117
|
+
- [ ] 6.1 Build _toolbar.html.erb — Top bar (zoom controls, page info)
|
|
118
|
+
- [ ] 6.2 Build _floating_toolbar.html.erb — Vertical tool buttons (select, text highlight, area highlight, colors)
|
|
119
|
+
- [ ] 6.3 Keyboard shortcuts (Ctrl+Z undo, Escape deselect, arrow keys for pages)
|
|
120
|
+
|
|
121
|
+
### Phase 7: Views & Integration
|
|
122
|
+
- [ ] 7.1 Build _viewer.html.erb — Main layout composing all panels
|
|
123
|
+
- [ ] 7.2 Build viewer.css — Required styles (text layer positioning, highlight blending, sidebar transitions)
|
|
124
|
+
- [ ] 7.3 Wire helper method to render the viewer partial with all options
|
|
125
|
+
- [ ] 7.4 Write README with usage examples, configuration, and override instructions
|
|
126
|
+
|
|
127
|
+
### Phase 8: Testing
|
|
128
|
+
- [ ] 8.1 RSpec tests for engine loading, configuration, helper output
|
|
129
|
+
- [ ] 8.2 Generator tests (install generator creates expected files)
|
data/test/dummy/Rakefile
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "highlite"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<%= highlite_viewer(url: @pdf_url, document_id: @document_id) %>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>Highlite Test</title>
|
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
6
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
7
|
+
<%= stylesheet_link_tag "highlite/viewer" %>
|
|
8
|
+
<%= javascript_importmap_tags %>
|
|
9
|
+
</head>
|
|
10
|
+
<body>
|
|
11
|
+
<%= yield %>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require_relative "boot"
|
|
2
|
+
|
|
3
|
+
require "action_controller/railtie"
|
|
4
|
+
require "action_view/railtie"
|
|
5
|
+
require "propshaft"
|
|
6
|
+
require "importmap-rails"
|
|
7
|
+
require "highlite"
|
|
8
|
+
|
|
9
|
+
module Dummy
|
|
10
|
+
class Application < Rails::Application
|
|
11
|
+
config.load_defaults Rails::VERSION::STRING.to_f
|
|
12
|
+
config.eager_load = false
|
|
13
|
+
config.secret_key_base = "test-secret-key-base-for-dummy-app"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
Binary file
|
metadata
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: highlite
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Nathan Jones
|
|
8
|
+
bindir: exe
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: rails
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '7.1'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '7.1'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: importmap-rails
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '0'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '0'
|
|
40
|
+
description: A Rails engine that wraps PDF.js to provide a full-featured PDF viewer
|
|
41
|
+
with text and area highlighting, powered by Stimulus controllers and Tailwind CSS.
|
|
42
|
+
Includes a three-panel layout with outline/thumbnails sidebar, highlight management,
|
|
43
|
+
and an overridable right sidebar for custom integrations.
|
|
44
|
+
email:
|
|
45
|
+
- natejones@hey.com
|
|
46
|
+
executables: []
|
|
47
|
+
extensions: []
|
|
48
|
+
extra_rdoc_files: []
|
|
49
|
+
files:
|
|
50
|
+
- ".claude/commands/publish.md"
|
|
51
|
+
- README.md
|
|
52
|
+
- Rakefile
|
|
53
|
+
- app/assets/stylesheets/highlite/viewer.css
|
|
54
|
+
- app/helpers/highlite/application_helper.rb
|
|
55
|
+
- app/javascript/highlite/controllers/.keep
|
|
56
|
+
- app/javascript/highlite/controllers/highlight_controller.js
|
|
57
|
+
- app/javascript/highlite/controllers/highlights_panel_controller.js
|
|
58
|
+
- app/javascript/highlite/controllers/sidebar_controller.js
|
|
59
|
+
- app/javascript/highlite/controllers/viewer_controller.js
|
|
60
|
+
- app/javascript/highlite/index.js
|
|
61
|
+
- app/javascript/highlite/lib/.keep
|
|
62
|
+
- app/javascript/highlite/lib/highlight_store.js
|
|
63
|
+
- app/javascript/highlite/lib/pdf_renderer.js
|
|
64
|
+
- app/views/highlite/_floating_toolbar.html.erb
|
|
65
|
+
- app/views/highlite/_left_sidebar.html.erb
|
|
66
|
+
- app/views/highlite/_right_sidebar.html.erb
|
|
67
|
+
- app/views/highlite/_toolbar.html.erb
|
|
68
|
+
- app/views/highlite/_viewer.html.erb
|
|
69
|
+
- config/importmap.rb
|
|
70
|
+
- lib/generators/highlite/install/install_generator.rb
|
|
71
|
+
- lib/generators/highlite/install/templates/_right_sidebar.html.erb.tt
|
|
72
|
+
- lib/generators/highlite/install/templates/initializer.rb.tt
|
|
73
|
+
- lib/highlite.rb
|
|
74
|
+
- lib/highlite/configuration.rb
|
|
75
|
+
- lib/highlite/engine.rb
|
|
76
|
+
- lib/highlite/version.rb
|
|
77
|
+
- sig/highlite.rbs
|
|
78
|
+
- tasks/todo.md
|
|
79
|
+
- test/dummy/Rakefile
|
|
80
|
+
- test/dummy/app/controllers/application_controller.rb
|
|
81
|
+
- test/dummy/app/controllers/documents_controller.rb
|
|
82
|
+
- test/dummy/app/javascript/application.js
|
|
83
|
+
- test/dummy/app/views/documents/show.html.erb
|
|
84
|
+
- test/dummy/app/views/layouts/application.html.erb
|
|
85
|
+
- test/dummy/bin/rails
|
|
86
|
+
- test/dummy/config.ru
|
|
87
|
+
- test/dummy/config/application.rb
|
|
88
|
+
- test/dummy/config/boot.rb
|
|
89
|
+
- test/dummy/config/environment.rb
|
|
90
|
+
- test/dummy/config/importmap.rb
|
|
91
|
+
- test/dummy/config/routes.rb
|
|
92
|
+
- test/dummy/public/convention-over-configuration.pdf
|
|
93
|
+
homepage: https://github.com/nathanjones/highlite
|
|
94
|
+
licenses:
|
|
95
|
+
- MIT
|
|
96
|
+
metadata:
|
|
97
|
+
homepage_uri: https://github.com/nathanjones/highlite
|
|
98
|
+
source_code_uri: https://github.com/nathanjones/highlite
|
|
99
|
+
changelog_uri: https://github.com/nathanjones/highlite/blob/main/CHANGELOG.md
|
|
100
|
+
rdoc_options: []
|
|
101
|
+
require_paths:
|
|
102
|
+
- lib
|
|
103
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
104
|
+
requirements:
|
|
105
|
+
- - ">="
|
|
106
|
+
- !ruby/object:Gem::Version
|
|
107
|
+
version: 3.1.0
|
|
108
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
109
|
+
requirements:
|
|
110
|
+
- - ">="
|
|
111
|
+
- !ruby/object:Gem::Version
|
|
112
|
+
version: '0'
|
|
113
|
+
requirements: []
|
|
114
|
+
rubygems_version: 4.0.3
|
|
115
|
+
specification_version: 4
|
|
116
|
+
summary: Rails engine providing a PDF viewer with text and area highlighting
|
|
117
|
+
test_files: []
|