plain-rails 0.1.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.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +162 -0
  3. data/Rakefile +8 -0
  4. data/app/assets/builds/plain.css +1 -0
  5. data/app/assets/config/plain_manifest.js +1 -0
  6. data/app/assets/stylesheets/plain/application.css +15 -0
  7. data/app/assets/stylesheets/plain/application.tailwind.css +7 -0
  8. data/app/controllers/plain/application_controller.rb +4 -0
  9. data/app/controllers/plain/conversations_controller.rb +55 -0
  10. data/app/controllers/plain/docs_controller.rb +63 -0
  11. data/app/controllers/plain/home_controller.rb +10 -0
  12. data/app/controllers/plain/messages_controller.rb +30 -0
  13. data/app/helpers/plain/application_helper.rb +4 -0
  14. data/app/helpers/plain/conversations_helper.rb +4 -0
  15. data/app/helpers/plain/docs_helper.rb +4 -0
  16. data/app/helpers/plain/home_helper.rb +4 -0
  17. data/app/helpers/plain/messages_helper.rb +4 -0
  18. data/app/javascripts/loader_controller.js +27 -0
  19. data/app/javascripts/scroll_controller.js +8 -0
  20. data/app/javascripts/toggle_class_controller.js +11 -0
  21. data/app/jobs/plain/application_job.rb +4 -0
  22. data/app/jobs/plain/message_processor_job.rb +9 -0
  23. data/app/mailers/plain/application_mailer.rb +6 -0
  24. data/app/models/plain/application_record.rb +5 -0
  25. data/app/models/plain/conversation.rb +53 -0
  26. data/app/models/plain/message.rb +62 -0
  27. data/app/services/plain/ai_docs.rb +163 -0
  28. data/app/services/plain/docs_service.rb +127 -0
  29. data/app/views/layouts/plain/application.html.erb +51 -0
  30. data/app/views/plain/conversations/_conversation_item.erb +15 -0
  31. data/app/views/plain/conversations/_conversation_item.html.erb +21 -0
  32. data/app/views/plain/conversations/_conversation_list.erb +18 -0
  33. data/app/views/plain/conversations/_conversation_list.html.erb +13 -0
  34. data/app/views/plain/conversations/_modal.html.erb +73 -0
  35. data/app/views/plain/conversations/index.html.erb +17 -0
  36. data/app/views/plain/conversations/show.html.erb +14 -0
  37. data/app/views/plain/docs/_footer.erb +61 -0
  38. data/app/views/plain/docs/_menu.erb +20 -0
  39. data/app/views/plain/docs/_sections.erb +73 -0
  40. data/app/views/plain/docs/show.html.erb +126 -0
  41. data/app/views/plain/home/index.html.erb +35 -0
  42. data/app/views/plain/messages/_form.html.erb +25 -0
  43. data/app/views/plain/messages/_message_item.html.erb +26 -0
  44. data/app/views/plain/messages/_message_list.html.erb +16 -0
  45. data/app/views/plain/messages/_new_message.turbo_stream.erb +3 -0
  46. data/app/views/plain/messages/create.turbo_stream.erb +8 -0
  47. data/app/views/plain/messages/index.html.erb +1 -0
  48. data/config/database.yml +53 -0
  49. data/config/routes.rb +11 -0
  50. data/db/migrate/20230729010703_create_plain_conversations.rb +10 -0
  51. data/db/migrate/20230729010745_create_plain_messages.rb +11 -0
  52. data/lib/plain/configuration.rb +12 -0
  53. data/lib/plain/engine.rb +16 -0
  54. data/lib/plain/version.rb +3 -0
  55. data/lib/plain.rb +17 -0
  56. data/lib/tasks/plain_tasks.rake +21 -0
  57. metadata +196 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 43a10b608f595d930e8f6a5b78e1eaacfb215e9e41c52a2a370bf1a59ba82bf7
4
+ data.tar.gz: 97887d97476ac81f3a4211f0cee8b2b478993426d8944fded04c0086acb0080f
5
+ SHA512:
6
+ metadata.gz: 4feede7f6b64116184a6c5f90c1aae43f9a80aa42146ab9dbb72f82af2b37cd17147e501898715ce4dbfad44aa4d87ff9b0c0ccf58b5a5e258fc5af63637f6b7
7
+ data.tar.gz: cefdc7499f3e939162db104ff11c1e7d90b9557055b76891c968dd3f5e76148f72c93c4cdf977ce8d6d9eb7430a0b93260f4783cff4c750b8ae12d2826ae6562
data/README.md ADDED
@@ -0,0 +1,162 @@
1
+ # What is this Ruby on Plan rails engine
2
+
3
+ Plain is a Rails engine that serves as an Artificial Intelligence (AI) assistant for your Rails project. It's not just about organizing your codes or managing your project structure, but about providing deeper, more meaningful context to your work, in real-time. It was proudly developed and presented during the esteemed Rails Hackathon 2023.
4
+
5
+ *This is an example of plain operating in Rauversion project*
6
+
7
+ https://github.com/chaskiq/plain/assets/11976/87f0d62d-d63a-45d9-91e2-b8878542c4ee
8
+
9
+ ## Usage
10
+ How to use my plugin.
11
+
12
+ ## Installation
13
+ Add this line to your application's Gemfile:
14
+
15
+ ```ruby
16
+ gem "plain-rails"
17
+ ```
18
+
19
+ or development version
20
+
21
+ ```ruby
22
+ gem "plain-rails", github: "chaskiq/plain", branch: "main"
23
+ ```
24
+
25
+ ### Overview
26
+
27
+ Plain is a Rails engine that serves as an Artificial Intelligence (AI) assistant for your Rails project. It's not just about organizing your codes or managing your project structure, but about providing deeper, more meaningful context to your work, in real-time. It was proudly developed and presented during the esteemed Rails Hackathon 2023. Special Kudos to [@claunicole](https://github.com/claunicole), [@silva96](https://github.com/silva96)
28
+
29
+
30
+ ### Functionality
31
+
32
+ The most salient feature of Plain is its capability to analyze your project on the go. Using AI, it can instantly provide explanations and insights about various aspects of your Rails project, effectively becoming an intelligent companion during your development process.
33
+
34
+
35
+ ### Documentation Site
36
+
37
+
38
+ Beyond just an AI assistant, Plain acts as a comprehensive documentation site. What sets Plain apart is its ability to take markdown files and seamlessly integrate them into the documentation site. No more disjointed files and folders, everything is displayed on a beautifully designed, user-friendly site. This enables developers to add, modify, or access documentation effortlessly and intuitively.
39
+
40
+
41
+ ## Getting started
42
+
43
+ ### Install Migrations:
44
+
45
+ `rails plain:install:migrations`
46
+
47
+ ### Configuration:
48
+
49
+ put this in an config/initializers , config/initializers/plain.rb
50
+
51
+ ```ruby
52
+ Plain.configure do |config|
53
+ config.paths = [
54
+ Rails.root.join("Gemfile"),
55
+ Rails.root.join("app/models"),
56
+ Rails.root.join("app/controllers"),
57
+ Rails.root.join("spec")
58
+ ]
59
+ config.extensions = ["rb", "js", "md", "json", "erb"]
60
+ config.chat_environments = [:development]
61
+
62
+ # initialize your vector search
63
+ config.vector_search = Langchain::Vectorsearch::Qdrant.new(
64
+ url: ENV["QDRANT_URL"],
65
+ api_key: ENV["QDRANT_API_KEY"],
66
+ index_name: ENV["QDRANT_INDEX"],
67
+ llm: Langchain::LLM::OpenAI.new(
68
+ api_key: ENV["OPENAI_API_KEY"],
69
+ llm_options: {},
70
+ default_options: {
71
+ chat_completion_model_name: "gpt-3.5-turbo-16k"
72
+ }
73
+ )
74
+ )
75
+ end
76
+ ```
77
+
78
+ For other vector search please refer to langchainrb repo https://github.com/andreibondarev/langchainrb#using-vector-search-databases-
79
+
80
+ Some environment configuration variables are required:
81
+
82
+ ```bash
83
+ QDRANT_URL =
84
+ QDRANT_API_KEY =
85
+ QDRANT_INDEX =
86
+ OPENAI_API_KEY =
87
+ ```
88
+
89
+ You can get a free account on the https://qdrant.tech/ there will be more providers to connect soon.
90
+
91
+ ### Load information to Index:
92
+
93
+ `rails plain:load`
94
+
95
+ ### Mount Doc site:
96
+
97
+ in config/routes.rb mount the engine:
98
+
99
+ `mount Plain::Engine => "/plain"`
100
+
101
+ in app/assets/config/manifest.js
102
+
103
+ add
104
+
105
+ ```js
106
+ //= link plain.css
107
+ ```
108
+
109
+
110
+ ## Documentation site.
111
+
112
+ Plain provides a documentation site that can be populated via markdown files with front-matter support, how it works.
113
+
114
+ Place your markdowns on a `docs` folder on your project's root. also you can add a main configuration file, for example:
115
+
116
+ ![Screen Shot 2023-08-17 at 10 54 14 PM](https://github.com/chaskiq/plain/assets/11976/0dee77c6-9cb7-489e-8521-3c870952861c)
117
+
118
+
119
+ ### Documentation side main config
120
+
121
+ Put this on /docs/config.yml
122
+
123
+ ```yaml
124
+ name: "Rauversion docs"
125
+ logo: "logo.png"
126
+ chat_envs:
127
+ - "development"
128
+ - "test"
129
+ links:
130
+ -
131
+ name: "Start us on github"
132
+ url: "https://github.com/xxx/rxxx
133
+ -
134
+ name: "X"
135
+ url: "https://x.com/xxx"
136
+ footer:
137
+ legend: "xxxx © Copyright 2023 . All rights reserved."
138
+ links:
139
+ -
140
+ name: "Twitter / X"
141
+ url: "https://twitter.com/xxx"
142
+ -
143
+ name: "IG"
144
+ url: "https://instagram.com/xxx"
145
+ sections:
146
+ -
147
+ name: "getting_started"
148
+ position: 1
149
+ items:
150
+ -
151
+ name: "oli"
152
+ path: "aaa"
153
+ description: "hello there"
154
+ ```
155
+
156
+
157
+ ### Development:
158
+
159
+ `bin/rails plain:tailwind_engine_watch --trace`
160
+
161
+
162
+ License: MIT
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/setup"
2
+
3
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
4
+ load "rails/tasks/engine.rake"
5
+
6
+ load "rails/tasks/statistics.rake"
7
+
8
+ require "bundler/gem_tasks"
@@ -0,0 +1 @@
1
+ /*! tailwindcss v3.3.3 | MIT License | https://tailwindcss.com*/*,:after,:before{border:0 solid #e4e4e7;box-sizing:border-box}:after,:before{--tw-content:""}html{-webkit-text-size-adjust:100%;font-feature-settings:normal;font-family:DM Sans,sans-serif;font-variation-settings:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{font-feature-settings:inherit;color:inherit;font-family:inherit;font-size:100%;font-variation-settings:inherit;font-weight:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{color:#a1a1aa;opacity:1}input::placeholder,textarea::placeholder{color:#a1a1aa;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[hidden]{display:none}[multiple],[type=date],[type=datetime-local],[type=email],[type=month],[type=number],[type=password],[type=search],[type=tel],[type=text],[type=time],[type=url],[type=week],select,textarea{--tw-shadow:0 0 #0000;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#71717a;border-radius:0;border-width:1px;font-size:1rem;line-height:1.5rem;padding:.5rem .75rem}[multiple]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=email]:focus,[type=month]:focus,[type=number]:focus,[type=password]:focus,[type=search]:focus,[type=tel]:focus,[type=text]:focus,[type=time]:focus,[type=url]:focus,[type=week]:focus,select:focus,textarea:focus{--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#2563eb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);border-color:#2563eb;box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);outline:2px solid #0000;outline-offset:2px}input::-moz-placeholder,textarea::-moz-placeholder{color:#71717a;opacity:1}input::placeholder,textarea::placeholder{color:#71717a;opacity:1}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-date-and-time-value{min-height:1.5em}::-webkit-datetime-edit,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-meridiem-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-year-field{padding-bottom:0;padding-top:0}select{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%2371717a' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3E%3C/svg%3E");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}[multiple]{background-image:none;background-position:0 0;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}[type=checkbox],[type=radio]{--tw-shadow:0 0 #0000;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;background-origin:border-box;border-color:#71717a;border-width:1px;color:#2563eb;display:inline-block;flex-shrink:0;height:1rem;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;-webkit-user-select:none;-moz-user-select:none;user-select:none;vertical-align:middle;width:1rem}[type=checkbox]{border-radius:0}[type=radio]{border-radius:100%}[type=checkbox]:focus,[type=radio]:focus{--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:2px;--tw-ring-offset-color:#fff;--tw-ring-color:#2563eb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);outline:2px solid #0000;outline-offset:2px}[type=checkbox]:checked,[type=radio]:checked{background-color:currentColor;background-position:50%;background-repeat:no-repeat;background-size:100% 100%;border-color:#0000}[type=checkbox]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Cpath d='M12.207 4.793a1 1 0 0 1 0 1.414l-5 5a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L6.5 9.086l4.293-4.293a1 1 0 0 1 1.414 0z'/%3E%3C/svg%3E")}[type=radio]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='3'/%3E%3C/svg%3E")}[type=checkbox]:checked:focus,[type=checkbox]:checked:hover,[type=checkbox]:indeterminate,[type=radio]:checked:focus,[type=radio]:checked:hover{background-color:currentColor;border-color:#0000}[type=checkbox]:indeterminate{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3E%3Cpath stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3E%3C/svg%3E");background-position:50%;background-repeat:no-repeat;background-size:100% 100%}[type=checkbox]:indeterminate:focus,[type=checkbox]:indeterminate:hover{background-color:currentColor;border-color:#0000}[type=file]{background:unset;border-color:inherit;border-radius:0;border-width:0;font-size:unset;line-height:inherit;padding:0}[type=file]:focus{outline:1px solid ButtonText;outline:1px auto -webkit-focus-ring-color}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.prose{color:var(--tw-prose-body);max-width:65ch}.prose :where([class~=lead]):not(:where([class~=not-prose] *)){color:var(--tw-prose-lead);font-size:1.25em;line-height:1.6;margin-bottom:1.2em;margin-top:1.2em}.prose :where(a):not(:where([class~=not-prose] *)){color:var(--tw-prose-links);font-weight:500;text-decoration:underline}.prose :where(strong):not(:where([class~=not-prose] *)){color:var(--tw-prose-bold);font-weight:600}.prose :where(a strong):not(:where([class~=not-prose] *)){color:inherit}.prose :where(blockquote strong):not(:where([class~=not-prose] *)){color:inherit}.prose :where(thead th strong):not(:where([class~=not-prose] *)){color:inherit}.prose :where(ol):not(:where([class~=not-prose] *)){list-style-type:decimal;margin-bottom:1.25em;margin-top:1.25em;padding-left:1.625em}.prose :where(ol[type=A]):not(:where([class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a]):not(:where([class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=A s]):not(:where([class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a s]):not(:where([class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=I]):not(:where([class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i]):not(:where([class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type=I s]):not(:where([class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i s]):not(:where([class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type="1"]):not(:where([class~=not-prose] *)){list-style-type:decimal}.prose :where(ul):not(:where([class~=not-prose] *)){list-style-type:disc;margin-bottom:1.25em;margin-top:1.25em;padding-left:1.625em}.prose :where(ol>li):not(:where([class~=not-prose] *))::marker{color:var(--tw-prose-counters);font-weight:400}.prose :where(ul>li):not(:where([class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.prose :where(hr):not(:where([class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-bottom:3em;margin-top:3em}.prose :where(blockquote):not(:where([class~=not-prose] *)){border-left-color:var(--tw-prose-quote-borders);border-left-width:.25rem;color:var(--tw-prose-quotes);font-style:italic;font-weight:500;margin-bottom:1.6em;margin-top:1.6em;padding-left:1em;quotes:"\201C""\201D""\2018""\2019"}.prose :where(blockquote p:first-of-type):not(:where([class~=not-prose] *)):before{content:open-quote}.prose :where(blockquote p:last-of-type):not(:where([class~=not-prose] *)):after{content:close-quote}.prose :where(h1):not(:where([class~=not-prose] *)){color:var(--tw-prose-headings);font-size:2.25em;font-weight:800;line-height:1.1111111;margin-bottom:.8888889em;margin-top:0}.prose :where(h1 strong):not(:where([class~=not-prose] *)){color:inherit;font-weight:900}.prose :where(h2):not(:where([class~=not-prose] *)){color:var(--tw-prose-headings);font-size:1.5em;font-weight:700;line-height:1.3333333;margin-bottom:1em;margin-top:2em}.prose :where(h2 strong):not(:where([class~=not-prose] *)){color:inherit;font-weight:800}.prose :where(h3):not(:where([class~=not-prose] *)){color:var(--tw-prose-headings);font-size:1.25em;font-weight:600;line-height:1.6;margin-bottom:.6em;margin-top:1.6em}.prose :where(h3 strong):not(:where([class~=not-prose] *)){color:inherit;font-weight:700}.prose :where(h4):not(:where([class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;line-height:1.5;margin-bottom:.5em;margin-top:1.5em}.prose :where(h4 strong):not(:where([class~=not-prose] *)){color:inherit;font-weight:700}.prose :where(img):not(:where([class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.prose :where(figure>*):not(:where([class~=not-prose] *)){margin-bottom:0;margin-top:0}.prose :where(figcaption):not(:where([class~=not-prose] *)){color:var(--tw-prose-captions);font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.prose :where(code):not(:where([class~=not-prose] *)){color:var(--tw-prose-code);font-size:.875em;font-weight:600}.prose :where(code):not(:where([class~=not-prose] *)):before{content:"`"}.prose :where(code):not(:where([class~=not-prose] *)):after{content:"`"}.prose :where(a code):not(:where([class~=not-prose] *)){color:inherit}.prose :where(h1 code):not(:where([class~=not-prose] *)){color:inherit}.prose :where(h2 code):not(:where([class~=not-prose] *)){color:inherit;font-size:.875em}.prose :where(h3 code):not(:where([class~=not-prose] *)){color:inherit;font-size:.9em}.prose :where(h4 code):not(:where([class~=not-prose] *)){color:inherit}.prose :where(blockquote code):not(:where([class~=not-prose] *)){color:inherit}.prose :where(thead th code):not(:where([class~=not-prose] *)){color:inherit}.prose :where(pre):not(:where([class~=not-prose] *)){background-color:var(--tw-prose-pre-bg);border-radius:.375rem;color:var(--tw-prose-pre-code);font-size:.875em;font-weight:400;line-height:1.7142857;margin-bottom:1.7142857em;margin-top:1.7142857em;overflow-x:auto;padding:.8571429em 1.1428571em}.prose :where(pre code):not(:where([class~=not-prose] *)){background-color:initial;border-radius:0;border-width:0;color:inherit;font-family:inherit;font-size:inherit;font-weight:inherit;line-height:inherit;padding:0}.prose :where(pre code):not(:where([class~=not-prose] *)):before{content:none}.prose :where(pre code):not(:where([class~=not-prose] *)):after{content:none}.prose :where(table):not(:where([class~=not-prose] *)){font-size:.875em;line-height:1.7142857;margin-bottom:2em;margin-top:2em;table-layout:auto;text-align:left;width:100%}.prose :where(thead):not(:where([class~=not-prose] *)){border-bottom-color:var(--tw-prose-th-borders);border-bottom-width:1px}.prose :where(thead th):not(:where([class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;padding-bottom:.5714286em;padding-left:.5714286em;padding-right:.5714286em;vertical-align:bottom}.prose :where(tbody tr):not(:where([class~=not-prose] *)){border-bottom-color:var(--tw-prose-td-borders);border-bottom-width:1px}.prose :where(tbody tr:last-child):not(:where([class~=not-prose] *)){border-bottom-width:0}.prose :where(tbody td):not(:where([class~=not-prose] *)){vertical-align:initial}.prose :where(tfoot):not(:where([class~=not-prose] *)){border-top-color:var(--tw-prose-th-borders);border-top-width:1px}.prose :where(tfoot td):not(:where([class~=not-prose] *)){vertical-align:top}.prose{--tw-prose-body:#374151;--tw-prose-headings:#111827;--tw-prose-lead:#4b5563;--tw-prose-links:#111827;--tw-prose-bold:#111827;--tw-prose-counters:#6b7280;--tw-prose-bullets:#d1d5db;--tw-prose-hr:#e5e7eb;--tw-prose-quotes:#111827;--tw-prose-quote-borders:#e5e7eb;--tw-prose-captions:#6b7280;--tw-prose-code:#111827;--tw-prose-pre-code:#e5e7eb;--tw-prose-pre-bg:#1f2937;--tw-prose-th-borders:#d1d5db;--tw-prose-td-borders:#e5e7eb;--tw-prose-invert-body:#d1d5db;--tw-prose-invert-headings:#fff;--tw-prose-invert-lead:#9ca3af;--tw-prose-invert-links:#fff;--tw-prose-invert-bold:#fff;--tw-prose-invert-counters:#9ca3af;--tw-prose-invert-bullets:#4b5563;--tw-prose-invert-hr:#374151;--tw-prose-invert-quotes:#f3f4f6;--tw-prose-invert-quote-borders:#374151;--tw-prose-invert-captions:#9ca3af;--tw-prose-invert-code:#fff;--tw-prose-invert-pre-code:#d1d5db;--tw-prose-invert-pre-bg:#00000080;--tw-prose-invert-th-borders:#4b5563;--tw-prose-invert-td-borders:#374151;font-size:1rem;line-height:1.75}.prose :where(p):not(:where([class~=not-prose] *)){margin-bottom:1.25em;margin-top:1.25em}.prose :where(video):not(:where([class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.prose :where(figure):not(:where([class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.prose :where(li):not(:where([class~=not-prose] *)){margin-bottom:.5em;margin-top:.5em}.prose :where(ol>li):not(:where([class~=not-prose] *)){padding-left:.375em}.prose :where(ul>li):not(:where([class~=not-prose] *)){padding-left:.375em}.prose :where(.prose>ul>li p):not(:where([class~=not-prose] *)){margin-bottom:.75em;margin-top:.75em}.prose :where(.prose>ul>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ul>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.25em}.prose :where(.prose>ol>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ol>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.25em}.prose :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose] *)){margin-bottom:.75em;margin-top:.75em}.prose :where(hr+*):not(:where([class~=not-prose] *)){margin-top:0}.prose :where(h2+*):not(:where([class~=not-prose] *)){margin-top:0}.prose :where(h3+*):not(:where([class~=not-prose] *)){margin-top:0}.prose :where(h4+*):not(:where([class~=not-prose] *)){margin-top:0}.prose :where(thead th:first-child):not(:where([class~=not-prose] *)){padding-left:0}.prose :where(thead th:last-child):not(:where([class~=not-prose] *)){padding-right:0}.prose :where(tbody td,tfoot td):not(:where([class~=not-prose] *)){padding:.5714286em}.prose :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose] *)){padding-left:0}.prose :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose] *)){padding-right:0}.prose :where(.prose>:first-child):not(:where([class~=not-prose] *)){margin-top:0}.prose :where(.prose>:last-child):not(:where([class~=not-prose] *)){margin-bottom:0}.prose-sm{font-size:.875rem;line-height:1.7142857}.prose-sm :where(p):not(:where([class~=not-prose] *)){margin-bottom:1.1428571em;margin-top:1.1428571em}.prose-sm :where([class~=lead]):not(:where([class~=not-prose] *)){font-size:1.2857143em;line-height:1.5555556;margin-bottom:.8888889em;margin-top:.8888889em}.prose-sm :where(blockquote):not(:where([class~=not-prose] *)){margin-bottom:1.3333333em;margin-top:1.3333333em;padding-left:1.1111111em}.prose-sm :where(h1):not(:where([class~=not-prose] *)){font-size:2.1428571em;line-height:1.2;margin-bottom:.8em;margin-top:0}.prose-sm :where(h2):not(:where([class~=not-prose] *)){font-size:1.4285714em;line-height:1.4;margin-bottom:.8em;margin-top:1.6em}.prose-sm :where(h3):not(:where([class~=not-prose] *)){font-size:1.2857143em;line-height:1.5555556;margin-bottom:.4444444em;margin-top:1.5555556em}.prose-sm :where(h4):not(:where([class~=not-prose] *)){line-height:1.4285714;margin-bottom:.5714286em;margin-top:1.4285714em}.prose-sm :where(img):not(:where([class~=not-prose] *)){margin-bottom:1.7142857em;margin-top:1.7142857em}.prose-sm :where(video):not(:where([class~=not-prose] *)){margin-bottom:1.7142857em;margin-top:1.7142857em}.prose-sm :where(figure):not(:where([class~=not-prose] *)){margin-bottom:1.7142857em;margin-top:1.7142857em}.prose-sm :where(figure>*):not(:where([class~=not-prose] *)){margin-bottom:0;margin-top:0}.prose-sm :where(figcaption):not(:where([class~=not-prose] *)){font-size:.8571429em;line-height:1.3333333;margin-top:.6666667em}.prose-sm :where(code):not(:where([class~=not-prose] *)){font-size:.8571429em}.prose-sm :where(h2 code):not(:where([class~=not-prose] *)){font-size:.9em}.prose-sm :where(h3 code):not(:where([class~=not-prose] *)){font-size:.8888889em}.prose-sm :where(pre):not(:where([class~=not-prose] *)){border-radius:.25rem;font-size:.8571429em;line-height:1.6666667;margin-bottom:1.6666667em;margin-top:1.6666667em;padding:.6666667em 1em}.prose-sm :where(ol):not(:where([class~=not-prose] *)){margin-bottom:1.1428571em;margin-top:1.1428571em;padding-left:1.5714286em}.prose-sm :where(ul):not(:where([class~=not-prose] *)){margin-bottom:1.1428571em;margin-top:1.1428571em;padding-left:1.5714286em}.prose-sm :where(li):not(:where([class~=not-prose] *)){margin-bottom:.2857143em;margin-top:.2857143em}.prose-sm :where(ol>li):not(:where([class~=not-prose] *)){padding-left:.4285714em}.prose-sm :where(ul>li):not(:where([class~=not-prose] *)){padding-left:.4285714em}.prose-sm :where(.prose>ul>li p):not(:where([class~=not-prose] *)){margin-bottom:.5714286em;margin-top:.5714286em}.prose-sm :where(.prose>ul>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.1428571em}.prose-sm :where(.prose>ul>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.1428571em}.prose-sm :where(.prose>ol>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.1428571em}.prose-sm :where(.prose>ol>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.1428571em}.prose-sm :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose] *)){margin-bottom:.5714286em;margin-top:.5714286em}.prose-sm :where(hr):not(:where([class~=not-prose] *)){margin-bottom:2.8571429em;margin-top:2.8571429em}.prose-sm :where(hr+*):not(:where([class~=not-prose] *)){margin-top:0}.prose-sm :where(h2+*):not(:where([class~=not-prose] *)){margin-top:0}.prose-sm :where(h3+*):not(:where([class~=not-prose] *)){margin-top:0}.prose-sm :where(h4+*):not(:where([class~=not-prose] *)){margin-top:0}.prose-sm :where(table):not(:where([class~=not-prose] *)){font-size:.8571429em;line-height:1.5}.prose-sm :where(thead th):not(:where([class~=not-prose] *)){padding-bottom:.6666667em;padding-left:1em;padding-right:1em}.prose-sm :where(thead th:first-child):not(:where([class~=not-prose] *)){padding-left:0}.prose-sm :where(thead th:last-child):not(:where([class~=not-prose] *)){padding-right:0}.prose-sm :where(tbody td,tfoot td):not(:where([class~=not-prose] *)){padding:.6666667em 1em}.prose-sm :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose] *)){padding-left:0}.prose-sm :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose] *)){padding-right:0}.prose-sm :where(.prose>:first-child):not(:where([class~=not-prose] *)){margin-top:0}.prose-sm :where(.prose>:last-child):not(:where([class~=not-prose] *)){margin-bottom:0}.prose-base :where(.prose>ul>li p):not(:where([class~=not-prose] *)){margin-bottom:.75em;margin-top:.75em}.prose-base :where(.prose>ul>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.25em}.prose-base :where(.prose>ul>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.25em}.prose-base :where(.prose>ol>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.25em}.prose-base :where(.prose>ol>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.25em}.prose-base :where(.prose>:first-child):not(:where([class~=not-prose] *)){margin-top:0}.prose-base :where(.prose>:last-child):not(:where([class~=not-prose] *)){margin-bottom:0}.prose-lg :where(.prose>ul>li p):not(:where([class~=not-prose] *)){margin-bottom:.8888889em;margin-top:.8888889em}.prose-lg :where(.prose>ul>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.3333333em}.prose-lg :where(.prose>ul>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.3333333em}.prose-lg :where(.prose>ol>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.3333333em}.prose-lg :where(.prose>ol>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.3333333em}.prose-lg :where(.prose>:first-child):not(:where([class~=not-prose] *)){margin-top:0}.prose-lg :where(.prose>:last-child):not(:where([class~=not-prose] *)){margin-bottom:0}.prose-xl :where(.prose>ul>li p):not(:where([class~=not-prose] *)){margin-bottom:.8em;margin-top:.8em}.prose-xl :where(.prose>ul>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.2em}.prose-xl :where(.prose>ul>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.2em}.prose-xl :where(.prose>ol>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.2em}.prose-xl :where(.prose>ol>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.2em}.prose-xl :where(.prose>:first-child):not(:where([class~=not-prose] *)){margin-top:0}.prose-xl :where(.prose>:last-child):not(:where([class~=not-prose] *)){margin-bottom:0}.prose-2xl :where(.prose>ul>li p):not(:where([class~=not-prose] *)){margin-bottom:.8333333em;margin-top:.8333333em}.prose-2xl :where(.prose>ul>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.3333333em}.prose-2xl :where(.prose>ul>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.3333333em}.prose-2xl :where(.prose>ol>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.3333333em}.prose-2xl :where(.prose>ol>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.3333333em}.prose-2xl :where(.prose>:first-child):not(:where([class~=not-prose] *)){margin-top:0}.prose-2xl :where(.prose>:last-child):not(:where([class~=not-prose] *)){margin-bottom:0}.sr-only{clip:rect(0,0,0,0);border-width:0;height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;white-space:nowrap;width:1px}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.inset-x-0{left:0;right:0}.inset-y-0{bottom:0;top:0}.inset-y-\[-30\%\]{bottom:-30%;top:-30%}.bottom-0{bottom:0}.right-0{right:0}.top-0{top:0}.top-full{top:100%}.z-50{z-index:50}.m-2{margin:.5rem}.m-4{margin:1rem}.-mx-1{margin-left:-.25rem;margin-right:-.25rem}.-mx-1\.5{margin-left:-.375rem;margin-right:-.375rem}.-my-1{margin-bottom:-.25rem;margin-top:-.25rem}.mx-4{margin-left:1rem;margin-right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.my-1{margin-bottom:.25rem;margin-top:.25rem}.my-16{margin-bottom:4rem;margin-top:4rem}.-ml-1{margin-left:-.25rem}.-mr-1{margin-right:-.25rem}.ml-3{margin-left:.75rem}.ml-4{margin-left:1rem}.ml-\[calc\(-1\*var\(--width\)\)\]{margin-left:calc(var(--width)*-1)}.ml-auto{margin-left:auto}.mt-0{margin-top:0}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-4{margin-top:1rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.contents{display:contents}.hidden{display:none}.h-0{height:0}.h-10{height:2.5rem}.h-14{height:3.5rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-\[160\%\]{height:160%}.h-\[52px\]{height:52px}.h-\[calc\(100vh-155px\)\]{height:calc(100vh - 155px)}.h-\[calc\(100vh-255px\)\]{height:calc(100vh - 255px)}.h-full{height:100%}.h-px{height:1px}.w-2{width:.5rem}.w-2\.5{width:.625rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-7{width:1.75rem}.w-\[448px\]{width:448px}.w-\[var\(--width\)\]{width:var(--width)}.w-full{width:100%}.w-screen{width:100vw}.max-w-2xl{max-width:42rem}.max-w-full{max-width:100%}.max-w-md{max-width:28rem}.flex-1{flex:1 1 0%}.flex-grow{flex-grow:1}.translate-x-0{--tw-translate-x:0px}.translate-x-0,.translate-x-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-full{--tw-translate-x:100%}.rotate-180{--tw-rotate:180deg}.rotate-180,.skew-y-\[-18deg\]{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.skew-y-\[-18deg\]{--tw-skew-y:-18deg}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scroll-mt-24{scroll-margin-top:6rem}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-\[1fr\2c 1px\2c 1fr\]{grid-template-columns:1fr 1px 1fr}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0{gap:0}.gap-0\.5{gap:.125rem}.gap-12{gap:3rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-5{gap:1.25rem}.gap-6{gap:1.5rem}.gap-8{gap:2rem}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(.5rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(.5rem*var(--tw-space-x-reverse))}.space-y-10>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(2.5rem*var(--tw-space-y-reverse));margin-top:calc(2.5rem*(1 - var(--tw-space-y-reverse)))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.5rem*var(--tw-space-y-reverse));margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-bottom-width:calc(1px*var(--tw-divide-y-reverse));border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)))}.divide-gray-200>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(228 228 231/var(--tw-divide-opacity))}.overflow-hidden{overflow:hidden}.overflow-visible{overflow:visible}.overflow-y-auto{overflow-y:auto}.overflow-y-scroll{overflow-y:scroll}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-sm{border-radius:.125rem}.border{border-width:1px}.border-0{border-width:0}.border-l{border-left-width:1px}.border-t{border-top-width:1px}.border-black\/10{border-color:#0000001a}.border-transparent{border-color:#0000}.border-zinc-900\/10{border-color:#18181b1a}.border-zinc-900\/5{border-color:#18181b0d}.bg-black\/5{background-color:#0000000d}.bg-brand-200{--tw-bg-opacity:1;background-color:rgb(251 207 232/var(--tw-bg-opacity))}.bg-brand-600{--tw-bg-opacity:1;background-color:rgb(219 39 119/var(--tw-bg-opacity))}.bg-brand-700{--tw-bg-opacity:1;background-color:rgb(190 24 93/var(--tw-bg-opacity))}.bg-gray-900{--tw-bg-opacity:1;background-color:rgb(24 24 27/var(--tw-bg-opacity))}.bg-red-600{--tw-bg-opacity:1;background-color:rgb(225 29 72/var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-white\/\[var\(--bg-opacity-light\)\]{background-color:rgb(255 255 255/var(--bg-opacity-light))}.bg-zinc-100{--tw-bg-opacity:1;background-color:rgb(244 244 245/var(--tw-bg-opacity))}.bg-zinc-50{--tw-bg-opacity:1;background-color:rgb(250 250 250/var(--tw-bg-opacity))}.bg-zinc-900{--tw-bg-opacity:1;background-color:rgb(24 24 27/var(--tw-bg-opacity))}.bg-zinc-900\/10{background-color:#18181b1a}.bg-zinc-900\/5{background-color:#18181b0d}.bg-gradient-to-r{background-image:linear-gradient(to right,var(--tw-gradient-stops))}.from-\[\#D7EDEA\]{--tw-gradient-from:#d7edea var(--tw-gradient-from-position);--tw-gradient-to:#d7edea00 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.to-\[\#F4FBDF\]{--tw-gradient-to:#f4fbdf var(--tw-gradient-to-position)}.fill-black\/50{fill:#00000080}.fill-black\/\[0\.02\]{fill:#00000005}.fill-zinc-700{fill:#3f3f46}.fill-zinc-700\/10{fill:#3f3f461a}.stroke-black\/5{stroke:#0000000d}.stroke-black\/70{stroke:#000000b3}.stroke-current{stroke:currentColor}.stroke-white{stroke:#fff}.stroke-zinc-500{stroke:#71717a}.stroke-zinc-700{stroke:#3f3f46}.stroke-zinc-900{stroke:#18181b}.p-2{padding:.5rem}.p-4{padding:1rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.py-1{padding-bottom:.25rem;padding-top:.25rem}.py-1\.5{padding-bottom:.375rem;padding-top:.375rem}.py-16{padding-bottom:4rem;padding-top:4rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.py-6{padding-bottom:1.5rem;padding-top:1.5rem}.pb-1{padding-bottom:.25rem}.pb-16{padding-bottom:4rem}.pb-4{padding-bottom:1rem}.pl-10{padding-left:2.5rem}.pl-2{padding-left:.5rem}.pl-4{padding-left:1rem}.pr-3{padding-right:.75rem}.pt-10{padding-top:2.5rem}.pt-14{padding-top:3.5rem}.pt-16{padding-top:4rem}.pt-2{padding-top:.5rem}.pt-8{padding-top:2rem}.font-sans{font-family:DM Sans,sans-serif}.text-2xl{font-size:1.5rem;line-height:2rem}.text-\[0\.8125rem\]{font-size:.8125rem}.text-base{font-size:1rem;line-height:1.5rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-extrabold{font-weight:800}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.capitalize{text-transform:capitalize}.leading-5{line-height:1.25rem}.leading-6{line-height:1.5rem}.leading-7{line-height:1.75rem}.tracking-tight{letter-spacing:-.025em}.text-brand-200{--tw-text-opacity:1;color:rgb(251 207 232/var(--tw-text-opacity))}.text-brand-300{--tw-text-opacity:1;color:rgb(249 168 212/var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity:1;color:rgb(24 24 27/var(--tw-text-opacity))}.text-inherit{color:inherit}.text-slate-900{--tw-text-opacity:1;color:rgb(15 23 42/var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.text-zinc-400{--tw-text-opacity:1;color:rgb(161 161 170/var(--tw-text-opacity))}.text-zinc-500{--tw-text-opacity:1;color:rgb(113 113 122/var(--tw-text-opacity))}.text-zinc-600{--tw-text-opacity:1;color:rgb(82 82 91/var(--tw-text-opacity))}.text-zinc-900{--tw-text-opacity:1;color:rgb(24 24 27/var(--tw-text-opacity))}.no-underline{text-decoration-line:none}.opacity-0{opacity:0}.mix-blend-overlay{mix-blend-mode:overlay}.shadow-sm{--tw-shadow:0 1px 2px 0 #0000000d;--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.shadow-sm,.shadow-xl{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px #0000001a,0 8px 10px -6px #0000001a;--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color),0 8px 10px -6px var(--tw-shadow-color)}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-inset{--tw-ring-inset:inset}.ring-gray-300,.ring-zinc-300{--tw-ring-opacity:1;--tw-ring-color:rgb(212 212 216/var(--tw-ring-opacity))}.ring-zinc-900\/10{--tw-ring-color:#18181b1a}.ring-zinc-900\/25{--tw-ring-color:#18181b40}.backdrop-blur-\[2px\]{--tw-backdrop-blur:blur(2px)}.backdrop-blur-\[2px\],.backdrop-blur-sm{-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.backdrop-blur-sm{--tw-backdrop-blur:blur(4px)}.transition{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-colors{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-shadow{transition-duration:.15s;transition-property:box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-300{transition-duration:.3s}.duration-500{transition-duration:.5s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.\[--width\:calc\(2\.625rem\+0\.5px\+50\%-min\(50\%\2c calc\(theme\(maxWidth\.lg\)\+theme\(spacing\.8\)\)\)\)\]{--width:calc(2.625rem + 0.5px + 50% - min(50%,calc(32rem + 2rem)))}.\[mask-image\:linear-gradient\(white\2c transparent\)\]{-webkit-mask-image:linear-gradient(#fff,#0000);mask-image:linear-gradient(#fff,#0000)}@media (prefers-color-scheme:dark){.dark\:prose-invert{--tw-prose-body:var(--tw-prose-invert-body);--tw-prose-headings:var(--tw-prose-invert-headings);--tw-prose-lead:var(--tw-prose-invert-lead);--tw-prose-links:var(--tw-prose-invert-links);--tw-prose-bold:var(--tw-prose-invert-bold);--tw-prose-counters:var(--tw-prose-invert-counters);--tw-prose-bullets:var(--tw-prose-invert-bullets);--tw-prose-hr:var(--tw-prose-invert-hr);--tw-prose-quotes:var(--tw-prose-invert-quotes);--tw-prose-quote-borders:var(--tw-prose-invert-quote-borders);--tw-prose-captions:var(--tw-prose-invert-captions);--tw-prose-code:var(--tw-prose-invert-code);--tw-prose-pre-code:var(--tw-prose-invert-pre-code);--tw-prose-pre-bg:var(--tw-prose-invert-pre-bg);--tw-prose-th-borders:var(--tw-prose-invert-th-borders);--tw-prose-td-borders:var(--tw-prose-invert-td-borders)}}.placeholder\:text-gray-400::-moz-placeholder{--tw-text-opacity:1;color:rgb(161 161 170/var(--tw-text-opacity))}.placeholder\:text-gray-400::placeholder{--tw-text-opacity:1;color:rgb(161 161 170/var(--tw-text-opacity))}.empty\:mb-\[-600px\]:empty{margin-bottom:-600px}.empty\:mb-\[300px\]:empty{margin-bottom:300px}.empty\:mt-\[-300px\]:empty{margin-top:-300px}.empty\:mt-\[600px\]:empty{margin-top:600px}.empty\:block:empty{display:block}.hover\:bg-black\/10:hover{background-color:#0000001a}.hover\:bg-black\/5:hover{background-color:#0000000d}.hover\:bg-brand-500:hover{--tw-bg-opacity:1;background-color:rgb(236 72 153/var(--tw-bg-opacity))}.hover\:bg-gray-50:hover{--tw-bg-opacity:1;background-color:rgb(250 250 250/var(--tw-bg-opacity))}.hover\:bg-slate-900\/\[0\.03\]:hover{background-color:#0f172a08}.hover\:bg-zinc-200:hover{--tw-bg-opacity:1;background-color:rgb(228 228 231/var(--tw-bg-opacity))}.hover\:bg-zinc-700:hover{--tw-bg-opacity:1;background-color:rgb(63 63 70/var(--tw-bg-opacity))}.hover\:bg-zinc-900\/5:hover{background-color:#18181b0d}.hover\:text-inherit:hover{color:inherit}.hover\:text-white:hover{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.hover\:text-zinc-600:hover{--tw-text-opacity:1;color:rgb(82 82 91/var(--tw-text-opacity))}.hover\:text-zinc-900:hover{--tw-text-opacity:1;color:rgb(24 24 27/var(--tw-text-opacity))}.hover\:shadow-md:hover{--tw-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a;--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.hover\:shadow-zinc-900\/5:hover{--tw-shadow-color:#18181b0d;--tw-shadow:var(--tw-shadow-colored)}.hover\:ring-zinc-500:hover{--tw-ring-opacity:1;--tw-ring-color:rgb(113 113 122/var(--tw-ring-opacity))}.hover\:ring-zinc-900\/20:hover{--tw-ring-color:#18181b33}.focus\:outline-none:focus{outline:2px solid #0000;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-inset:focus{--tw-ring-inset:inset}.focus\:ring-brand-600:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(219 39 119/var(--tw-ring-opacity))}.focus\:ring-white:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(255 255 255/var(--tw-ring-opacity))}.focus-visible\:outline:focus-visible{outline-style:solid}.focus-visible\:outline-2:focus-visible{outline-width:2px}.focus-visible\:outline-offset-2:focus-visible{outline-offset:2px}.focus-visible\:outline-brand-600:focus-visible{outline-color:#db2777}.group:hover .group-hover\:bg-white\/50{background-color:#ffffff80}.group:hover .group-hover\:fill-zinc-900{fill:#18181b}.group:hover .group-hover\:stroke-zinc-900{stroke:#18181b}.group:hover .group-hover\:opacity-100{opacity:1}.group:hover .group-hover\:opacity-50{opacity:.5}.group:hover .group-hover\:ring-zinc-900\/10{--tw-ring-color:#18181b1a}.group:hover .group-hover\:ring-zinc-900\/25{--tw-ring-color:#18181b40}.group:focus .group-focus\:opacity-100{opacity:1}.group:not(:empty) .group-\[\&\:not\(\:empty\)\]\:hidden{display:none}@media (prefers-color-scheme:dark){.dark\:block{display:block}.dark\:hidden{display:none}.dark\:border-white\/10{border-color:#ffffff1a}.dark\:border-white\/5{border-color:#ffffff0d}.dark\:bg-emerald-400\/10{background-color:#34d3991a}.dark\:bg-white\/10{background-color:#ffffff1a}.dark\:bg-white\/5{background-color:#ffffff0d}.dark\:bg-zinc-800{--tw-bg-opacity:1;background-color:rgb(39 39 42/var(--tw-bg-opacity))}.dark\:bg-zinc-800\/40{background-color:#27272a66}.dark\:bg-zinc-900\/\[var\(--bg-opacity-dark\)\]{background-color:rgb(24 24 27/var(--bg-opacity-dark))}.dark\:from-\[\#202D2E\]{--tw-gradient-from:#202d2e var(--tw-gradient-from-position);--tw-gradient-to:#202d2e00 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.dark\:to-\[\#303428\]{--tw-gradient-to:#303428 var(--tw-gradient-to-position)}.dark\:fill-white\/10{fill:#ffffff1a}.dark\:stroke-white{stroke:#fff}.dark\:stroke-white\/10{stroke:#ffffff1a}.dark\:stroke-zinc-400{stroke:#a1a1aa}.dark\:text-emerald-400{--tw-text-opacity:1;color:rgb(52 211 153/var(--tw-text-opacity))}.dark\:text-slate-200{--tw-text-opacity:1;color:rgb(226 232 240/var(--tw-text-opacity))}.dark\:text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.dark\:text-zinc-400{--tw-text-opacity:1;color:rgb(161 161 170/var(--tw-text-opacity))}.dark\:text-zinc-500{--tw-text-opacity:1;color:rgb(113 113 122/var(--tw-text-opacity))}.dark\:ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.dark\:ring-inset{--tw-ring-inset:inset}.dark\:ring-emerald-400\/20{--tw-ring-color:#34d39933}.dark\:ring-white\/10{--tw-ring-color:#ffffff1a}.dark\:ring-zinc-700{--tw-ring-opacity:1;--tw-ring-color:rgb(63 63 70/var(--tw-ring-opacity))}.dark\:ring-zinc-800{--tw-ring-opacity:1;--tw-ring-color:rgb(39 39 42/var(--tw-ring-opacity))}.dark\:backdrop-blur{--tw-backdrop-blur:blur(8px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.dark\:hover\:bg-emerald-400\/10:hover{background-color:#34d3991a}.dark\:hover\:bg-white\/5:hover{background-color:#ffffff0d}.dark\:hover\:bg-zinc-700:hover{--tw-bg-opacity:1;background-color:rgb(63 63 70/var(--tw-bg-opacity))}.dark\:hover\:bg-zinc-800:hover{--tw-bg-opacity:1;background-color:rgb(39 39 42/var(--tw-bg-opacity))}.dark\:hover\:text-emerald-300:hover{--tw-text-opacity:1;color:rgb(110 231 183/var(--tw-text-opacity))}.dark\:hover\:text-white:hover{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.dark\:hover\:text-zinc-300:hover{--tw-text-opacity:1;color:rgb(212 212 216/var(--tw-text-opacity))}.dark\:hover\:shadow-black\/5:hover{--tw-shadow-color:#0000000d;--tw-shadow:var(--tw-shadow-colored)}.dark\:hover\:ring-emerald-300:hover{--tw-ring-opacity:1;--tw-ring-color:rgb(110 231 183/var(--tw-ring-opacity))}.dark\:hover\:ring-white\/20:hover{--tw-ring-color:#fff3}.dark\:hover\:ring-zinc-600:hover{--tw-ring-opacity:1;--tw-ring-color:rgb(82 82 91/var(--tw-ring-opacity))}.group:hover .dark\:group-hover\:bg-emerald-300\/10{background-color:#6ee7b71a}.group:hover .dark\:group-hover\:fill-emerald-300\/10{fill:#6ee7b71a}.group:hover .dark\:group-hover\:fill-zinc-500{fill:#71717a}.group\/anchor:hover .dark\:group-hover\/anchor\:stroke-white{stroke:#fff}.group:hover .dark\:group-hover\:stroke-emerald-400{stroke:#34d399}.group:hover .dark\:group-hover\:ring-emerald-400{--tw-ring-opacity:1;--tw-ring-color:rgb(52 211 153/var(--tw-ring-opacity))}.group:hover .dark\:group-hover\:ring-white\/20{--tw-ring-color:#fff3}}@media (min-width:416px){.min-\[416px\]\:contents{display:contents}}@media (min-width:640px){.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:pl-16{padding-left:4rem}.sm\:text-3xl{font-size:1.875rem;line-height:2.25rem}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}.sm\:leading-6{line-height:1.5rem}.sm\:duration-700{transition-duration:.7s}}@media (min-width:768px){.md\:block{display:block}.md\:h-5{height:1.25rem}.md\:w-px{width:1px}.md\:justify-start{justify-content:flex-start}.md\:bg-zinc-900\/10{background-color:#18181b1a}}@media (min-width:1024px){.lg\:pointer-events-none{pointer-events:none}.lg\:pointer-events-auto{pointer-events:auto}.lg\:fixed{position:fixed}.lg\:inset-0{inset:0}.lg\:left-72{left:18rem}.lg\:z-30{z-index:30}.lg\:z-40{z-index:40}.lg\:z-50{z-index:50}.lg\:ml-72{margin-left:18rem}.lg\:mt-10{margin-top:2.5rem}.lg\:block{display:block}.lg\:flex{display:flex}.lg\:hidden{display:none}.lg\:w-72{width:18rem}.lg\:max-w-5xl{max-width:64rem}.lg\:max-w-md{max-width:28rem}.lg\:flex-auto{flex:1 1 auto}.lg\:overflow-y-auto{overflow-y:auto}.lg\:border-r{border-right-width:1px}.lg\:border-zinc-900\/10{border-color:#18181b1a}.lg\:px-6{padding-left:1.5rem;padding-right:1.5rem}.lg\:px-8{padding-left:2rem;padding-right:2rem}.lg\:pb-8{padding-bottom:2rem}.lg\:pt-4{padding-top:1rem}@media (prefers-color-scheme:dark){.lg\:dark\:border-white\/10{border-color:#ffffff1a}}}@media (min-width:1280px){.xl\:left-80{left:20rem}.xl\:ml-80{margin-left:20rem}.xl\:w-80{width:20rem}.xl\:max-w-none{max-width:none}.xl\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}@media (min-width:1536px){.\32xl\:\[--width\:theme\(spacing\.10\)\]{--width:2.5rem}}
@@ -0,0 +1 @@
1
+ //= link_directory ../stylesheets/plain .css
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,7 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+
6
+
7
+ @layer components {}
@@ -0,0 +1,4 @@
1
+ module Plain
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,55 @@
1
+ module Plain
2
+ class ConversationsController < ApplicationController
3
+ PER_PAGE = 10
4
+
5
+ layout "plain/application"
6
+
7
+ skip_before_action :verify_authenticity_token
8
+
9
+ before_action :allow_iframe_requests #, only: [:index, :create]
10
+
11
+ def allow_iframe_requests
12
+ response.headers.delete("X-Frame-Options")
13
+ end
14
+
15
+ def index
16
+ @needs_back = true
17
+ @conversations = Plain::Conversation.all
18
+
19
+ if @conversations.empty?
20
+ Plain::Conversation.create
21
+ end
22
+
23
+ @current_page = params[:page].to_i
24
+ @next_page = @current_page + 1
25
+ @conversations = Plain::Conversation.limit(PER_PAGE)
26
+ .offset(@current_page * PER_PAGE)
27
+ .order(pinned_at: :asc, created_at: :desc)
28
+ end
29
+
30
+ def show
31
+ @conversation = Plain::Conversation.find(params[:id])
32
+ end
33
+
34
+ def new
35
+ @conversation = Plain::Conversation.create
36
+ redirect_to conversation_path(@conversation)
37
+ end
38
+
39
+ def edit
40
+ @conversation = Plain::Conversation.find(params[:id])
41
+ end
42
+
43
+ def update
44
+ @conversation = Plain::Conversation.find(params[:id])
45
+ end
46
+
47
+ def destroy
48
+ Plain::Conversation.find(params[:id]).destroy
49
+
50
+ @conversation = Plain::Conversation.create
51
+ render "index"
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,63 @@
1
+ module Plain
2
+ class DocsController < ApplicationController
3
+
4
+ def show
5
+ #@docs_structure = directory_hash(Rails.root.join('docs'))
6
+ #render_markdown(params[:file_path])
7
+ @docs_structure = DocsService.get_structure
8
+ @config = DocsService.config
9
+
10
+ if params[:file_path].blank?
11
+ @content = nil
12
+ @main_config = DocsService.parse_section_items
13
+ render "show" and return
14
+ end
15
+
16
+ if params[:file_path].ends_with?('/')
17
+ @content = DocsService.get_content("#{params[:file_path]}README")
18
+ else
19
+ @content = DocsService.get_content(params[:file_path])
20
+ end
21
+
22
+ @file = find_file(@docs_structure, params[:file_path])
23
+ end
24
+
25
+ private
26
+
27
+ def find_file(directory, file_path)
28
+ directory[:children].each do |child|
29
+ if child[:type] == 'file' && child[:path] == file_path
30
+ return child
31
+ elsif child[:type] == 'directory'
32
+ found_file = find_file(child, file_path)
33
+ return found_file if found_file
34
+ end
35
+ end
36
+ nil
37
+ end
38
+
39
+ def render_markdown(file_path)
40
+ markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML, autolink: true, tables: true)
41
+ file = File.read(Rails.root.join('docs', "#{file_path}.md"))
42
+ @content = markdown.render(file).html_safe
43
+ rescue Errno::ENOENT
44
+ render file: "#{Rails.root}/public/404.html", status: :not_found
45
+ end
46
+
47
+ def directory_hash(path, name=nil)
48
+ data = {name: (name || path)}
49
+ data[:type] = File.directory?(path) ? 'directory' : 'file'
50
+ data[:children] = children = []
51
+ Dir.foreach(path) do |entry|
52
+ next if (entry == '..' || entry == '.')
53
+ full_path = File.join(path, entry)
54
+ if File.directory?(full_path)
55
+ children << directory_hash(full_path, entry)
56
+ else
57
+ children << { name: entry, type: 'file' }
58
+ end
59
+ end
60
+ data
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,10 @@
1
+ module Plain
2
+ class HomeController < ApplicationController
3
+
4
+ def index
5
+ @conversations = Plain::Conversation
6
+ .order(pinned_at: :asc, created_at: :desc)
7
+ .limit(4)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,30 @@
1
+ module Plain
2
+ class MessagesController < ApplicationController
3
+ layout false
4
+ skip_before_action :verify_authenticity_token
5
+
6
+ PER_PAGE = 10
7
+ layout false
8
+
9
+ def index
10
+ @conversation = Plain::Conversation.find(params[:conversation_id])
11
+ @current_page = params[:page].to_i
12
+ @next_page = @current_page + 1
13
+ @messages = @conversation.messages.limit(PER_PAGE).offset(@current_page * PER_PAGE).order(created_at: :desc)
14
+ end
15
+
16
+ def new
17
+ @conversation = Plain::Conversation.find(params[:conversation_id])
18
+ @message = @conversation.messages.new
19
+ end
20
+
21
+ def create
22
+ @conversation = Plain::Conversation.find(params[:conversation_id])
23
+ @question = params[:message][:content]
24
+ @conversation.messages.create(role: "user", content: @question)
25
+ @conversation.add_assistant_response_async(@question)
26
+ end
27
+
28
+ end
29
+
30
+ end
@@ -0,0 +1,4 @@
1
+ module Plain
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Plain
2
+ module ConversationsHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Plain
2
+ module DocsHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Plain
2
+ module HomeHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Plain
2
+ module MessagesHelper
3
+ end
4
+ end
@@ -0,0 +1,27 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class extends Controller {
4
+ static targets = [ "loader" ]
5
+
6
+ connect() {
7
+ }
8
+
9
+ showLoader() {
10
+ //this.loaderTarget.classList.remove('hidden')
11
+ }
12
+
13
+ hideLoader() {
14
+ //this.loaderTarget.classList.remove('hidden')
15
+ this.loaderTarget.innerHTML = "Ask Plain!"
16
+ }
17
+
18
+ formSubmitting() {
19
+ this.loaderTarget.innerHTML = "Loading..."
20
+ //if(this.hasLoaderTarget) this.showLoader()
21
+ }
22
+
23
+ formSubmitted() {
24
+ this.loaderTarget.innerHTML = "Ask Plain!"
25
+ //if(this.hasLoaderTarget) this.hideLoader()
26
+ }
27
+ }
@@ -0,0 +1,8 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ // Connects to data-controller="scroll"
4
+ export default class extends Controller {
5
+ connect() {
6
+ this.element.scrollIntoView()
7
+ }
8
+ }
@@ -0,0 +1,11 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class extends Controller {
4
+ toggle(event) {
5
+ // Toggle 'active' class on button
6
+ event.currentTarget.classList.toggle('active');
7
+
8
+ // Toggle 'hidden' class on controller's root element
9
+ this.element.classList.toggle('hidden');
10
+ }
11
+ }
@@ -0,0 +1,4 @@
1
+ module Plain
2
+ class ApplicationJob < ActiveJob::Base
3
+ end
4
+ end
@@ -0,0 +1,9 @@
1
+ module Plain
2
+ class MessageProcessorJob < ApplicationJob
3
+ queue_as :default
4
+
5
+ def perform(conversation, question: )
6
+ conversation.add_assistant_response(question)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ module Plain
2
+ class ApplicationMailer < ActionMailer::Base
3
+ default from: "from@example.com"
4
+ layout "mailer"
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module Plain
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end
@@ -0,0 +1,53 @@
1
+ module Plain
2
+ class Conversation < ApplicationRecord
3
+ has_many :messages, foreign_key: "plain_conversation_id", dependent: :destroy
4
+
5
+ def add_assistant_response(question)
6
+ ai_docs = Plain::AiDocs.new
7
+ vector_search = ai_docs.client
8
+ complete_response = ""
9
+
10
+ message = messages.new(role: "assistant", content: "")
11
+
12
+ chat = Plain::AiDocs.new.conversation_client do |chunk|
13
+ puts "****"
14
+ p chunk
15
+ puts "****"
16
+
17
+ next if chunk.content.nil?
18
+ complete_response << chunk.content
19
+ message.content = complete_response
20
+ message.save
21
+ end
22
+
23
+ # plain_answer = vector_search.ask(question: @question)
24
+ search_results = vector_search.similarity_search(query: question)
25
+
26
+ context = search_results.map do |result|
27
+ result.dig("payload", "content").to_s
28
+ end
29
+
30
+ plain_answer = context.join("\n---\n")
31
+
32
+ chat.add_examples(messages) if messages.any?
33
+ Plain::AiDocs.set_conversation_title(self) if messages.size >= 4 && subject.blank?
34
+
35
+ puts "CONTEXT"
36
+ context = "The following is the context of my application, please respond accordingly with this context: \r\n" << plain_answer << "end of context"
37
+ puts context
38
+
39
+ chat.set_context(context)
40
+ # chat.set_functions(Plain::AiDocs.functions())
41
+ chat.message(question)
42
+ end
43
+
44
+ def add_assistant_response_async(question)
45
+ Plain::MessageProcessorJob.perform_later(self, question: question)
46
+ end
47
+
48
+ def add_subject_from_summary
49
+ Plain::AiDocs.set_conversation_title(self)
50
+ end
51
+
52
+ end
53
+ end