coveragebook_components 0.7.10 → 0.8.0.beta.1

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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/build/coco/app.css +1065 -148
  3. data/app/assets/build/coco/app.js +255 -47
  4. data/app/assets/build/coco/book.css +26 -0
  5. data/app/assets/css/app/tippy.css +4 -0
  6. data/app/components/coco/app/blocks/header/header.css +43 -0
  7. data/app/components/coco/app/blocks/header/header.html.erb +30 -0
  8. data/app/components/coco/app/blocks/header/header.js +11 -0
  9. data/app/components/coco/app/blocks/header/header.rb +35 -0
  10. data/app/components/coco/app/blocks/nav_drawer/nav_drawer.css +48 -3
  11. data/app/components/coco/app/blocks/nav_drawer/nav_drawer.html.erb +14 -6
  12. data/app/components/coco/app/blocks/nav_drawer/nav_drawer.js +18 -1
  13. data/app/components/coco/app/blocks/nav_drawer/nav_drawer.rb +26 -1
  14. data/app/components/coco/app/blocks/sidebar_nav/sidebar_nav.css +104 -0
  15. data/app/components/coco/app/blocks/sidebar_nav/sidebar_nav.html.erb +42 -0
  16. data/app/components/coco/app/blocks/sidebar_nav/sidebar_nav.js +28 -0
  17. data/app/components/coco/app/blocks/sidebar_nav/sidebar_nav.rb +28 -0
  18. data/app/components/coco/app/blocks/sidebar_nav_item/sidebar_nav_item.css +165 -0
  19. data/app/components/coco/app/blocks/sidebar_nav_item/sidebar_nav_item.html.erb +43 -0
  20. data/app/components/coco/app/blocks/sidebar_nav_item/sidebar_nav_item.js +41 -0
  21. data/app/components/coco/app/blocks/sidebar_nav_item/sidebar_nav_item.rb +98 -0
  22. data/app/components/coco/app/elements/alert/alert.css +65 -18
  23. data/app/components/coco/app/elements/alert/alert.html.erb +4 -4
  24. data/app/components/coco/app/elements/alert/alert.js +4 -3
  25. data/app/components/coco/app/elements/alert/alert.rb +10 -0
  26. data/app/components/coco/app/elements/button/button.css +58 -0
  27. data/app/components/coco/app/elements/button/button.rb +1 -1
  28. data/app/components/coco/app/elements/button_group/button_group.rb +4 -0
  29. data/app/components/coco/app/elements/color_picker/color_picker.rb +1 -1
  30. data/app/components/coco/app/elements/menu/menu.css +1 -0
  31. data/app/components/coco/app/elements/menu/menu.html.erb +1 -1
  32. data/app/components/coco/app/elements/menu/menu.rb +2 -1
  33. data/app/components/coco/app/elements/menu_items/user_profile/user_profile.css +22 -0
  34. data/app/components/coco/app/elements/menu_items/user_profile/user_profile.html.erb +17 -0
  35. data/app/components/coco/app/elements/menu_items/user_profile/user_profile.rb +20 -0
  36. data/app/components/coco/app/elements/notice/notice.css +4 -0
  37. data/app/components/coco/app/elements/snackbar/snackbar.css +8 -1
  38. data/app/components/coco/app/elements/snackbar/snackbar.rb +2 -2
  39. data/app/components/coco/app/elements/system_banner/system_banner.html.erb +2 -1
  40. data/app/components/coco/app/elements/system_banner/system_banner.js +35 -2
  41. data/app/components/coco/app/elements/system_banner/system_banner.rb +47 -3
  42. data/app/components/coco/app/layouts/application/application.css +104 -4
  43. data/app/components/coco/app/layouts/application/application.html.erb +28 -7
  44. data/app/components/coco/app/layouts/application/application.js +16 -0
  45. data/app/components/coco/app/layouts/application/application.rb +11 -3
  46. data/app/components/coco/base/avatar/avatar.css +25 -0
  47. data/app/components/coco/base/avatar/avatar.rb +20 -0
  48. data/app/components/coco/base/modal/modal.html.erb +1 -1
  49. data/app/components/coco/concerns/accepts_tag_attributes.rb +6 -2
  50. data/app/components/coco/concerns/acts_as_button_group.rb +5 -0
  51. data/app/helpers/coco/app_helper.rb +16 -0
  52. data/app/helpers/coco/base_helper.rb +4 -0
  53. data/config/tokens.cjs +4 -1
  54. data/lib/coco.rb +1 -1
  55. metadata +22 -10
  56. data/app/components/coco/app/blocks/banner/banner.css +0 -5
  57. data/app/components/coco/app/blocks/banner/banner.rb +0 -8
  58. data/app/components/coco/app/blocks/nav_bar/nav_bar.css +0 -51
  59. data/app/components/coco/app/blocks/nav_bar/nav_bar.html.erb +0 -23
  60. data/app/components/coco/app/blocks/nav_bar/nav_bar.js +0 -31
  61. data/app/components/coco/app/blocks/nav_bar/nav_bar.rb +0 -19
@@ -4299,7 +4299,7 @@
4299
4299
  function toString(value) {
4300
4300
  return value == null ? "" : baseToString(value);
4301
4301
  }
4302
- var assign = createAssigner(function(object, source) {
4302
+ var assign2 = createAssigner(function(object, source) {
4303
4303
  if (isPrototype(source) || isArrayLike(source)) {
4304
4304
  copyObject(source, keys(source), object);
4305
4305
  return;
@@ -4611,7 +4611,7 @@
4611
4611
  position -= target.length;
4612
4612
  return position >= 0 && string.slice(position, end2) == target;
4613
4613
  }
4614
- function escape(string) {
4614
+ function escape2(string) {
4615
4615
  string = toString(string);
4616
4616
  return string && reHasUnescapedHtml.test(string) ? string.replace(reUnescapedHtml, escapeHtmlChar) : string;
4617
4617
  }
@@ -5049,7 +5049,7 @@
5049
5049
  }
5050
5050
  lodash.after = after;
5051
5051
  lodash.ary = ary;
5052
- lodash.assign = assign;
5052
+ lodash.assign = assign2;
5053
5053
  lodash.assignIn = assignIn;
5054
5054
  lodash.assignInWith = assignInWith;
5055
5055
  lodash.assignWith = assignWith;
@@ -5217,7 +5217,7 @@
5217
5217
  lodash.divide = divide;
5218
5218
  lodash.endsWith = endsWith;
5219
5219
  lodash.eq = eq;
5220
- lodash.escape = escape;
5220
+ lodash.escape = escape2;
5221
5221
  lodash.escapeRegExp = escapeRegExp;
5222
5222
  lodash.every = every;
5223
5223
  lodash.find = find;
@@ -6073,6 +6073,9 @@
6073
6073
  warning: __spreadValues({}, colors.amber),
6074
6074
  info: __spreadValues({}, colors.blue),
6075
6075
  background: {
6076
+ header: {
6077
+ DEFAULT: "#427484"
6078
+ },
6076
6079
  light: {
6077
6080
  1: colors.white,
6078
6081
  2: colors.gray[50],
@@ -6151,7 +6154,7 @@
6151
6154
  xl: "1200px",
6152
6155
  "2xl": "1400px",
6153
6156
  max: "1800px",
6154
- "small-landscape": { raw: "(max-height: 760px) and (min-width: 576px)" },
6157
+ letterbox: { raw: "(max-height: 760px) and (min-width: 576px)" },
6155
6158
  print: { raw: "print" }
6156
6159
  // Note: PDFs are rendered at a viewport width of 1280px
6157
6160
  };
@@ -14035,7 +14038,7 @@
14035
14038
  var package_default = {
14036
14039
  name: "coveragebook-components",
14037
14040
  type: "module",
14038
- version: "0.7.10",
14041
+ version: "0.8.0-beta.1",
14039
14042
  main: "index.js",
14040
14043
  repository: "git@github.com:coveragebook/coco.git",
14041
14044
  author: "Mark Perkins <mark@coveragebook.com>",
@@ -14056,6 +14059,7 @@
14056
14059
  "container-query-polyfill": "^1.0.2",
14057
14060
  del: "^7.0.0",
14058
14061
  html2canvas: "^1.4.1",
14062
+ "js-cookie": "^3.0.5",
14059
14063
  lodash: "^4.17.21",
14060
14064
  "lucide-static": "^0.258.0",
14061
14065
  tailwindcss: "^3.3.0",
@@ -20210,17 +20214,6 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
20210
20214
  var import_lodash = __toESM(require_lodash(), 1);
20211
20215
 
20212
20216
  // helpers/dom.js
20213
- function getHiddenElementDimensions(el, display = "block") {
20214
- let size2;
20215
- if (el.style.display === "none") {
20216
- el.style.display = display;
20217
- size2 = el.getBoundingClientRect();
20218
- el.style.display = "none";
20219
- } else {
20220
- size2 = el.getBoundingClientRect();
20221
- }
20222
- return size2;
20223
- }
20224
20217
  function castAttributeValue(value) {
20225
20218
  if (value === "false") {
20226
20219
  return false;
@@ -24160,45 +24153,111 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
24160
24153
  // book/components.js
24161
24154
  var components_default2 = registerComponents(__default2);
24162
24155
 
24163
- // ../../components/coco/app/blocks/nav_bar/nav_bar.js
24164
- var nav_bar_exports = {};
24165
- __export(nav_bar_exports, {
24166
- default: () => nav_bar_default
24156
+ // ../../components/coco/app/blocks/header/header.js
24157
+ var header_exports = {};
24158
+ __export(header_exports, {
24159
+ default: () => header_default
24160
+ });
24161
+ var header_default = CocoComponent("appHeader", () => {
24162
+ return {
24163
+ drawerOpen: false,
24164
+ toggleDrawer() {
24165
+ this.drawerOpen = !this.drawerOpen;
24166
+ }
24167
+ };
24168
+ });
24169
+
24170
+ // ../../components/coco/app/blocks/nav_drawer/nav_drawer.js
24171
+ var nav_drawer_exports = {};
24172
+ __export(nav_drawer_exports, {
24173
+ default: () => nav_drawer_default
24174
+ });
24175
+ var nav_drawer_default = CocoComponent("appNavDrawer", () => {
24176
+ return {
24177
+ active: false,
24178
+ init() {
24179
+ this.$watch("drawerOpen", (open) => {
24180
+ if (open) {
24181
+ this.$refs.content.scrollTop = 0;
24182
+ setTimeout(() => {
24183
+ this.active = true;
24184
+ }, 200);
24185
+ } else {
24186
+ this.active = false;
24187
+ }
24188
+ });
24189
+ },
24190
+ close() {
24191
+ this.drawerOpen = false;
24192
+ }
24193
+ };
24194
+ });
24195
+
24196
+ // ../../components/coco/app/blocks/sidebar_nav/sidebar_nav.js
24197
+ var sidebar_nav_exports = {};
24198
+ __export(sidebar_nav_exports, {
24199
+ default: () => sidebar_nav_default
24167
24200
  });
24168
24201
  var import_tokens = __toESM(require_tokens(), 1);
24169
- var nav_bar_default = CocoComponent("appNavBar", () => {
24170
- const mobileMaxWidth = parseInt(import_tokens.default.app.screens.md, 10);
24202
+ var mobileMaxWidth = parseInt(import_tokens.default.app.screens.sm, 10);
24203
+ var sidebar_nav_default = CocoComponent("appSidebarNav", () => {
24171
24204
  return {
24172
- mobile: true,
24205
+ sizeObserver: null,
24206
+ mobileLayout: true,
24173
24207
  init() {
24174
- const sizeObserver = new ResizeObserver(
24208
+ this.sizeObserver = new ResizeObserver(
24175
24209
  Alpine.throttle((entries) => {
24176
24210
  this.$nextTick(() => {
24177
- const navWidth = entries[0].contentRect.width;
24178
- const linksWidth = this.$refs.links.offsetWidth;
24179
- const primaryWidth = getHiddenElementDimensions(this.$refs.primaryLinks, "flex").width;
24180
- const secondaryWidth = getHiddenElementDimensions(
24181
- this.$refs.secondaryLinks,
24182
- "flex"
24183
- ).width;
24184
- const difference = linksWidth - primaryWidth - secondaryWidth;
24185
- this.mobile = navWidth < mobileMaxWidth || this.mobudifference <= 50;
24211
+ const bodyWidth = entries[0].contentRect.width;
24212
+ this.mobileLayout = bodyWidth < mobileMaxWidth;
24186
24213
  });
24187
24214
  }, 20)
24188
24215
  );
24189
- sizeObserver.observe(this.$root);
24216
+ this.sizeObserver.observe(document.documentElement);
24217
+ },
24218
+ destroy() {
24219
+ this.sizeObserver && this.sizeObserver.disconnect();
24190
24220
  }
24191
24221
  };
24192
24222
  });
24193
24223
 
24194
- // ../../components/coco/app/blocks/nav_drawer/nav_drawer.js
24195
- var nav_drawer_exports = {};
24196
- __export(nav_drawer_exports, {
24197
- default: () => nav_drawer_default
24224
+ // ../../components/coco/app/blocks/sidebar_nav_item/sidebar_nav_item.js
24225
+ var sidebar_nav_item_exports = {};
24226
+ __export(sidebar_nav_item_exports, {
24227
+ default: () => sidebar_nav_item_default
24198
24228
  });
24199
- var nav_drawer_default = CocoComponent("appNavDrawer", () => {
24229
+ var sidebar_nav_item_default = CocoComponent("appSidebarNavItem", () => {
24200
24230
  return {
24201
- open: false
24231
+ menu: null,
24232
+ init() {
24233
+ if (this.$refs.menu) {
24234
+ this.menu = tippy_default(this.$el, {
24235
+ theme: "coco-naked-dropdown",
24236
+ placement: this.menuPlacement,
24237
+ arrow: false,
24238
+ offset: [0, 0],
24239
+ trigger: "click",
24240
+ interactive: true,
24241
+ maxWidth: null,
24242
+ content: () => {
24243
+ return this.$refs.menu.innerHTML;
24244
+ }
24245
+ });
24246
+ }
24247
+ this.$watch("mobileLayout", () => {
24248
+ this.onOrientationChange();
24249
+ });
24250
+ },
24251
+ onOrientationChange() {
24252
+ if (this.menu) {
24253
+ this.menu.setProps({
24254
+ placement: this.menuPlacement
24255
+ });
24256
+ }
24257
+ },
24258
+ get menuPlacement() {
24259
+ return this.mobileLayout ? "top" : "right-start";
24260
+ }
24202
24261
  };
24203
24262
  });
24204
24263
 
@@ -24531,16 +24590,17 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
24531
24590
  }
24532
24591
  },
24533
24592
  remove() {
24593
+ this.$nextTick(() => this.$dispatch("alert:removed", { alert: this }));
24534
24594
  this.$root.remove();
24535
24595
  },
24536
24596
  checkSingleLineWrap({ height }) {
24537
- if (!this.forceMultiLine) {
24597
+ this.forceMultiLine = false;
24598
+ this.$nextTick(() => {
24538
24599
  this.forceMultiLine = height > 24 && this.$options.singleLine;
24539
- }
24600
+ });
24540
24601
  },
24541
24602
  root: {
24542
24603
  "x-options": '["dismissable", "singleLine"]',
24543
- "x-show": "!dismissed",
24544
24604
  ":class": "{'force-multi-line': forceMultiLine}"
24545
24605
  }
24546
24606
  };
@@ -26650,8 +26710,135 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
26650
26710
  __export(system_banner_exports, {
26651
26711
  default: () => system_banner_default
26652
26712
  });
26653
- var system_banner_default = CocoComponent("appSystemBanner", () => {
26654
- return {};
26713
+
26714
+ // ../../../node_modules/js-cookie/dist/js.cookie.mjs
26715
+ function assign(target) {
26716
+ for (var i3 = 1; i3 < arguments.length; i3++) {
26717
+ var source = arguments[i3];
26718
+ for (var key in source) {
26719
+ target[key] = source[key];
26720
+ }
26721
+ }
26722
+ return target;
26723
+ }
26724
+ var defaultConverter = {
26725
+ read: function(value) {
26726
+ if (value[0] === '"') {
26727
+ value = value.slice(1, -1);
26728
+ }
26729
+ return value.replace(/(%[\dA-F]{2})+/gi, decodeURIComponent);
26730
+ },
26731
+ write: function(value) {
26732
+ return encodeURIComponent(value).replace(
26733
+ /%(2[346BF]|3[AC-F]|40|5[BDE]|60|7[BCD])/g,
26734
+ decodeURIComponent
26735
+ );
26736
+ }
26737
+ };
26738
+ function init(converter, defaultAttributes) {
26739
+ function set3(name, value, attributes) {
26740
+ if (typeof document === "undefined") {
26741
+ return;
26742
+ }
26743
+ attributes = assign({}, defaultAttributes, attributes);
26744
+ if (typeof attributes.expires === "number") {
26745
+ attributes.expires = new Date(Date.now() + attributes.expires * 864e5);
26746
+ }
26747
+ if (attributes.expires) {
26748
+ attributes.expires = attributes.expires.toUTCString();
26749
+ }
26750
+ name = encodeURIComponent(name).replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent).replace(/[()]/g, escape);
26751
+ var stringifiedAttributes = "";
26752
+ for (var attributeName in attributes) {
26753
+ if (!attributes[attributeName]) {
26754
+ continue;
26755
+ }
26756
+ stringifiedAttributes += "; " + attributeName;
26757
+ if (attributes[attributeName] === true) {
26758
+ continue;
26759
+ }
26760
+ stringifiedAttributes += "=" + attributes[attributeName].split(";")[0];
26761
+ }
26762
+ return document.cookie = name + "=" + converter.write(value, name) + stringifiedAttributes;
26763
+ }
26764
+ function get3(name) {
26765
+ if (typeof document === "undefined" || arguments.length && !name) {
26766
+ return;
26767
+ }
26768
+ var cookies = document.cookie ? document.cookie.split("; ") : [];
26769
+ var jar = {};
26770
+ for (var i3 = 0; i3 < cookies.length; i3++) {
26771
+ var parts = cookies[i3].split("=");
26772
+ var value = parts.slice(1).join("=");
26773
+ try {
26774
+ var found = decodeURIComponent(parts[0]);
26775
+ jar[found] = converter.read(value, found);
26776
+ if (name === found) {
26777
+ break;
26778
+ }
26779
+ } catch (e3) {
26780
+ }
26781
+ }
26782
+ return name ? jar[name] : jar;
26783
+ }
26784
+ return Object.create(
26785
+ {
26786
+ set: set3,
26787
+ get: get3,
26788
+ remove: function(name, attributes) {
26789
+ set3(
26790
+ name,
26791
+ "",
26792
+ assign({}, attributes, {
26793
+ expires: -1
26794
+ })
26795
+ );
26796
+ },
26797
+ withAttributes: function(attributes) {
26798
+ return init(this.converter, assign({}, this.attributes, attributes));
26799
+ },
26800
+ withConverter: function(converter2) {
26801
+ return init(assign({}, this.converter, converter2), this.attributes);
26802
+ }
26803
+ },
26804
+ {
26805
+ attributes: { value: Object.freeze(defaultAttributes) },
26806
+ converter: { value: Object.freeze(converter) }
26807
+ }
26808
+ );
26809
+ }
26810
+ var api = init(defaultConverter, { path: "/" });
26811
+
26812
+ // ../../components/coco/app/elements/system_banner/system_banner.js
26813
+ var system_banner_default = CocoComponent("appSystemBanner", (opts = {}) => {
26814
+ return {
26815
+ cookieName: null,
26816
+ cookieValue: null,
26817
+ cookieExpiry: null,
26818
+ init() {
26819
+ this.cookieName = opts.cookieName;
26820
+ this.cookieValue = opts.cookieValue;
26821
+ this.cookieExpiry = opts.cookieExpiry;
26822
+ },
26823
+ onDismiss() {
26824
+ this.$dispatch("banner:dismiss", { banner: this });
26825
+ if (this.shouldSetCookie) {
26826
+ api.set(this.cookieName, this.cookieValue, {
26827
+ expires: this.cookieExpiry
26828
+ });
26829
+ }
26830
+ },
26831
+ remove() {
26832
+ this.$root.remove();
26833
+ },
26834
+ get shouldSetCookie() {
26835
+ return Number.isInteger(this.cookieExpiry);
26836
+ },
26837
+ root: {
26838
+ "@alert:dismiss": "onDismiss",
26839
+ "@alert:removed": "remove"
26840
+ }
26841
+ };
26655
26842
  });
26656
26843
 
26657
26844
  // ../../components/coco/app/elements/toast/toast.js
@@ -26724,8 +26911,26 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
26724
26911
  };
26725
26912
  });
26726
26913
 
26914
+ // ../../components/coco/app/layouts/application/application.js
26915
+ var application_exports = {};
26916
+ __export(application_exports, {
26917
+ default: () => application_default
26918
+ });
26919
+ var application_default = CocoComponent("appLayout", (opts) => {
26920
+ return {
26921
+ banner: false,
26922
+ init() {
26923
+ this.banner = opts.banner;
26924
+ },
26925
+ hideBanner() {
26926
+ this.banner = false;
26927
+ this.$el.remove();
26928
+ }
26929
+ };
26930
+ });
26931
+
26727
26932
  // import-glob:/Users/mark/Code/coveragebook/coco/app/assets/js/app|@appComponents/**/*.js
26728
- var modules3 = [nav_bar_exports, nav_drawer_exports, slide_editor_exports, alert_exports, button_group_exports, color_picker_exports, color_picker_button_exports, confirm_panel_exports, image_picker_exports, image_picker_button_exports, layout_picker_button_exports, menu_button_exports, notice_exports, seamless_textarea_exports, snackbar_exports, system_banner_exports, toast_exports, toolbar_exports];
26933
+ var modules3 = [header_exports, nav_drawer_exports, sidebar_nav_exports, sidebar_nav_item_exports, slide_editor_exports, alert_exports, button_group_exports, color_picker_exports, color_picker_button_exports, confirm_panel_exports, image_picker_exports, image_picker_button_exports, layout_picker_button_exports, menu_button_exports, notice_exports, seamless_textarea_exports, snackbar_exports, system_banner_exports, toast_exports, toolbar_exports, application_exports];
26729
26934
  var __default3 = modules3;
26730
26935
 
26731
26936
  // app/components.js
@@ -26785,4 +26990,7 @@ html2canvas/dist/html2canvas.js:
26785
26990
  * Licensed under MPL 2.0
26786
26991
  * github.com/jaames/iro.js
26787
26992
  *)
26993
+
26994
+ js-cookie/dist/js.cookie.mjs:
26995
+ (*! js-cookie v3.0.5 | MIT *)
26788
26996
  */
@@ -737,6 +737,32 @@ select {
737
737
  [data-coco] h6 {
738
738
  font-family: proxima-nova, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
739
739
  }
740
+ [data-coco][data-component="avatar"] {
741
+ display: block;
742
+ flex: none;
743
+ overflow: hidden;
744
+ border-radius: 9999px;
745
+ }
746
+ [data-coco][data-component="avatar"] img {
747
+ width: 100%;
748
+ border-radius: 9999px;
749
+ }
750
+ [data-coco][data-component="avatar"][data-size="sm"] {
751
+ height: 1.25rem;
752
+ width: 1.25rem;
753
+ }
754
+ [data-coco][data-component="avatar"][data-size="md"] {
755
+ height: 1.5rem;
756
+ width: 1.5rem;
757
+ }
758
+ [data-coco][data-component="avatar"][data-size="lg"] {
759
+ height: 1.75rem;
760
+ width: 1.75rem;
761
+ }
762
+ [data-coco][data-component="avatar"][data-size="xl"] {
763
+ height: 2rem;
764
+ width: 2rem;
765
+ }
740
766
  [data-coco].coco-button {
741
767
  display: flex;
742
768
  width: auto;
@@ -12,4 +12,8 @@
12
12
  .tippy-box[data-theme~="coco-app-menu"] {
13
13
  @apply tippy-dropdown-box;
14
14
  }
15
+
16
+ .tippy-box[data-theme~="coco-naked-dropdown"] {
17
+ width: min-content;
18
+ }
15
19
  }
@@ -0,0 +1,43 @@
1
+ @layer components {
2
+ [data-coco][data-component="app-header"] {
3
+ @apply @container;
4
+
5
+ .header-content {
6
+ @apply h-14 flex items-center bg-background-header px-app;
7
+ }
8
+
9
+ .header-logo {
10
+ @apply flex-none mr-6;
11
+ }
12
+
13
+ .header-logo-no-wordmark {
14
+ @apply h-7 xs:hidden translate-x-1;
15
+ }
16
+
17
+ .header-logo-full {
18
+ @apply hidden xs:block h-7;
19
+ }
20
+
21
+ .header-links {
22
+ @apply flex items-center w-full;
23
+ }
24
+
25
+ .header-link-group {
26
+ @apply items-center gap-x-6;
27
+ }
28
+
29
+ .header-secondary {
30
+ @apply ml-auto translate-x-2 sm:translate-x-[17px];
31
+ }
32
+
33
+ .header-mobile-controls {
34
+ @apply flex @4xl:hidden items-center ml-auto translate-x-2 sm:translate-x-4 md:translate-x-6;
35
+ }
36
+
37
+ &.with-nav-drawer {
38
+ .header-link-group {
39
+ @apply hidden @4xl:flex;
40
+ }
41
+ }
42
+ }
43
+ }
@@ -0,0 +1,30 @@
1
+ <%= render component_tag(
2
+ x: {data: "appHeader", "bind:class": "{'drawer-open': drawerOpen}"},
3
+ class: {"with-nav-drawer": mobile_nav?}
4
+ ) do %>
5
+ <div class="header-content">
6
+ <%= tag.send(home_path ? :a : :div, class: "header-logo", href: home_path) do %>
7
+ <%= image_tag asset_url("coco/img/coveragebook-logomark-white.svg"),
8
+ alt: "CoverageBook logomark",
9
+ class: "header-logo-no-wordmark" %>
10
+ <%= image_tag asset_url("coco/img/coveragebook-landscape-white.svg"),
11
+ alt: "CoverageBook full logo",
12
+ class: "header-logo-full" %>
13
+ <% end %>
14
+ <nav class="header-links" x-ref="links">
15
+ <div class="header-link-group header-primary" x-ref="primaryLinks">
16
+ <%= primary_nav %>
17
+ </div>
18
+ <div class="header-link-group header-secondary" x-ref="secondaryLinks">
19
+ <%= secondary_nav %>
20
+ </div>
21
+ <% if mobile_nav? %>
22
+ <div class="header-mobile-controls">
23
+ <%= coco_button(icon: :menu, theme: :text_neutral_light, size: :md, click: "toggleDrawer", x: {show: "!drawerOpen"}) %>
24
+ <%= coco_button(icon: :x, theme: :text_neutral_light, size: :md, click: "toggleDrawer", x: {show: "drawerOpen", cloak: true}) %>
25
+ </div>
26
+ <% end %>
27
+ </nav>
28
+ </div>
29
+ <%= mobile_nav %>
30
+ <% end %>
@@ -0,0 +1,11 @@
1
+ import { CocoComponent } from "@js/coco";
2
+
3
+ export default CocoComponent("appHeader", () => {
4
+ return {
5
+ drawerOpen: false,
6
+
7
+ toggleDrawer() {
8
+ this.drawerOpen = !this.drawerOpen;
9
+ },
10
+ };
11
+ });
@@ -0,0 +1,35 @@
1
+ module Coco
2
+ module App
3
+ module Blocks
4
+ class Header < Coco::Component
5
+ renders_one :primary_nav, ->(**kwargs) do
6
+ Coco::App::Elements::ButtonGroup.new(
7
+ theme: :text_neutral_light,
8
+ collapsible: false,
9
+ size: :sm,
10
+ **kwargs
11
+ )
12
+ end
13
+
14
+ renders_one :secondary_nav, ->(**kwargs) do
15
+ Coco::App::Elements::ButtonGroup.new(
16
+ theme: :text_neutral_light,
17
+ collapsible: false,
18
+ size: :sm,
19
+ **kwargs
20
+ )
21
+ end
22
+
23
+ renders_one :mobile_nav, ->(**kwargs) do
24
+ Coco::App::Blocks::NavDrawer.new(**kwargs)
25
+ end
26
+
27
+ attr_reader :home_path
28
+
29
+ def initialize(home_path: nil, **)
30
+ @home_path = home_path
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,9 +1,54 @@
1
1
  @layer components {
2
2
  [data-coco][data-component="app-nav-drawer"] {
3
- @apply fixed top-0 left-0 bottom-0 h-screen w-[340px] bg-white shadow-2xl overflow-hidden;
3
+ @apply pointer-events-none fixed top-14 left-0 bottom-0 w-screen overflow-hidden;
4
+ height: var(--app-height);
4
5
 
5
- .nav-inner {
6
- @apply p-4;
6
+ .nav-drawer-overlay {
7
+ @apply pointer-events-none absolute inset-0 bg-black opacity-0 transition-opacity;
8
+ }
9
+
10
+ .nav-drawer-content {
11
+ @apply absolute top-0 right-0 bottom-0 bg-white overflow-auto translate-x-full transition-transform py-4;
12
+ max-width: 340px;
13
+ min-width: 280px;
14
+ width: fit-content;
15
+ }
16
+
17
+ .nav-drawer-item:last-child {
18
+ @apply mb-10;
19
+ }
20
+
21
+ .nav-drawer-button {
22
+ @apply w-full text-content-dark-2 hover:text-content-dark-1 hover:bg-background-light-3;
23
+
24
+ .button-inner {
25
+ @apply mx-0 px-4 py-3;
26
+ }
27
+ }
28
+
29
+ .nav-drawer-heading {
30
+ @apply mt-4 mb-2 mx-4 border-b text-content-dark-1/50 border-gray-300 pb-3;
31
+ }
32
+
33
+ .nav-drawer-divider {
34
+ @apply h-0 border-t border-gray-300 my-3;
35
+ }
36
+
37
+ [data-component="app-notice"] {
38
+ @apply mb-4;
39
+ }
40
+
41
+ .drawer-open & {
42
+ @apply pointer-events-auto;
43
+
44
+ .nav-drawer-overlay {
45
+ @apply pointer-events-auto opacity-60;
46
+ backdrop-filter: blur(2px);
47
+ }
48
+
49
+ .nav-drawer-content {
50
+ @apply pointer-events-auto translate-x-0 shadow-2xl;
51
+ }
7
52
  }
8
53
  }
9
54
  }
@@ -1,8 +1,16 @@
1
- <%= render component_tag(x: { data: "appNavDrawer" }) do %>
2
- <div class="nav-inner">
3
- <div class="nav-header">
4
- <%= coco_button(icon: :x, theme: nil) %>
5
- </div>
6
- <%= content %>
1
+ <%= render component_tag(
2
+ x: {
3
+ data: "appNavDrawer",
4
+ "@keydown.escape.document": "close",
5
+ "@resize.window": "close"
6
+ }
7
+ ) do %>
8
+ <div class="nav-drawer-overlay" @click="close"></div>
9
+ <div class="nav-drawer-content" x-ref="content" x-trap.noscroll.inert.noreturn="active">
10
+ <% items.each do |item| %>
11
+ <div class="nav-drawer-item">
12
+ <%= item %>
13
+ </div>
14
+ <% end %>
7
15
  </div>
8
16
  <% end %>
@@ -2,6 +2,23 @@ import { CocoComponent } from "@js/coco";
2
2
 
3
3
  export default CocoComponent("appNavDrawer", () => {
4
4
  return {
5
- open: false,
5
+ active: false,
6
+
7
+ init() {
8
+ this.$watch("drawerOpen", (open) => {
9
+ if (open) {
10
+ this.$refs.content.scrollTop = 0;
11
+ setTimeout(() => {
12
+ this.active = true;
13
+ }, 200);
14
+ } else {
15
+ this.active = false;
16
+ }
17
+ });
18
+ },
19
+
20
+ close() {
21
+ this.drawerOpen = false;
22
+ },
6
23
  };
7
24
  });