nitro_rails 0.1.0 → 0.1.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 (103) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +18 -0
  3. data/app/assets/audio/mousetap.mp3 +0 -0
  4. data/app/assets/config/nitro_rails_manifest.js +2 -0
  5. data/app/assets/javascript/nitro_rails/application.js +4 -0
  6. data/app/assets/javascript/nitro_rails/controllers/application.js +9 -0
  7. data/app/assets/javascript/nitro_rails/controllers/audio_controller.js +16 -0
  8. data/app/assets/javascript/nitro_rails/controllers/clock_controller.js +21 -0
  9. data/app/assets/javascript/nitro_rails/controllers/editable_text_controller.js +61 -0
  10. data/app/assets/javascript/nitro_rails/controllers/index.js +21 -0
  11. data/app/assets/javascript/nitro_rails/controllers/nitro_collection_controller.js +127 -0
  12. data/app/assets/javascript/nitro_rails/controllers/nitro_controller.js +35 -0
  13. data/app/assets/javascript/nitro_rails/controllers/nitro_form_controller.js +81 -0
  14. data/app/assets/javascript/nitro_rails/controllers/panel_controller.js +70 -0
  15. data/app/assets/javascript/nitro_rails/controllers/panel_manager_controller.js +89 -0
  16. data/app/assets/javascript/nitro_rails/controllers/tabs_controller.js +81 -0
  17. data/app/assets/javascript/nitro_rails/controllers/time_zone_controller.js +47 -0
  18. data/app/assets/javascript/nitro_rails/controllers/togglable_checkbox_controller.js +9 -0
  19. data/app/assets/javascript/nitro_rails/helpers/device_info_helper.js +99 -0
  20. data/app/assets/javascript/nitro_rails/helpers/screen_info_helper.js +20 -0
  21. data/app/assets/javascript/nitro_rails/turbo_streams/clear_errors.js +22 -0
  22. data/app/assets/javascript/nitro_rails/turbo_streams/focus.js +8 -0
  23. data/app/assets/javascript/nitro_rails/turbo_streams/index.js +8 -0
  24. data/app/assets/javascript/nitro_rails/turbo_streams/insert.js +10 -0
  25. data/app/assets/javascript/nitro_rails/turbo_streams/redirect.js +10 -0
  26. data/app/assets/javascript/nitro_rails/turbo_streams/refresh_frame.js +9 -0
  27. data/app/assets/javascript/nitro_rails/turbo_streams/render_errors.js +26 -0
  28. data/app/assets/javascript/nitro_rails/turbo_streams/toggle_checkbox.js +9 -0
  29. data/app/assets/javascript/nitro_rails/turbo_streams/toggle_class.js +14 -0
  30. data/app/assets/stylesheets/nitro_rails/__reset.css +25 -0
  31. data/app/assets/stylesheets/nitro_rails/_base/_color.css +24 -0
  32. data/app/assets/stylesheets/nitro_rails/_base/_font.css +35 -0
  33. data/app/assets/stylesheets/nitro_rails/_base/_format.css +38 -0
  34. data/app/assets/stylesheets/nitro_rails/_base/_grayscale.css +79 -0
  35. data/app/assets/stylesheets/nitro_rails/_base/_utility.css +34 -0
  36. data/app/assets/stylesheets/nitro_rails/application.css +23 -0
  37. data/app/assets/stylesheets/nitro_rails/modules/action-navigation.css +24 -0
  38. data/app/assets/stylesheets/nitro_rails/modules/alert.css +31 -0
  39. data/app/assets/stylesheets/nitro_rails/modules/btn.css +57 -0
  40. data/app/assets/stylesheets/nitro_rails/modules/checkbox.css +42 -0
  41. data/app/assets/stylesheets/nitro_rails/modules/clickable.css +9 -0
  42. data/app/assets/stylesheets/nitro_rails/modules/clock.css +0 -0
  43. data/app/assets/stylesheets/nitro_rails/modules/editable-text.css +45 -0
  44. data/app/assets/stylesheets/nitro_rails/modules/forms.css +108 -0
  45. data/app/assets/stylesheets/nitro_rails/modules/hover-reveal.css +11 -0
  46. data/app/assets/stylesheets/nitro_rails/modules/inline-svg.css +14 -0
  47. data/app/assets/stylesheets/nitro_rails/modules/list.css +29 -0
  48. data/app/assets/stylesheets/nitro_rails/modules/main-navigation.css +20 -0
  49. data/app/assets/stylesheets/nitro_rails/modules/nitro-checkbox.css +42 -0
  50. data/app/assets/stylesheets/nitro_rails/modules/resource-collection.css +12 -0
  51. data/app/assets/stylesheets/nitro_rails/modules/search-bar.css +36 -0
  52. data/app/assets/stylesheets/nitro_rails/modules/settings.css +33 -0
  53. data/app/assets/stylesheets/nitro_rails/modules/tabs.css +38 -0
  54. data/app/assets/stylesheets/nitro_rails/modules/toggle-switch.css +60 -0
  55. data/app/assets/stylesheets/nitro_rails/panels/bound-card-dropdown-panel.css +0 -0
  56. data/app/assets/stylesheets/nitro_rails/panels/card-panel.css +0 -0
  57. data/app/assets/stylesheets/nitro_rails/panels/embedded-panel.css +31 -0
  58. data/app/assets/stylesheets/nitro_rails/panels/panel-display.css +111 -0
  59. data/app/assets/stylesheets/nitro_rails/panels/popup-panel.css +123 -0
  60. data/app/assets/stylesheets/nitro_rails/panels/side-panel.css +0 -0
  61. data/app/controllers/nitro_rails/sequence_controller.rb +64 -0
  62. data/app/helpers/nitro_rails/application_helper.rb +42 -1
  63. data/app/helpers/nitro_rails/color_helper.rb +23 -0
  64. data/app/helpers/nitro_rails/components_helper.rb +49 -0
  65. data/app/helpers/nitro_rails/inline_edit_helper.rb +48 -0
  66. data/app/helpers/nitro_rails/nitro_action_helper.rb +178 -0
  67. data/app/helpers/nitro_rails/nitro_collection_helper.rb +87 -0
  68. data/app/helpers/nitro_rails/nitro_edit_helper.rb +15 -0
  69. data/app/helpers/nitro_rails/nitro_form_helper.rb +104 -0
  70. data/app/helpers/nitro_rails/nitro_options_helper.rb +78 -0
  71. data/app/helpers/nitro_rails/nitro_tag_helper.rb +183 -0
  72. data/app/helpers/nitro_rails/panel_helper.rb +65 -0
  73. data/app/helpers/nitro_rails/resource_collection_helper.rb +66 -0
  74. data/app/helpers/nitro_rails/tabs_helper.rb +51 -0
  75. data/app/helpers/nitro_rails/turbo_stream_helper.rb +46 -0
  76. data/app/lib/nitro_rails/local_time.rb +51 -0
  77. data/app/lib/nitro_rails/performable_routes.rb +24 -0
  78. data/app/lib/nitro_rails/resource_collection.rb +183 -0
  79. data/app/lib/nitro_rails/sequential_routes.rb +36 -0
  80. data/app/lib/nitro_rails/time_interval.rb +88 -0
  81. data/app/lib/nitro_rails/time_string.rb +22 -0
  82. data/app/models/nitro_rails/broadcast.rb +76 -0
  83. data/app/models/nitro_rails/broadcastable_model.rb +91 -0
  84. data/app/models/nitro_rails/broadcastable_record.rb +118 -0
  85. data/app/models/nitro_rails/default_broadcasts.rb +149 -0
  86. data/app/models/nitro_rails/record.rb +50 -0
  87. data/app/pseudocode/nitro.html.erb +18 -0
  88. data/app/view_components/nitro_rails/nitro_collection/batch_selectable.rb +24 -0
  89. data/app/view_components/nitro_rails/nitro_collection.rb +66 -0
  90. data/app/view_components/nitro_rails/view_component.rb +9 -0
  91. data/app/views/layouts/nitro_rails/application.html.erb +3 -5
  92. data/app/views/nitro_rails/_editable_text.html.erb +32 -0
  93. data/app/views/nitro_rails/_nitro_checkbox.html.erb +5 -0
  94. data/app/views/nitro_rails/_nitro_form.html.erb +10 -0
  95. data/app/views/nitro_rails/_panel_frame_tag.html.erb +8 -0
  96. data/app/views/nitro_rails/_panel_template.html.erb +40 -0
  97. data/app/views/nitro_rails/_togglable_checkbox.html.erb +16 -0
  98. data/config/importmap.rb +1 -0
  99. data/config/initializers/date_formatters.rb +9 -0
  100. data/lib/nitro_rails/engine.rb +25 -0
  101. data/lib/nitro_rails/version.rb +1 -1
  102. metadata +165 -3
  103. data/app/models/nitro_rails/application_record.rb +0 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 58fecea7521e815c776c017ced0a11c7d9dcf37da50ece5bb1e1ec7917fd5596
4
- data.tar.gz: ab26c0d8d11fa746ff7ad749c0e59327f638f70514383d93cbb6ec3e44593539
3
+ metadata.gz: 7f71c75899ffa891a15764b40d7b2689c0bb60ed23ebd40e6122837958e0a613
4
+ data.tar.gz: ebd57bac0083b2d6c1b19b0212e5c61c152fe7d8a92194a44113912f59996879
5
5
  SHA512:
6
- metadata.gz: 3d18abd332c81c5aab048c83ca575bff72e53467ce0586a18d89b778330771c96c1fe0352ee94f6e0be34c5116348ecf4086ea3017062201878aa9bfa7e5f73f
7
- data.tar.gz: edc206a091c19e45f4c416a37814fee496307d2bb548933ad1fdd2627c8a3cb568822b2a8bcf3012642e092bec0650ed5cdc110eb6e055122fe89bc55c55ba57
6
+ metadata.gz: a287da566c8533cf9793ce71405e48a62610862cdd1277361fa7c714af73c3ba03c7555505a19bd7098a34bf3eda713a685ee2628d003e7e2c3cdc2d49c86ba1
7
+ data.tar.gz: 979d4d22beccf10641a959762e6c91c8bb084746bea0e79dcc880a8fe65efa68c305763e90c6bdf7352138ff66d857376c4d621d3e3955f577fdf973375928a6
data/README.md CHANGED
@@ -21,6 +21,24 @@ Or install it yourself as:
21
21
  $ gem install nitro_rails
22
22
  ```
23
23
 
24
+ ## Features
25
+
26
+ ### NitroTags
27
+ Similar to content_tag with additional functions.
28
+ ```erb
29
+ <%= nitro_tag(:h1, "Hello World") %>
30
+ ```
31
+
32
+ Allows for hashed styles:
33
+ ```erb
34
+ <%= nitro_tag(:div, "Hello World", style: { color: "red", margin_bottom: 20 })
35
+ ```
36
+
37
+ Allows for easy "nitro_id" via resource and attribut
38
+ ```erb
39
+ <%= nitro_tag(:p, resource: @task, attribute: :description) %> <%# data-nitro-id = "task_3:description" %>
40
+ ```
41
+
24
42
  ## Contributing
25
43
  Contribution directions go here.
26
44
 
Binary file
@@ -1 +1,3 @@
1
1
  //= link_directory ../stylesheets/nitro_rails .css
2
+ //= link_tree ../javascript/nitro_rails .js
3
+ //= link_tree ../images/nitro_rails
@@ -0,0 +1,4 @@
1
+ // Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
2
+ import "@hotwired/turbo-rails"
3
+ import "./controllers/index.js"
4
+ import "./turbo_streams/index.js"
@@ -0,0 +1,9 @@
1
+ import { Application } from "@hotwired/stimulus"
2
+
3
+ const application = Application.start()
4
+
5
+ // Configure Stimulus development experience
6
+ application.debug = false
7
+ window.Stimulus = application
8
+
9
+ export { application }
@@ -0,0 +1,16 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+
3
+ export default class extends Controller {
4
+ // Preload audio files
5
+ connect() {
6
+ this.audio = new Audio(`/assets/${this.element.dataset.audio}.mp3`)
7
+ this.audio.load();
8
+ this.audio.preload = "auto";
9
+ // this.audio.time
10
+ }
11
+
12
+ play() {
13
+ this.audio.currentTime = 20000;
14
+ this.audio.play();
15
+ }
16
+ }
@@ -0,0 +1,21 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+
3
+ export default class extends Controller {
4
+ static targets = ["time"]
5
+ static values = { format: String }
6
+
7
+ connect() {
8
+ this.updateTime();
9
+ this.interval = setInterval(this.updateTime.bind(this), 1000);
10
+ }
11
+
12
+ disconnect() {
13
+ clearInterval(this.interval);
14
+ }
15
+
16
+ updateTime() {
17
+ const now = new Date();
18
+ const options = { hour: 'numeric', minute: 'numeric' };
19
+ this.timeTarget.textContent = now.toLocaleTimeString(undefined, options);
20
+ }
21
+ }
@@ -0,0 +1,61 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+
3
+ export default class extends Controller {
4
+ static targets = ["input", "editor", "form"]
5
+ static values = { attribute: String }
6
+
7
+ connect() {
8
+ this.inputTarget.value = this.editorTarget.innerText;
9
+ this.typingTimer;
10
+ }
11
+
12
+ focus() {
13
+ this.editorTarget.setAttribute('data-reject-broadcasts', '');
14
+ }
15
+
16
+ blur() {
17
+ this.editorTarget.removeAttribute('data-reject-broadcasts');
18
+ this.submit();
19
+ }
20
+
21
+ submit() {
22
+ if(this.inputTarget.value != this.editorTarget.innerText || this.editorTarget.innerText == '') {
23
+ this.inputTarget.value = this.editorTarget.innerText.trim();
24
+ this.formTarget.requestSubmit();
25
+ }
26
+ }
27
+
28
+ handleKeyDown(event) {
29
+ if(event.key == 'Enter') {
30
+ this.handleEnterKey(event);
31
+ } else {
32
+ clearTimeout(this.typingTimer);
33
+ this.typingTimer = setTimeout(this.submit.bind(this), 750)
34
+ if(event.key == 'Backspace') {
35
+ this.handleBackspaceKey(event);
36
+ }
37
+ }
38
+ }
39
+
40
+ handleEnterKey(event) {
41
+ event.preventDefault();
42
+ this.editorTarget.dataset.temporaryPlacement = window.getSelection().getRangeAt(0).startOffset;
43
+ this.editorTarget.blur();
44
+ return;
45
+ }
46
+
47
+ handleBackspaceKey(event) {
48
+ const selectionRange = window.getSelection().getRangeAt(0);
49
+
50
+ if(selectionRange.startOffset == 0 && selectionRange.endOffset == 0) {
51
+ event.preventDefault();
52
+ }
53
+
54
+ if(this.editorTarget.innerText.length == 1 || (selectionRange.startOffset == 0 && selectionRange.endOffset == this.editorTarget.innerText.length)) {
55
+ this.editorTarget.innerText = '';
56
+ }
57
+
58
+ return;
59
+ }
60
+
61
+ }
@@ -0,0 +1,21 @@
1
+ // Import and register all your controllers from the importmap under controllers/*
2
+
3
+ import { application } from "./application"
4
+
5
+ // Load all controllers one by one
6
+ // import EngineController from "./engine_controller"
7
+ // application.register("engine", EngineController)
8
+
9
+ // const controllers = ["editable_text", "search", "panel", "panel_manager", "resource_collection", "switch"];
10
+
11
+ const controllers = ["panel", "panel_manager", "editable_text", "time_zone", "togglable_checkbox", "nitro", "clock", "nitro_form", "audio", "nitro_collection", "tabs"];
12
+
13
+ controllers.forEach((controller) => {
14
+ import(`./${controller}_controller.js`).then(( { default: module }) => {
15
+ application.register(controller.replace("_", "-"), module)
16
+ })
17
+ })
18
+
19
+ // Lazy load controllers as they appear in the DOM (remember not to preload controllers in import map!)
20
+ // import { lazyLoadControllersFrom } from "@hotwired/stimulus-loading"
21
+ // lazyLoadControllersFrom("controllers", application)
@@ -0,0 +1,127 @@
1
+ // HACK: Needs major refactoring
2
+
3
+ import { Controller } from '@hotwired/stimulus';
4
+
5
+ export default class extends Controller {
6
+ static targets = ["template", "collection", "container", "item", "selections", "selectionForm"];
7
+
8
+ connect() {
9
+ this.selectedItems = [];
10
+ this.dragEvent = {
11
+ dragging: false,
12
+ originItem: null,
13
+ currentItem: null,
14
+ draggingItem: null
15
+ };
16
+ }
17
+
18
+ addTemporaryItem() {
19
+ var content = this.templateTarget.innerHTML;
20
+ var newElement = document.createElement("div");
21
+ newElement.innerHTML = content;
22
+ this.collectionTarget.appendChild(newElement);
23
+ }
24
+
25
+ selectItem(event) {
26
+ var item = event.currentTarget.closest("[data-nitro-collection-target='item']");
27
+
28
+ if(item.dataset.selected === "true") {
29
+ item.dataset.selected = "false";
30
+ item.classList.remove("selected");
31
+ this.selectedItems = this.selectedItems.filter(i => i !== item);
32
+ } else {
33
+ item.dataset.selected = "true";
34
+ item.classList.add("selected");
35
+ this.selectedItems.push(item);
36
+ }
37
+
38
+ if(this.selectedItems.length > 0) {
39
+ this.collectionTarget.classList.add("has-selection");
40
+ this.selectionsTarget.classList.remove("hidden");
41
+ } else {
42
+ this.collectionTarget.classList.remove("has-selection");
43
+ this.selectionsTarget.classList.add("hidden");
44
+ }
45
+
46
+ this.selectionsTarget.querySelector("#selection-count").innerText = `${this.selectedItems.length}`;
47
+
48
+ this.selectionFormTargets.forEach((form) => {
49
+ if(!form.querySelector(`#hidden-selections`)) {
50
+ var hiddenDiv = document.createElement("div");
51
+ hiddenDiv.id = "hidden-selections";
52
+ form.appendChild(hiddenDiv);
53
+ }
54
+
55
+ const selectionsDiv = form.querySelector(`#hidden-selections`);
56
+ selectionsDiv.innerHTML = "";
57
+
58
+ this.selectedItems.forEach((item, index) => {
59
+ selectionsDiv.innerHTML += `<input type="hidden" name="selected_ids[]" value="${item.dataset.id}">`;
60
+ });
61
+ });
62
+ }
63
+
64
+ startReposition(event) {
65
+ if(event.target.closest("a, input, button, textarea, .nitro-form-submit")) {
66
+ return;
67
+ }
68
+
69
+ event.preventDefault();
70
+ const item = event.currentTarget.closest("[data-nitro-collection-target='item']");
71
+ const itemClone = item.cloneNode(true);
72
+
73
+ this.dragEvent.originItem = item;
74
+ this.dragEvent.draggingItem = itemClone;
75
+ this.dragEvent.dragging = true;
76
+
77
+ item.classList.add("placeholder");
78
+
79
+
80
+ itemClone.style.position = "absolute";
81
+ itemClone.style.zIndex = "1000";
82
+ itemClone.id = "dragging-item";
83
+ itemClone.classList.add("dragging");
84
+ itemClone.dataset.action = "mouseup->nitro-collection#endReposition";
85
+
86
+ document.addEventListener("mousemove", (e) => {
87
+ itemClone.style.left = `${e.pageX - itemClone.offsetWidth / 2}px`;
88
+ itemClone.style.top = `${e.pageY - itemClone.offsetHeight / 2}px`;
89
+ });
90
+
91
+ document.addEventListener("mouseup", (e) => {
92
+ this.endReposition(e);
93
+ document.removeEventListener("mousemove", null);
94
+ });
95
+
96
+ this.collectionTarget.appendChild(itemClone);
97
+
98
+ itemClone.style.width = `${item.getBoundingClientRect().width}px`;
99
+ itemClone.style.left = `${event.pageX - itemClone.offsetWidth / 2}px`;
100
+ itemClone.style.top = `${event.pageY - itemClone.offsetHeight / 2}px`;
101
+ }
102
+
103
+ changePosition(event) {
104
+ this.dragEvent.currentItem = event.currentTarget.closest("[data-nitro-collection-target='item']");
105
+
106
+ if(this.dragEvent.dragging && this.dragEvent.currentItem !== this.dragEvent.originItem) {
107
+ if(this.dragEvent.currentItem !== this.dragEvent.originItem.nextElementSibling) {
108
+ this.collectionTarget.insertBefore(this.dragEvent.originItem, this.dragEvent.currentItem);
109
+ } else {
110
+ this.collectionTarget.insertBefore(this.dragEvent.originItem, this.dragEvent.currentItem.nextElementSibling);
111
+ }
112
+ }
113
+ }
114
+
115
+ endReposition() {
116
+ if(this.dragEvent.dragging) {
117
+ this.dragEvent.originItem.classList.remove("placeholder");
118
+ this.dragEvent.draggingItem.remove();
119
+ this.dragEvent = {
120
+ dragging: false,
121
+ originItem: null,
122
+ currentItem: null,
123
+ draggingItem: null
124
+ };
125
+ }
126
+ }
127
+ };
@@ -0,0 +1,35 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+
3
+ export default class extends Controller {
4
+ changeClasses(event) {
5
+ console.log("Changing classes");
6
+ var data = new FormData(event.target)
7
+ console.log(data.keys());
8
+ console.log(data.get("daypoint[num_stars]"));
9
+ var newNum = data.get("daypoint[num_stars]");
10
+ document.querySelector('[data-broadcast-tag="daypoint-69"]').classList.remove("stars-1", "stars-2", "stars-3", "stars-4", "stars-5");
11
+ document.querySelector('[data-broadcast-tag="daypoint-69"]').classList.add("stars-" + newNum);
12
+ // document.querySelector("[data-broadcast-tag='daypoint-69'").toggleClass("stars-" + newNum, true);
13
+
14
+ // data.getAll.for
15
+
16
+ for (const [name, value] of data.entries()) {
17
+ console.log(name + ": " + value);
18
+ }
19
+ }
20
+
21
+ simulateResponse() {
22
+ console.log("Simulating response");
23
+ // var data = new FormData();
24
+ // data.append("daypoint[num_stars]", "3");
25
+ // var event = {
26
+ // target: document.querySelector('[data-broadcast-tag="daypoint-69"]')
27
+ // };
28
+ // this.changeClasses(event);
29
+ }
30
+
31
+ link(event) {
32
+ var url = event.currentTarget.getAttribute("data-nitro-link");
33
+ window.location.href = url;
34
+ }
35
+ };
@@ -0,0 +1,81 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+
3
+ export default class extends Controller {
4
+ static targets = ["form", "field", "collection"]
5
+ static values = {
6
+ resourceTarget: String
7
+ }
8
+
9
+ submit(event) {
10
+ event.preventDefault();
11
+ event.stopPropagation();
12
+ this.formTarget.requestSubmit();
13
+
14
+ if(this.formTarget.dataset.nitroEffects) {
15
+ console.log(this.formTarget.dataset.nitroEffects);
16
+ this.formTarget.dataset.nitroEffects.split(" ").forEach((effect) => {
17
+ if(this[effect]) {
18
+ this[effect]();
19
+ }
20
+ });
21
+ }
22
+ }
23
+
24
+ insertItems(){
25
+
26
+ }
27
+
28
+ addToAffiliatedLists(affiliation, value, field) {
29
+ document.querySelectorAll(`[data-nitro-collection-id="${affiliation}"]`).forEach((element) => {
30
+ var collectionController = window.Stimulus.getControllerForElementAndIdentifier(element, "nitro-collection");
31
+ collectionController.addTemporaryItem();
32
+ });
33
+ }
34
+
35
+ attributeEffects(){
36
+ this.fieldTargets.forEach((field) => {
37
+ field.dataset.nitroEffects.split(" ").forEach((effect) => {
38
+ if(this[effect]) {
39
+ this[effect](field.dataset.nitroAttribute, field.value, field);
40
+ }
41
+ });
42
+ console.log(field.dataset.nitroEffects)
43
+ });
44
+ }
45
+
46
+ updateStatusClass(attribute, value) {
47
+ console.log(`Updating status class for ${attribute} with value ${value}`);
48
+ document.querySelectorAll(`[data-nitro-id="${this.resourceTargetValue}"], [data-nitro-id="${this.resourceTargetValue}:${attribute}"]`).forEach((element) => {
49
+ // Remove classes starting with attribute
50
+ element.classList.forEach((className) => {
51
+ if(className.startsWith(attribute)) {
52
+ element.classList.remove(className);
53
+ }
54
+ });
55
+
56
+ element.classList.add(`${attribute}-${value}`);
57
+ });
58
+
59
+ this.resourceTargetValue
60
+ }
61
+
62
+ toggleBooleanStatusClass(attribute, value, field) {
63
+ document.querySelectorAll(`[data-nitro-id="${this.resourceTargetValue}"]`).forEach((element) => {
64
+ if(field.checked) {
65
+ element.classList.add(`${attribute}`);
66
+ } else {
67
+ element.classList.remove(`${attribute}`);
68
+ }
69
+ });
70
+ }
71
+
72
+ removeItem() {
73
+ document.querySelectorAll(`[data-nitro-id="${this.resourceTargetValue}"]`).forEach((element) => {
74
+ element.remove();
75
+ });
76
+ }
77
+
78
+ connect() {
79
+ console.log("Nitro Form Connected!");
80
+ }
81
+ };
@@ -0,0 +1,70 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+
3
+ export default class extends Controller {
4
+ static targets = ["turboFrame"]
5
+
6
+ connect() {
7
+ this.initialPanelTop = null;
8
+ this.isCardFullyExpanded = false;
9
+ console.log("Panel Connected!");
10
+ // this.element.addEventListener('wheel', this.handleScroll.bind(this));
11
+ }
12
+
13
+ open() {
14
+ let path = this.turboFrameTarget.src
15
+ path = new URL(path, window.location.href);
16
+ path.searchParams.delete("panel_request");
17
+ Turbo.visit(path, { action: "advance" });
18
+ }
19
+
20
+ beforeVisit(event) {
21
+ console.log(event);
22
+ console.log(event.srcElement.src);
23
+ // event.srcElement.src = event.srcElement.src + "?panel_request=true";
24
+
25
+ const { fetchOptions } = event.detail;
26
+
27
+ // Add your custom header
28
+ fetchOptions.headers["Turbo-Panel-Request"] = "true";
29
+ console.log(fetchOptions.headers);
30
+
31
+ }
32
+
33
+ close() {
34
+ this.element.remove();
35
+ }
36
+
37
+ scroll(event) {
38
+ event.preventDefault();
39
+ event.stopPropagation();
40
+ console.log("SCROLLING PANEL");
41
+ console.log(event);
42
+ }
43
+
44
+ handleScroll(event) {
45
+ if (!this.isCardFullyExpanded) {
46
+ event.preventDefault();
47
+ const scrollDirection = event.deltaY * -1; // Positive when scrolling down, negative when scrolling up
48
+
49
+ // Initialize initialPanelTop if it's not set
50
+ if (this.initialPanelTop === null) {
51
+ const panelPosition = this.element.getBoundingClientRect();
52
+ this.initialPanelTop = panelPosition.top;
53
+ }
54
+
55
+ // Calculate new position based on scroll direction
56
+ let newTopPosition = this.initialPanelTop + scrollDirection;
57
+ newTopPosition = Math.max(newTopPosition, 0); // Ensure the panel does not move above the top of the screen
58
+
59
+ // Move the panel by updating its CSS transform property
60
+ this.element.style.transform = `translateY(${newTopPosition}px)`;
61
+
62
+ if (newTopPosition === 0) {
63
+ this.isCardFullyExpanded = true; // The card is now fully expanded
64
+ } else {
65
+ // Update initialPanelTop for the next scroll event
66
+ this.initialPanelTop = newTopPosition;
67
+ }
68
+ }
69
+ }
70
+ }
@@ -0,0 +1,89 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+ import { deviceInfoHelper } from '../helpers/device_info_helper';
3
+ import { screenInfoHelper } from '../helpers/screen_info_helper';
4
+
5
+ // Needs a complete overhaul, probably so that links and panels are connected without panel containers
6
+ export default class extends Controller {
7
+ static targets = ["panelTemplate", "container", "panel"]
8
+ connect() {
9
+ }
10
+
11
+ morph(event) {
12
+ this.containerTargets.forEach((panel) => {
13
+ console.log(panel);
14
+ });
15
+ }
16
+
17
+ closeOtherPanels(event) {
18
+ let activePanels = this.panelTargets.filter((panel) => {
19
+ return panel.closest('.panel-container').classList.contains("active");
20
+ });
21
+
22
+ let currentPanelContainer = event.target.closest('.panel-container');
23
+ activePanels.forEach((panel) => {
24
+
25
+ if(panel.closest('.panel-container') !== currentPanelContainer) {
26
+ panel.closest('.panel-container').classList.remove("active");
27
+ panel.classList.add("hidden");
28
+ }
29
+ });
30
+ }
31
+
32
+ closeAllPanels(event) {
33
+ if(event.target === event.currentTarget) {
34
+ this.panelTargets.forEach((panel) => {
35
+ panel.closest('.panel-container').classList.remove("active");
36
+ panel.classList.add("hidden");
37
+ });
38
+ }
39
+ }
40
+
41
+ initializePanel(anchor, panelContainer, panelID) {
42
+ const panel = this.panelTemplateTarget.cloneNode(true);
43
+
44
+ panel.id = panelID;
45
+
46
+ // Add panel request parameter to path
47
+ let path = new URL(anchor.getAttribute("href"), window.location.href);
48
+ path.searchParams.append("panel_request", "true");
49
+
50
+
51
+
52
+ if(anchor.dataset.panelPresentation) {
53
+ console.log(anchor.dataset);
54
+ panel.classList.add(anchor.dataset.panelPresentation);
55
+ }
56
+
57
+ panel.dataset.panelManagerTarget = "panel";
58
+ panelContainer.appendChild(panel);
59
+ panel.querySelector("turbo-frame").src = anchor.getAttribute("href");
60
+ return panel;
61
+ }
62
+
63
+ toggle(event) {
64
+ if(deviceInfoHelper.isIOSApp() || this.isInPanel(event)) {
65
+ console.log("HERE");
66
+ return;
67
+ }
68
+
69
+ event.preventDefault();
70
+
71
+ let anchor = event.currentTarget;
72
+ let panelContainer = (anchor.closest('.panel-container') || document.body);
73
+
74
+ let panelID = `panel-${anchor.dataset.panelId}`;
75
+ let panel = (panelContainer.querySelector(`#${panelID}`) || this.initializePanel(anchor, panelContainer, panelID));
76
+
77
+ if(panel.classList.contains("hidden")) {
78
+ panel.classList.remove("hidden");
79
+ panelContainer.classList.add("active");
80
+ } else {
81
+ panel.classList.add("hidden");
82
+ panelContainer.classList.remove("active");
83
+ }
84
+ }
85
+
86
+ isInPanel(event) {
87
+ return event.currentTarget.closest('[data-controller~="panel"]') !== null;
88
+ }
89
+ }
@@ -0,0 +1,81 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class extends Controller {
4
+ static targets = ["tab", "screen", "screens"]
5
+
6
+ connect(event) {
7
+ if(this.element.dataset.tabsLoaded === "true") {
8
+ return
9
+ }
10
+
11
+ this.tabId = this.element.id || "tab";
12
+ const source = this.element.closest("turbo-frame");
13
+ let urlParams;
14
+
15
+ if (source && source.src) {
16
+ urlParams = new URLSearchParams(source.src.split("?")[1]);
17
+ } else {
18
+ urlParams = new URLSearchParams(window.location.search);
19
+ }
20
+
21
+ const tab = urlParams.get(this.tabId);
22
+
23
+ if (tab) {
24
+ const selectedTab = this.tabTargets.find((searchTab) => searchTab.dataset.tabsScreen === tab);
25
+
26
+ if (selectedTab) {
27
+ this.#showScreen(selectedTab);
28
+ }
29
+ } else {
30
+ this.#showScreen(this.tabTargets[0]);
31
+ }
32
+
33
+ this.element.dataset.tabsLoaded = "true";
34
+ }
35
+
36
+ changeScreens(event) {
37
+ event.preventDefault();
38
+ event.stopPropagation();
39
+
40
+ let selectedScreen = this.#showScreen(event.currentTarget);
41
+ console.log(selectedScreen);
42
+ let masonry = selectedScreen.querySelectorAll(".masonry");
43
+
44
+ if (masonry.length > 0) {
45
+ masonry.forEach((m) => {
46
+ let stimulusController = this.application.getControllerForElementAndIdentifier(m, "masonry")
47
+ stimulusController.layout()
48
+ })
49
+ }
50
+ }
51
+
52
+ #showScreen(tab) {
53
+ const screenName = tab.dataset.tabsScreen
54
+ this.#addQueryParamToCurrentUrl(this.tabId, screenName)
55
+ this.#clearState();
56
+
57
+ tab.classList.add("active")
58
+
59
+ let screenTarget = this.screensTarget.querySelector(`[data-tabs-screen="${screenName}"]`);
60
+ if (screenTarget) {
61
+ screenTarget.classList.remove("hidden")
62
+ }
63
+ return screenTarget;
64
+ }
65
+
66
+ #addQueryParamToCurrentUrl(key, value) {
67
+ const url = new URL(window.location.href);
68
+ url.searchParams.set(key, value);
69
+ window.history.replaceState({}, '', url);
70
+ }
71
+
72
+ #clearState() {
73
+ this.tabTargets.forEach((tab) => {
74
+ tab.classList.remove("active");
75
+ })
76
+
77
+ this.screenTargets.forEach((screen) => {
78
+ screen.classList.add("hidden");
79
+ })
80
+ }
81
+ }