@huydao/karrot 0.1.6 → 0.1.8

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.
@@ -0,0 +1,201 @@
1
+ (function () {
2
+ const doc = document;
3
+ const body = doc.body;
4
+
5
+ function copyCode(button) {
6
+ const block = button.closest('.code-block');
7
+ const code = block ? block.querySelector('code') : null;
8
+
9
+ if (!code) {
10
+ return;
11
+ }
12
+
13
+ navigator.clipboard.writeText(code.innerText).then(() => {
14
+ const original = button.textContent;
15
+ button.textContent = 'Copied';
16
+ button.setAttribute('aria-live', 'polite');
17
+ window.setTimeout(() => {
18
+ button.textContent = original || 'Copy';
19
+ }, 1400);
20
+ }).catch(() => {
21
+ button.textContent = 'Select';
22
+ });
23
+ }
24
+
25
+ function enhanceCodeBlocks() {
26
+ doc.querySelectorAll('pre').forEach((pre) => {
27
+ if (pre.parentElement && pre.parentElement.classList.contains('code-block')) {
28
+ return;
29
+ }
30
+
31
+ const wrapper = doc.createElement('div');
32
+ wrapper.className = 'code-block';
33
+ const button = doc.createElement('button');
34
+ button.type = 'button';
35
+ button.className = 'copy-button';
36
+ button.textContent = 'Copy';
37
+ button.addEventListener('click', () => copyCode(button));
38
+
39
+ pre.parentNode.insertBefore(wrapper, pre);
40
+ wrapper.appendChild(button);
41
+ wrapper.appendChild(pre);
42
+ });
43
+ }
44
+
45
+ function setupMobileNav() {
46
+ const toggle = doc.querySelector('[data-nav-toggle]');
47
+ const sidebar = doc.querySelector('[data-sidebar]');
48
+ const backdrop = doc.querySelector('[data-sidebar-backdrop]');
49
+
50
+ if (!toggle || !sidebar) {
51
+ return;
52
+ }
53
+
54
+ function close() {
55
+ body.classList.remove('nav-open');
56
+ toggle.setAttribute('aria-expanded', 'false');
57
+ }
58
+
59
+ toggle.addEventListener('click', () => {
60
+ const open = body.classList.toggle('nav-open');
61
+ toggle.setAttribute('aria-expanded', String(open));
62
+ });
63
+
64
+ sidebar.querySelectorAll('a').forEach((link) => {
65
+ link.addEventListener('click', close);
66
+ });
67
+
68
+ if (backdrop) {
69
+ backdrop.addEventListener('click', close);
70
+ }
71
+
72
+ doc.addEventListener('keydown', (event) => {
73
+ if (event.key === 'Escape') {
74
+ close();
75
+ }
76
+ });
77
+ }
78
+
79
+ function setupHeadingLinks() {
80
+ doc.querySelectorAll('main section[id] > h2, main h3[id]').forEach((heading) => {
81
+ if (heading.querySelector('.heading-anchor')) {
82
+ return;
83
+ }
84
+
85
+ const targetId = heading.id || heading.closest('section[id]')?.id;
86
+
87
+ if (!targetId) {
88
+ return;
89
+ }
90
+
91
+ const anchor = doc.createElement('a');
92
+ anchor.className = 'heading-anchor';
93
+ anchor.href = `#${targetId}`;
94
+ anchor.setAttribute('aria-label', `Link to ${heading.textContent}`);
95
+ anchor.textContent = '#';
96
+ heading.appendChild(anchor);
97
+ });
98
+ }
99
+
100
+ function buildToc() {
101
+ const toc = doc.querySelector('[data-toc]');
102
+
103
+ if (!toc) {
104
+ return [];
105
+ }
106
+
107
+ const sections = Array.from(doc.querySelectorAll('main section[id]'));
108
+
109
+ if (!sections.length) {
110
+ toc.remove();
111
+ return [];
112
+ }
113
+
114
+ const list = doc.createElement('ul');
115
+ list.className = 'toc-list';
116
+
117
+ sections.forEach((section) => {
118
+ const heading = section.querySelector('h2');
119
+
120
+ if (!heading) {
121
+ return;
122
+ }
123
+
124
+ const item = doc.createElement('li');
125
+ const link = doc.createElement('a');
126
+ link.href = `#${section.id}`;
127
+ link.textContent = heading.textContent.replace('#', '').trim();
128
+ link.dataset.tocLink = section.id;
129
+ item.appendChild(link);
130
+ list.appendChild(item);
131
+ });
132
+
133
+ toc.appendChild(list);
134
+ return sections;
135
+ }
136
+
137
+ function setupActiveLinks(sections) {
138
+ const sectionLinks = Array.from(doc.querySelectorAll('[data-section-link]'));
139
+ const tocLinks = Array.from(doc.querySelectorAll('[data-toc-link]'));
140
+
141
+ if (!sections.length || (!sectionLinks.length && !tocLinks.length)) {
142
+ return;
143
+ }
144
+
145
+ const setActive = (id) => {
146
+ sectionLinks.forEach((link) => {
147
+ link.classList.toggle('is-active', link.getAttribute('href') === `#${id}`);
148
+ });
149
+ tocLinks.forEach((link) => {
150
+ link.classList.toggle('is-active', link.dataset.tocLink === id);
151
+ });
152
+ };
153
+
154
+ const updateFromScroll = () => {
155
+ const offset = 120;
156
+ let current = sections[0];
157
+
158
+ sections.forEach((section) => {
159
+ if (section.getBoundingClientRect().top <= offset) {
160
+ current = section;
161
+ }
162
+ });
163
+
164
+ if (current?.id) {
165
+ setActive(current.id);
166
+ }
167
+ };
168
+
169
+ [...sectionLinks, ...tocLinks].forEach((link) => {
170
+ link.addEventListener('click', () => {
171
+ const targetId = link.getAttribute('href')?.slice(1);
172
+
173
+ if (targetId) {
174
+ setActive(targetId);
175
+ }
176
+ });
177
+ });
178
+
179
+ window.addEventListener('scroll', updateFromScroll, { passive: true });
180
+ window.addEventListener('hashchange', () => {
181
+ if (window.location.hash) {
182
+ setActive(window.location.hash.slice(1));
183
+ }
184
+ });
185
+
186
+ if (window.location.hash) {
187
+ setActive(window.location.hash.slice(1));
188
+ } else if (sections[0]) {
189
+ setActive(sections[0].id);
190
+ }
191
+
192
+ window.setTimeout(updateFromScroll, 150);
193
+ }
194
+
195
+ doc.addEventListener('DOMContentLoaded', () => {
196
+ enhanceCodeBlocks();
197
+ setupMobileNav();
198
+ setupHeadingLinks();
199
+ setupActiveLinks(buildToc());
200
+ });
201
+ })();
@@ -0,0 +1,10 @@
1
+ <svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="title desc">
2
+ <title id="title">Karrot mark</title>
3
+ <desc id="desc">A simple carrot-shaped mark for Karrot documentation.</desc>
4
+ <rect width="64" height="64" rx="16" fill="#12352B"/>
5
+ <path d="M33.7 16.2c2.8-5.5 8.2-6.9 13.4-5.9-1.1 5.4-4.2 9.8-10.3 10.5 3.7-2.6 5.6-5.8 6.4-8.2-3.2.4-6.3 1.9-8.2 5.8l-1.3-2.2Z" fill="#62C370"/>
6
+ <path d="M28.9 18.2c-1.5-4.5-5.7-7-10.7-7.5.4 5.1 3.5 9.4 8.5 11l2.2-3.5Z" fill="#8ED97E"/>
7
+ <path d="M20.2 23.5c-2.1 3-2 7.1.1 10.1l13 18.9c1.6 2.3 5 2.2 6.5-.2l11.7-19.7c1.9-3.2 1.4-7.3-1.2-10-7.7-7.9-23.3-8.1-30.1.9Z" fill="#F28C38"/>
8
+ <path d="M24.7 27.5c4.7-3.9 14.3-3.8 20.2.2" stroke="#FFE2C0" stroke-width="3" stroke-linecap="round"/>
9
+ <path d="M30.3 39.2c2.8 1.8 6.9 1.8 9.5-.1" stroke="#9D471C" stroke-width="3" stroke-linecap="round"/>
10
+ </svg>