coveragebook_components 0.7.10 → 0.8.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
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
  });