@columbia-libraries/cul-toolkit 5.0.5 → 5.2.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.
package/README.md CHANGED
@@ -2,43 +2,44 @@
2
2
 
3
3
  _Version 5.x_
4
4
 
5
- ## Development requirements
5
+ ## Requirements
6
6
  ```
7
- nodejs >= v20
8
- npm >= 10.2
7
+ nodejs >= v22
9
8
  ```
10
9
 
11
- ## Vite for development
12
- Dev server runs on http://localhost:8181 and auto-recompiles code when resources change.
10
+ ## Development
11
+ Start the Vite dev server:
13
12
  ```
14
- npm start
13
+ npm run dev
15
14
  ```
16
- Preview server runs on http://localhost:4173 and serves the built dist/ dir.
15
+ The app is available at http://localhost:5173
16
+
17
+ ## Preview production build
18
+ Serve the production build locally:
17
19
  ```
18
20
  npm run preview
19
21
  ```
20
22
 
21
- ## Vite Build Instructions
22
- Vite will bundle code and copy public/ files for distribution into the dist/ dir.
23
- ```
24
- npm install # run the first time you want to build, or if the package-lock.json file has changed
25
- ```
26
- ```
23
+ ## Build
24
+ Install dependencies and build:
25
+ ```bash
26
+ npm install
27
27
  npm run build
28
28
  ```
29
+ The output is written to the dist/ directory.
29
30
 
30
31
  ## Deployment requirements
31
32
 
32
33
  Local machine:
33
34
  ```
34
- ruby >= 2.5.3 (we currently have a .ruby-version file requiring 2.5.3)
35
+ ruby >= 2.7.5 (we currently have a .ruby-version file requiring 2.7.5)
35
36
  bundler
36
37
  ```
37
38
 
38
39
  Remote deployment server:
39
40
  ```
40
- node >= 10.17.0
41
- yarn >= 1.19.1
41
+ node >= 22
42
+ npm >= 10
42
43
  ```
43
44
  ## Deploying a versioned release
44
45
 
@@ -59,3 +60,247 @@ cap dev deploy # or replace "dev" with "test" or "prod"
59
60
 
60
61
  Note: In order to deploy, you need to have your public key in the remote server user's authorized_keys file on your dev/test/prod hosts.
61
62
 
63
+
64
+ ---
65
+
66
+ ## CUL Menu Usage
67
+
68
+ CUL Menu is a portable BS5-compatible menu system that renders two styles of navigational menus from an authoritative JSON data source.
69
+
70
+ Purpose:
71
+
72
+ * **Menu content changes more often than apps**
73
+ * Avoid editing/redeploying multiple sites for a simple label or link change
74
+ * Centralized menu control
75
+ * Safe degradation when offline or blocked by CORS
76
+
77
+ Supports:
78
+
79
+ * **Runtime menu updates** (no rebuild required)
80
+ * **Graceful fallback** to a bundled example menu
81
+ * **Multiple render styles** (vertical collapse menu (CUL global menu / v5 theme), navbar (lweb v3 style))
82
+
83
+ Features:
84
+
85
+ * Fetch menu JSON from **remote authoritative source**
86
+ * Fallback to a **bundled example menu** if remote fails
87
+ * Cache-busting via app version
88
+ * Works in: Dynamic/JS apps, Static HTML pages, WP themes, etc.
89
+
90
+ Requirements:
91
+
92
+ * Bootstrap 5 CSS (**part of CUL Toolkit v5!**)
93
+ * Bootstrap 5 JS (dropdowns / collapse) (**part of CUL Toolkit v5!**)
94
+ * Modern browser (ES2019+)
95
+
96
+ ---
97
+
98
+ ### CUL Menu JSON Format
99
+
100
+ ```json
101
+ {
102
+ "Services & Tools": [
103
+ {
104
+ "href": "https://library.columbia.edu/services.html",
105
+ "value": "Services & Tools"
106
+ },
107
+ ],
108
+ "Libraries": [
109
+ {
110
+ "href": "https://library.columbia.edu/libraries.html",
111
+ "value": "Libraries & Affiliates"
112
+ },
113
+ {
114
+ "href": "https://library.columbia.edu/libraries/avery.html",
115
+ "value": "Avery Architectural & Fine Arts Library"
116
+ },
117
+ ]
118
+ }
119
+ ```
120
+
121
+ ### Usage in this app (CUL Toolkit examples, etc)
122
+
123
+ #### Environmental Variable
124
+
125
+ Create root `.env`:
126
+
127
+ ```env
128
+ VITE_CUL_MENU_URL=https://toolkit.library.columbia.edu/v5/assets/cul-main-menu.json
129
+ ```
130
+
131
+ #### main.js
132
+
133
+ ```js
134
+ import { makeCULmenu } from './culmenu.js';
135
+ import { makeCULNavbarMenu } from './culmenu-navbar.js';
136
+
137
+ const MENU_URL = import.meta.env.VITE_CUL_MENU_URL || undefined;
138
+
139
+ makeCULmenu(MENU_URL);
140
+ makeCULNavbarMenu('[data-cul-navbar]', MENU_URL);
141
+ ```
142
+
143
+ ---
144
+
145
+ ### Markup
146
+
147
+ #### Vertical / Collapse Menu
148
+
149
+ ```html
150
+ <nav data-cul-menu class="cul-menu-loading"></nav>
151
+ ```
152
+
153
+ #### Navbar / Dropdown Menu
154
+
155
+ ```html
156
+ <nav
157
+ class="navbar navbar-expand-lg cul-menu-loading"
158
+ data-cul-navbar
159
+ data-menu-id="main"
160
+ >
161
+ <ul class="navbar-nav"></ul>
162
+ </nav>
163
+ ```
164
+
165
+ The JS will replace the contents at runtime.
166
+
167
+ ---
168
+
169
+ ### Loading & Fallback Behavior
170
+
171
+ 1. Attempt to fetch menu from:
172
+
173
+ * `VITE_CUL_MENU_URL` (if provided)
174
+ 2. If fetch fails:
175
+
176
+ * Use bundled example menu (`cul-main-menu.json`)
177
+ 3. Cache-busting is applied using app version
178
+
179
+ Console warning when fallback is used:
180
+
181
+ ```
182
+ [CUL Menu] Remote menu unavailable, using bundled example.
183
+ ```
184
+
185
+ ---
186
+
187
+ ### Using the Bundle on Another Site
188
+
189
+ Standalone bundle:
190
+
191
+ * `cul-menu.bundle.js` (IIFE, for `<script>` tags)
192
+ * `cul-menu.bundle.es.js` (ES module)
193
+
194
+ #### Example static HTML / IIFE usage
195
+
196
+ ```html
197
+ <link rel="stylesheet" href="https://toolkit.library.columbia.edu/v5/setup.css">
198
+
199
+ <nav data-cul-menu></nav>
200
+
201
+ <script src="https://toolkit.library.columbia.edu/v5/bundles/cul-menu.bundle.js"></script>
202
+ <script>
203
+ CULMenu.initCollapse({
204
+ url: 'https://toolkit.library.columbia.edu/v5/assets/cul-main-menu.json'
205
+ });
206
+ </script>
207
+ ```
208
+
209
+ *Note: script/JSON URLs can be local or remote or mixed.*
210
+
211
+ ---
212
+
213
+ #### ES module app usage
214
+
215
+ *Installation*
216
+
217
+ ```bash
218
+ npm install @columbia-libraries/cul-toolkit
219
+ ```
220
+
221
+ *Import and usage*
222
+
223
+ ```js
224
+ import '@columbia-libraries/cul-toolkit/styles';
225
+ import '@columbia-libraries/cul-toolkit/setup';
226
+
227
+ import { makeCULmenu } from '@columbia-libraries/cul-toolkit';
228
+
229
+ const MENU_URL =
230
+ import.meta.env.VITE_CUL_MENU_URL ||
231
+ 'https://toolkit.library.columbia.edu/v5/assets/cul-main-menu.json';
232
+
233
+ makeCULmenu(MENU_URL);
234
+ ```
235
+
236
+ *Framework Notes*
237
+
238
+ makeCULmenu(MENU_URL) manipulates DOM elements with [data-cul-menu].
239
+ It must be called after the elements exist in the DOM:
240
+
241
+ - Vue: call after app.mount() or inside onMounted() / nextTick().
242
+ - React: call inside useEffect(() => { ... }, []).
243
+
244
+ *Vue note:*
245
+ ```js
246
+ import { createApp, nextTick } from 'vue';
247
+ import App from './App.vue';
248
+ import { makeCULmenu } from '@columbia-libraries/cul-toolkit';
249
+
250
+ const app = createApp(App);
251
+
252
+ // for after app is mounted:
253
+ app.mount('#app');
254
+ nextTick(() => {
255
+ makeCULmenu(MENU_URL);
256
+ });
257
+
258
+ // or for inside a component:
259
+ onMounted(() => {
260
+ makeCULmenu(MENU_URL);
261
+ });
262
+ ```
263
+
264
+ *React/other frameworks:*
265
+
266
+ Call after the component that contains [data-my-menu] has mounted.
267
+
268
+ *Markup requirement*
269
+
270
+ Must include target element: <nav data-my-menu></nav>
271
+
272
+ ---
273
+
274
+ #### Available Globals
275
+
276
+ - CULMenu.initCollapse({ url });
277
+ - CULMenu.initNavbar({ selector, url });
278
+
279
+ ---
280
+
281
+ ### Build Output (npm package)
282
+
283
+ ```bash
284
+ dist/
285
+ ├── assets/
286
+ │   ├── columbia_crown_logo-square-135x135.svg
287
+ │   ├── cul-main-menu.json
288
+ │   ├── cul-text-logo.svg
289
+ │   ├── favicon.ico
290
+ │   ├── main.css
291
+ │   └── main.js
292
+ ├── bundles/
293
+ │   ├── cul-menu.bundle.es.js
294
+ │   ├── cul-menu.bundle.es.js.map
295
+ │   ├── cul-menu.bundle.js
296
+ │   └── cul-menu.bundle.js.map
297
+ ├── js/
298
+ │   ├── quicksearch.js
299
+ │   └── typeahead-0.11.1.bundle.min.js
300
+ ├── setup.css
301
+ └── setup.js
302
+ ```
303
+
304
+ ---
305
+
306
+
@@ -0,0 +1,234 @@
1
+ {
2
+ "Services & Tools": [
3
+ {
4
+ "href": "https://library.columbia.edu/services.html",
5
+ "value": "Services & Tools"
6
+ },
7
+ {
8
+ "href": "https://library.columbia.edu/using-libraries/alumni.html",
9
+ "value": "For Alumni"
10
+ },
11
+ {
12
+ "href": "https://library.columbia.edu/services/faculty.html",
13
+ "value": "For Faculty"
14
+ },
15
+ {
16
+ "href": "https://library.columbia.edu/services.html#audience=student",
17
+ "value": "For Students"
18
+ },
19
+ {
20
+ "href": "https://library.columbia.edu/using-libraries/visitors.html",
21
+ "value": "For Visitors"
22
+ }
23
+ ],
24
+ "Libraries": [
25
+ {
26
+ "href": "https://library.columbia.edu/libraries.html",
27
+ "value": "Libraries & Affiliates"
28
+ },
29
+ {
30
+ "href": "https://library.columbia.edu/libraries/avery.html",
31
+ "value": "Avery Architectural & Fine Arts Library"
32
+ },
33
+ {
34
+ "href": "https://library.columbia.edu/libraries/burke.html",
35
+ "value": "Burke Library at Union Theological Seminary"
36
+ },
37
+ {
38
+ "href": "https://library.columbia.edu/libraries/business.html",
39
+ "value": "Business & Economics Library in Uris"
40
+ },
41
+ {
42
+ "href": "https://library.columbia.edu/libraries/business-manhattanville.html",
43
+ "value": "Business Library at Manhattanville"
44
+ },
45
+ {
46
+ "href": "https://library.columbia.edu/libraries/butler.html",
47
+ "value": "Butler Library"
48
+ },
49
+ {
50
+ "href": "https://library.columbia.edu/libraries/eastasian.html",
51
+ "value": "C.V. Starr East Asian Library"
52
+ },
53
+ {
54
+ "href": "https://library.columbia.edu/libraries/music.html",
55
+ "value": "Gabe M. Wiener Music & Arts Library"
56
+ },
57
+ {
58
+ "href": "https://library.cumc.columbia.edu/",
59
+ "value": "Health Sciences Library"
60
+ },
61
+ {
62
+ "href": "https://library.columbia.edu/libraries/journalism.html",
63
+ "value": "Journalism Library"
64
+ },
65
+ {
66
+ "href": "https://library.columbia.edu/libraries/lehman.html",
67
+ "value": "Lehman Social Sciences Library"
68
+ },
69
+ {
70
+ "href": "http://www.law.columbia.edu/library/",
71
+ "value": "Li Lu Law Library"
72
+ },
73
+ {
74
+ "href": "https://library.columbia.edu/libraries/math.html",
75
+ "value": "Mathematics Library"
76
+ },
77
+ {
78
+ "href": "https://library.columbia.edu/libraries/rbml.html",
79
+ "value": "Rare Book & Manuscript Library"
80
+ },
81
+ {
82
+ "href": "https://library.columbia.edu/libraries/science-engineering.html",
83
+ "value": "Science & Engineering Library"
84
+ },
85
+ {
86
+ "href": "https://library.columbia.edu/libraries/social-work.html",
87
+ "value": "Social Work Library"
88
+ }
89
+ ],
90
+ "Collections": [
91
+ {
92
+ "href": "https://library.columbia.edu/collections.html",
93
+ "value": "About Our Collections"
94
+ },
95
+ {
96
+ "href": "https://academiccommons.columbia.edu/",
97
+ "value": "Academic Commons"
98
+ },
99
+ {
100
+ "href": "https://library.columbia.edu/collections/archives-portal.html",
101
+ "value": "Archival Collections"
102
+ },
103
+ {
104
+ "href": "https://resolver.library.columbia.edu/clio",
105
+ "value": "CLIO: Columbia Libraries Catalog"
106
+ },
107
+ {
108
+ "href": "https://library.columbia.edu/about/policies/collection-development.html",
109
+ "value": "Collection Development"
110
+ },
111
+ {
112
+ "href": "https://dlc.library.columbia.edu",
113
+ "value": "Digital Collections"
114
+ },
115
+ {
116
+ "href": "https://library.columbia.edu/collections/eresources.html",
117
+ "value": "E-Resources"
118
+ },
119
+ {
120
+ "href": "https://resolver.library.columbia.edu/lweb0004",
121
+ "value": "Recommend a Title for Purchase"
122
+ },
123
+ {
124
+ "href": "https://library.columbia.edu/about/policies/collection-development/repatriation-return.html",
125
+ "value": "Repatriation"
126
+ },
127
+ {
128
+ "href": "https://library.columbia.edu/about/staff/subject-specialists-by-subject.html",
129
+ "value": "Subject Specialists"
130
+ }
131
+ ],
132
+ "Using the Libraries": [
133
+ {
134
+ "href": "https://library.columbia.edu/using-libraries.html",
135
+ "value": "Using the Libraries"
136
+ },
137
+ {
138
+ "href": "https://library.columbia.edu/using-libraries/access-privileges.html",
139
+ "value": "Access Privileges"
140
+ },
141
+ {
142
+ "href": "https://library.columbia.edu/using-libraries/disability.html",
143
+ "value": "Accessibility"
144
+ },
145
+ {
146
+ "href": "https://library.columbia.edu/using-libraries/borrowing.html",
147
+ "value": "Borrow, Request, Renew"
148
+ },
149
+ {
150
+ "href": "https://library.columbia.edu/services/reserves.html",
151
+ "value": "Course Reserves"
152
+ },
153
+ {
154
+ "href": "https://hours.library.columbia.edu/",
155
+ "value": "Hours"
156
+ },
157
+ {
158
+ "href": "https://library.columbia.edu/using-libraries/printing.html",
159
+ "value": "Print, Scan, Digitize"
160
+ }
161
+ ],
162
+ "Research & Teaching": [
163
+ {
164
+ "href": "https://library.columbia.edu/research-teaching.html",
165
+ "value": "Research & Teaching"
166
+ },
167
+ {
168
+ "href": "https://library.columbia.edu/research-teaching/copyright.html",
169
+ "value": "Copyright Information"
170
+ },
171
+ {
172
+ "href": "https://library.columbia.edu/research-teaching/getting-started.html",
173
+ "value": "Getting Started with the Libraries"
174
+ },
175
+ {
176
+ "href": "https://library.columbia.edu/research-teaching/global.html",
177
+ "value": "Global Studies"
178
+ },
179
+ {
180
+ "href": "https://library.columbia.edu/research-teaching/open-scholarship.html",
181
+ "value": "Open Scholarship Services"
182
+ },
183
+ {
184
+ "href": "https://library.columbia.edu/services/research-data-services.html",
185
+ "value": "Research Data Services"
186
+ },
187
+ {
188
+ "href": "https://library.columbia.edu/services/subject-guides.html",
189
+ "value": "Subject & Course Guides"
190
+ },
191
+ {
192
+ "href": "https://library.columbia.edu/research-teaching/workshops.html",
193
+ "value": "Workshops & Training"
194
+ }
195
+ ],
196
+ "About": [
197
+ {
198
+ "href": "https://library.columbia.edu/about.html",
199
+ "value": "About the Libraries"
200
+ },
201
+ {
202
+ "href": "https://library.columbia.edu/about/jobs-internships.html",
203
+ "value": "Jobs & Internships"
204
+ },
205
+ {
206
+ "href": "https://library.columbia.edu/about/news/alert.html",
207
+ "value": "Library Status Updates"
208
+ },
209
+ {
210
+ "href": "https://library.columbia.edu/about/news.html",
211
+ "value": "News"
212
+ },
213
+ {
214
+ "href": "https://library.columbia.edu/about/values.html",
215
+ "value": "Our Values & Commitment in Action"
216
+ },
217
+ {
218
+ "href": "https://library.columbia.edu/about/policies.html",
219
+ "value": "Policies"
220
+ },
221
+ {
222
+ "href": "https://library.columbia.edu/about/staff.html",
223
+ "value": "Staff"
224
+ },
225
+ {
226
+ "href": "https://strategicdirections.library.columbia.edu/",
227
+ "value": "Strategic Directions"
228
+ },
229
+ {
230
+ "href": "https://library.columbia.edu/about/student_advisory_committee.html",
231
+ "value": "Student Library Advisory Committee"
232
+ }
233
+ ]
234
+ }