head 0.0.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +37 -0
- data/app/assets/fonts/head/headicons.woff +0 -0
- data/app/assets/fonts/icomoon.json +228 -0
- data/app/assets/javascript/head/index.js +2 -0
- data/app/assets/javascript/head/knob.js +51 -0
- data/app/assets/javascript/head/wing.js +18 -0
- data/app/assets/stylesheets/head/components/knob.sass +49 -0
- data/app/assets/stylesheets/head/components/theater.sass +55 -0
- data/app/assets/stylesheets/head/components/wing.sass +70 -0
- data/app/assets/stylesheets/head/generics/flip.sass +3 -0
- data/app/assets/stylesheets/head/generics/fonts.sass +6 -0
- data/app/assets/stylesheets/head/index.sass +12 -0
- data/app/assets/stylesheets/head/objects/headicon.sass +28 -0
- data/app/assets/stylesheets/head/package.json +5 -0
- data/app/assets/stylesheets/head/settings/_colors.sass +14 -0
- data/app/assets/stylesheets/head/settings/_icons.scss +7 -0
- data/app/assets/stylesheets/head/tools/_cloud.sass +17 -0
- data/app/assets/stylesheets/head/tools/_link.sass +3 -0
- data/app/assets/stylesheets/head/tools/_mandatory.sass +6 -0
- data/app/assets/stylesheets/head/tools/_terminal.sass +3 -0
- data/app/assets/stylesheets/head/tools/_theme.sass +3 -0
- data/app/assets/stylesheets/head/utilities/smokescreen.sass +5 -0
- data/app/components/head/application_component.rb +39 -0
- data/app/components/head/knob.rb +86 -0
- data/app/components/head/theater.rb +87 -0
- data/app/components/head/wing.rb +37 -0
- data/config/importmap.rb +6 -0
- data/config/locales/head.en.yml +1 -0
- data/lib/head/css.rb +10 -0
- data/lib/head/engine.rb +37 -0
- data/lib/head/identicon.rb +53 -0
- data/lib/head/version.rb +5 -0
- data/lib/head.rb +10 -0
- metadata +177 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 11835ad46d870dcdc415a869c67328331f67eff34b8d1e704c2df9b184f48e30
|
4
|
+
data.tar.gz: f913154fbd0cb1b807fec777b50a736b25352232d88d67ea60d2ecc9abc489e2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a79743be804f0101a40d6696fd4266641ac1741bd7451d2e5558ff6b6b90160c6461bb40124b4c8938a903e0101193ff383c7099a7df01c3ba8fa56df961fc92
|
7
|
+
data.tar.gz: 4ec8047baec015c2a05d96914ce983f81e2c4e3c4316980b86d4226a00948d8816039512f4a9a6a8a3a61a5360dbf0f6f266d8b6b734933a29fce3eee7df22cb
|
data/CHANGELOG.md
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) halo
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# Head
|
2
|
+
|
3
|
+
Opinionated ViewComponents for building forms.
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
# In Rails view
|
9
|
+
```
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Install the gem and add to the application's Gemfile by executing:
|
14
|
+
|
15
|
+
bundle add head
|
16
|
+
|
17
|
+
If bundler is not being used to manage dependencies, install the gem by executing:
|
18
|
+
|
19
|
+
gem install head
|
20
|
+
|
21
|
+
## Development
|
22
|
+
|
23
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/ci` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
24
|
+
|
25
|
+
## Testing
|
26
|
+
|
27
|
+
Run one test individually with:
|
28
|
+
|
29
|
+
bundle exec ruby -I test test/lib/wrappers/test_required.rb
|
30
|
+
|
31
|
+
## Contributing
|
32
|
+
|
33
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/halo/head.
|
34
|
+
|
35
|
+
## License
|
36
|
+
|
37
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
Binary file
|
@@ -0,0 +1,228 @@
|
|
1
|
+
{
|
2
|
+
"metadata": {
|
3
|
+
"name": "headicons",
|
4
|
+
"lastOpened": 0,
|
5
|
+
"created": 1759221184557
|
6
|
+
},
|
7
|
+
"iconSets": [
|
8
|
+
{
|
9
|
+
"selection": [
|
10
|
+
{
|
11
|
+
"order": 9,
|
12
|
+
"id": 7,
|
13
|
+
"name": "gear",
|
14
|
+
"prevSize": 32,
|
15
|
+
"code": 59654,
|
16
|
+
"tempChar": ""
|
17
|
+
},
|
18
|
+
{
|
19
|
+
"order": 8,
|
20
|
+
"id": 6,
|
21
|
+
"name": "question-mark",
|
22
|
+
"prevSize": 32,
|
23
|
+
"code": 59648,
|
24
|
+
"tempChar": ""
|
25
|
+
},
|
26
|
+
{
|
27
|
+
"order": 7,
|
28
|
+
"id": 5,
|
29
|
+
"name": "bell-ringing",
|
30
|
+
"prevSize": 32,
|
31
|
+
"code": 59649,
|
32
|
+
"tempChar": ""
|
33
|
+
},
|
34
|
+
{
|
35
|
+
"order": 6,
|
36
|
+
"id": 4,
|
37
|
+
"name": "bell",
|
38
|
+
"prevSize": 32,
|
39
|
+
"code": 59650,
|
40
|
+
"tempChar": ""
|
41
|
+
},
|
42
|
+
{
|
43
|
+
"order": 5,
|
44
|
+
"id": 3,
|
45
|
+
"name": "magnifier",
|
46
|
+
"prevSize": 32,
|
47
|
+
"code": 59651,
|
48
|
+
"tempChar": ""
|
49
|
+
},
|
50
|
+
{
|
51
|
+
"order": 4,
|
52
|
+
"id": 2,
|
53
|
+
"name": "bars-thin",
|
54
|
+
"prevSize": 32,
|
55
|
+
"code": 59652,
|
56
|
+
"tempChar": ""
|
57
|
+
},
|
58
|
+
{
|
59
|
+
"order": 3,
|
60
|
+
"id": 1,
|
61
|
+
"name": "bars-bold",
|
62
|
+
"prevSize": 32,
|
63
|
+
"code": 59653,
|
64
|
+
"tempChar": ""
|
65
|
+
}
|
66
|
+
],
|
67
|
+
"id": 0,
|
68
|
+
"metadata": {
|
69
|
+
"name": "Untitled Set",
|
70
|
+
"importSize": {
|
71
|
+
"width": 24,
|
72
|
+
"height": 24
|
73
|
+
}
|
74
|
+
},
|
75
|
+
"height": 1024,
|
76
|
+
"prevSize": 32,
|
77
|
+
"icons": [
|
78
|
+
{
|
79
|
+
"id": 7,
|
80
|
+
"paths": [
|
81
|
+
"M1024 580.949v-137.899c-70.443-25.045-114.944-32.085-137.344-86.144v-0.043c-22.485-54.229 4.267-91.051 36.139-158.165l-97.493-97.493c-66.603 31.659-103.808 58.667-158.165 36.139h-0.043c-54.144-22.443-61.227-67.243-86.144-137.344h-137.899c-24.832 69.76-31.957 114.859-86.144 137.344h-0.043c-54.229 22.528-90.965-4.181-158.165-36.139l-97.493 97.493c31.787 66.901 58.667 103.851 36.139 158.165-22.485 54.229-67.584 61.355-137.344 86.187v137.899c69.632 24.747 114.859 31.957 137.344 86.144 22.613 54.699-4.864 92.416-36.139 158.165l97.493 97.536c66.645-31.701 103.851-58.667 158.165-36.139h0.043c54.187 22.443 61.269 67.371 86.144 137.344h137.899c24.832-69.803 32-114.773 86.485-137.472h0.043c53.845-22.357 90.453 4.309 157.781 36.309l97.493-97.536c-31.744-66.688-58.667-103.808-36.181-158.123 22.485-54.229 67.755-61.44 137.429-86.229zM512 682.667c-94.251 0-170.667-76.416-170.667-170.667s76.416-170.667 170.667-170.667 170.667 76.416 170.667 170.667-76.416 170.667-170.667 170.667z"
|
82
|
+
],
|
83
|
+
"attrs": [
|
84
|
+
{}
|
85
|
+
],
|
86
|
+
"isMulticolor": false,
|
87
|
+
"isMulticolor2": false,
|
88
|
+
"grid": 0,
|
89
|
+
"tags": [
|
90
|
+
"gear"
|
91
|
+
]
|
92
|
+
},
|
93
|
+
{
|
94
|
+
"id": 6,
|
95
|
+
"paths": [
|
96
|
+
"M622.976 917.333c0 58.88-47.616 106.667-106.624 106.667-58.795 0-106.624-47.787-106.624-106.667s47.829-106.667 106.624-106.667c59.008 0 106.624 47.744 106.624 106.667zM519.723 0c-171.904 0-301.227 114.901-301.227 341.333h168.747c0-98.304 38.656-178.731 129.024-178.731 53.205 0 109.653 35.328 114.517 102.869 5.248 71.083-32.725 107.136-80.725 152.832-124.757 118.613-120.149 172.757-120.149 307.029h168.235c0-61.952-6.699-107.008 78.421-198.784 56.789-61.269 127.403-137.472 128.896-253.568 2.005-169.088-117.376-272.981-285.739-272.981z"
|
97
|
+
],
|
98
|
+
"attrs": [
|
99
|
+
{}
|
100
|
+
],
|
101
|
+
"isMulticolor": false,
|
102
|
+
"isMulticolor2": false,
|
103
|
+
"grid": 0,
|
104
|
+
"tags": [
|
105
|
+
"question-mark"
|
106
|
+
]
|
107
|
+
},
|
108
|
+
{
|
109
|
+
"id": 5,
|
110
|
+
"paths": [
|
111
|
+
"M645.845 168.32c-27.477-15.957-44.459-45.653-44.416-77.653v-0.128c0.043-50.005-40.021-90.539-89.429-90.539s-89.472 40.533-89.472 90.539v0.128c0.043 32.043-16.896 61.696-44.416 77.653-199.125 115.712-84.693 499.84-292.779 567.723v74.624h853.333v-74.624c-208.085-67.883-93.653-452.011-292.821-567.723zM512 42.667c23.552 0 42.667 19.157 42.667 42.667 0 23.552-19.115 42.667-42.667 42.667s-42.667-19.115-42.667-42.667c0-23.509 19.115-42.667 42.667-42.667zM640 896c0 68.181-59.392 128-126.763 128s-129.237-59.819-129.237-128h256zM886.528 397.696c7.68 30.763 2.133 61.696-12.971 86.827l41.387 24.917c21.504-35.755 29.355-79.744 18.475-123.392-10.88-43.691-38.4-78.848-74.197-100.309l-24.832 41.387c25.131 15.147 44.501 39.851 52.139 70.571zM903.424 212.267l-25.472 42.453c43.648 26.283 77.312 69.248 90.667 122.624 13.269 53.376 3.627 107.093-22.613 150.784l42.411 25.515c22.869-38.059 35.627-82.176 35.627-128-0.043-84.48-43.093-166.784-120.619-213.376zM189.611 327.125l-24.832-41.387c-35.797 21.504-63.317 56.619-74.197 100.309-10.88 43.648-3.029 87.595 18.475 123.392l41.387-24.917c-15.104-25.088-20.651-56.064-12.971-86.827 7.637-30.72 27.008-55.424 52.139-70.571zM-0 425.6c0 45.824 12.757 89.941 35.627 128l42.411-25.515c-26.24-43.691-35.883-97.408-22.613-150.784 13.312-53.376 46.976-96.341 90.624-122.581l-25.472-42.453c-77.525 46.592-120.576 128.896-120.576 213.333z"
|
112
|
+
],
|
113
|
+
"attrs": [
|
114
|
+
{}
|
115
|
+
],
|
116
|
+
"isMulticolor": false,
|
117
|
+
"isMulticolor2": false,
|
118
|
+
"grid": 0,
|
119
|
+
"tags": [
|
120
|
+
"bell-ringing"
|
121
|
+
]
|
122
|
+
},
|
123
|
+
{
|
124
|
+
"id": 4,
|
125
|
+
"paths": [
|
126
|
+
"M645.845 168.32c-27.477-15.957-44.459-45.653-44.416-77.653v-0.128c0.043-50.005-40.021-90.539-89.429-90.539s-89.472 40.533-89.472 90.539v0.128c0.043 32.043-16.896 61.696-44.416 77.653-199.125 115.712-84.693 499.84-292.779 567.723v74.624h853.333v-74.624c-208.085-67.883-93.653-452.011-292.821-567.723zM512 42.667c23.552 0 42.667 19.157 42.667 42.667 0 23.552-19.115 42.667-42.667 42.667s-42.667-19.115-42.667-42.667c0-23.509 19.115-42.667 42.667-42.667zM640 896c0 68.181-59.392 128-126.763 128s-129.237-59.819-129.237-128h256z"
|
127
|
+
],
|
128
|
+
"attrs": [
|
129
|
+
{}
|
130
|
+
],
|
131
|
+
"isMulticolor": false,
|
132
|
+
"isMulticolor2": false,
|
133
|
+
"grid": 0,
|
134
|
+
"tags": [
|
135
|
+
"bell"
|
136
|
+
]
|
137
|
+
},
|
138
|
+
{
|
139
|
+
"id": 3,
|
140
|
+
"paths": [
|
141
|
+
"M1015.851 923.563l-264.747-264.747c49.792-68.48 79.232-152.704 79.232-243.669 0-228.907-186.24-415.147-415.189-415.147-228.907 0-415.147 186.24-415.147 415.147 0 228.949 186.24 415.147 415.147 415.147 86.784 0 167.381-26.752 234.112-72.448l266.155 266.155 100.437-100.437zM121.771 415.147c0-161.792 131.627-293.419 293.419-293.419s293.419 131.627 293.419 293.419-131.627 293.419-293.419 293.419c-161.835 0-293.419-131.627-293.419-293.419z"
|
142
|
+
],
|
143
|
+
"attrs": [
|
144
|
+
{}
|
145
|
+
],
|
146
|
+
"isMulticolor": false,
|
147
|
+
"isMulticolor2": false,
|
148
|
+
"grid": 0,
|
149
|
+
"tags": [
|
150
|
+
"magnifier"
|
151
|
+
]
|
152
|
+
},
|
153
|
+
{
|
154
|
+
"id": 2,
|
155
|
+
"paths": [
|
156
|
+
"M1024 757.333c0-21.205-17.195-38.4-38.4-38.4h-947.2c-21.205 0-38.4 17.195-38.4 38.4s17.195 38.4 38.4 38.4h947.2c21.205 0 38.4-17.195 38.4-38.4zM1024 501.333c0-21.205-17.195-38.4-38.4-38.4h-947.2c-21.205 0-38.4 17.195-38.4 38.4s17.195 38.4 38.4 38.4h947.2c21.205 0 38.4-17.195 38.4-38.4zM1024 245.333c0-21.205-17.195-38.4-38.4-38.4h-947.2c-21.205 0-38.4 17.195-38.4 38.4s17.195 38.4 38.4 38.4h947.2c21.205 0 38.4-17.195 38.4-38.4z"
|
157
|
+
],
|
158
|
+
"attrs": [
|
159
|
+
{}
|
160
|
+
],
|
161
|
+
"isMulticolor": false,
|
162
|
+
"isMulticolor2": false,
|
163
|
+
"grid": 0,
|
164
|
+
"tags": [
|
165
|
+
"bars-thin"
|
166
|
+
]
|
167
|
+
},
|
168
|
+
{
|
169
|
+
"id": 1,
|
170
|
+
"paths": [
|
171
|
+
"M1024 256h-1024v-170.667h1024v170.667zM1024 426.667h-1024v170.667h1024v-170.667zM1024 768h-1024v170.667h1024v-170.667z"
|
172
|
+
],
|
173
|
+
"attrs": [
|
174
|
+
{}
|
175
|
+
],
|
176
|
+
"isMulticolor": false,
|
177
|
+
"isMulticolor2": false,
|
178
|
+
"grid": 0,
|
179
|
+
"tags": [
|
180
|
+
"bars-bold"
|
181
|
+
]
|
182
|
+
}
|
183
|
+
],
|
184
|
+
"colorThemes": [],
|
185
|
+
"invisible": false
|
186
|
+
}
|
187
|
+
],
|
188
|
+
"uid": -1,
|
189
|
+
"preferences": {
|
190
|
+
"showGlyphs": true,
|
191
|
+
"showCodes": true,
|
192
|
+
"showQuickUse": true,
|
193
|
+
"showQuickUse2": true,
|
194
|
+
"showSVGs": true,
|
195
|
+
"fontPref": {
|
196
|
+
"prefix": "",
|
197
|
+
"metadata": {
|
198
|
+
"fontFamily": "headicons",
|
199
|
+
"majorVersion": 1,
|
200
|
+
"minorVersion": 0
|
201
|
+
},
|
202
|
+
"metrics": {
|
203
|
+
"emSize": 1024,
|
204
|
+
"baseline": 6.25,
|
205
|
+
"whitespace": 50
|
206
|
+
},
|
207
|
+
"embed": false,
|
208
|
+
"noie8": true,
|
209
|
+
"ie7": false,
|
210
|
+
"cssVars": true,
|
211
|
+
"cssVarsFormat": "scss",
|
212
|
+
"showSelector": true,
|
213
|
+
"selector": "i",
|
214
|
+
"showMetrics": true,
|
215
|
+
"showMetadata": true,
|
216
|
+
"showVersion": true
|
217
|
+
},
|
218
|
+
"imagePref": {
|
219
|
+
"prefix": "icon-",
|
220
|
+
"png": true,
|
221
|
+
"useClassSelector": true,
|
222
|
+
"color": 0,
|
223
|
+
"bgColor": 16777215
|
224
|
+
},
|
225
|
+
"historySize": 50,
|
226
|
+
"gridSize": 16
|
227
|
+
}
|
228
|
+
}
|
@@ -0,0 +1,51 @@
|
|
1
|
+
document.addEventListener('DOMContentLoaded', function () {
|
2
|
+
document.querySelectorAll('.js-head-knob').forEach((knob) => {
|
3
|
+
const href = knob.getAttribute('href')
|
4
|
+
|
5
|
+
// If this knob doesn't open a sidebar, it is a standalone link.
|
6
|
+
if (href != '#') return
|
7
|
+
|
8
|
+
knob.addEventListener('click', function (event) {
|
9
|
+
event.preventDefault()
|
10
|
+
const knob = event.currentTarget
|
11
|
+
|
12
|
+
// The identifier of a knob always matches that of its wing.
|
13
|
+
const identifier = knob.dataset.identifier
|
14
|
+
|
15
|
+
// Check screen size
|
16
|
+
const mainMenuWing = document.querySelector(`.js-head-wing[data-identifier="mainmenu"]`)
|
17
|
+
const tight = getComputedStyle(mainMenuWing).getPropertyValue('position') == 'absolute'
|
18
|
+
|
19
|
+
// Handle current wing
|
20
|
+
const wing = document.querySelector(`.js-head-wing[data-identifier="${identifier}"]`)
|
21
|
+
const visible = getComputedStyle(wing).getPropertyValue('display') == 'block'
|
22
|
+
const group = knob.dataset.group
|
23
|
+
|
24
|
+
// Always close sidebars on the same side of the screen (left/right)
|
25
|
+
document.querySelectorAll(`.js-head-wing[data-group="${group}"]`).forEach((someWing) => {
|
26
|
+
someWing.classList.remove('is-active')
|
27
|
+
someWing.classList.add('is-force-deactive')
|
28
|
+
})
|
29
|
+
|
30
|
+
if (tight) {
|
31
|
+
// On small screens, only ever show one menu, so close all others.
|
32
|
+
document.querySelectorAll('.js-head-wing').forEach((someWing) => {
|
33
|
+
if (someWing != wing) {
|
34
|
+
someWing.classList.remove('is-active')
|
35
|
+
someWing.classList.add('is-force-deactive')
|
36
|
+
}
|
37
|
+
})
|
38
|
+
}
|
39
|
+
|
40
|
+
// Now toggle the desired one.
|
41
|
+
if (visible) {
|
42
|
+
wing.classList.remove('is-active')
|
43
|
+
wing.classList.add('is-force-deactive')
|
44
|
+
} else {
|
45
|
+
wing.classList.add('is-active')
|
46
|
+
wing.classList.remove('is-force-deactive')
|
47
|
+
}
|
48
|
+
})
|
49
|
+
|
50
|
+
})
|
51
|
+
})
|
@@ -0,0 +1,18 @@
|
|
1
|
+
document.addEventListener('DOMContentLoaded', function() {
|
2
|
+
|
3
|
+
document.querySelectorAll('.js-head-wing__curtain').forEach(function (item) {
|
4
|
+
console.debug("Binding to Head Wing Curtain")
|
5
|
+
|
6
|
+
item.addEventListener('click', function(event) {
|
7
|
+
event.preventDefault()
|
8
|
+
|
9
|
+
const wing = event.currentTarget.parentNode
|
10
|
+
const identifier = wing.dataset.identifier
|
11
|
+
|
12
|
+
document.querySelectorAll(`.js-head-knob[data-identifier="${identifier}"]`).forEach(function (knob) {
|
13
|
+
knob.click()
|
14
|
+
})
|
15
|
+
})
|
16
|
+
})
|
17
|
+
|
18
|
+
})
|
@@ -0,0 +1,49 @@
|
|
1
|
+
@use "iglu/font-size"
|
2
|
+
@use "iglu/spacing"
|
3
|
+
@use "head/settings/colors"
|
4
|
+
@use "head/tools/link"
|
5
|
+
|
6
|
+
.c-head-knob
|
7
|
+
display: grid
|
8
|
+
padding-left: 0.25em
|
9
|
+
padding-right: 0.25em
|
10
|
+
text-decoration: none
|
11
|
+
+spacing.padding-vertical--tiny
|
12
|
+
+font-size.gigantic
|
13
|
+
|
14
|
+
+link.states
|
15
|
+
color: colors.$steel-gray
|
16
|
+
|
17
|
+
&:hover
|
18
|
+
color: colors.$silver-gray
|
19
|
+
|
20
|
+
&:active
|
21
|
+
color: colors.$white
|
22
|
+
|
23
|
+
&--identicon
|
24
|
+
max-width: 1em
|
25
|
+
border-radius: 50%
|
26
|
+
aspect-ratio: 1
|
27
|
+
display: grid
|
28
|
+
place-items: center
|
29
|
+
overflow: hidden
|
30
|
+
|
31
|
+
svg
|
32
|
+
width: 100%
|
33
|
+
height: 100%
|
34
|
+
object-fit: contain
|
35
|
+
|
36
|
+
&--avatar
|
37
|
+
max-width: 1em
|
38
|
+
border-radius: 50%
|
39
|
+
aspect-ratio: 1
|
40
|
+
display: grid
|
41
|
+
place-items: center
|
42
|
+
overflow: hidden
|
43
|
+
|
44
|
+
img
|
45
|
+
width: 100%
|
46
|
+
height: 100%
|
47
|
+
object-fit: contain
|
48
|
+
clip-path: circle()
|
49
|
+
background-color: #fff
|
@@ -0,0 +1,55 @@
|
|
1
|
+
@use "iglu/spacing"
|
2
|
+
@use "head/settings/colors"
|
3
|
+
|
4
|
+
.c-head-theater
|
5
|
+
height: 100%
|
6
|
+
display: grid
|
7
|
+
grid-template-rows: auto 1fr
|
8
|
+
|
9
|
+
&__roof
|
10
|
+
background-color: #444
|
11
|
+
display: grid
|
12
|
+
align-items: center
|
13
|
+
grid-template-columns: auto 1fr auto
|
14
|
+
grid-template-areas: "knobs--left logo knobs--right"
|
15
|
+
|
16
|
+
@each $column in knobs--left logo knobs--right
|
17
|
+
&__#{$column}
|
18
|
+
grid-area: #{$column}
|
19
|
+
|
20
|
+
&__knobs
|
21
|
+
display: flex
|
22
|
+
white-space: nowrap
|
23
|
+
|
24
|
+
&--left
|
25
|
+
+spacing.margin-left--smaller
|
26
|
+
|
27
|
+
&--right
|
28
|
+
justify-content: flex-end
|
29
|
+
+spacing.margin-right--smaller
|
30
|
+
|
31
|
+
&__logo
|
32
|
+
display: flex
|
33
|
+
justify-content: center
|
34
|
+
position: relative
|
35
|
+
color: colors.$white
|
36
|
+
padding: 0.3rem
|
37
|
+
overflow: auto // Clip wide logos on small screens
|
38
|
+
|
39
|
+
&:active
|
40
|
+
top: 1px
|
41
|
+
|
42
|
+
&__stage
|
43
|
+
display: grid
|
44
|
+
// So we can track the width of the curtain
|
45
|
+
container-type: inline-size
|
46
|
+
grid-template-columns: auto 1fr auto
|
47
|
+
grid-template-areas: "wings--left content wings--right"
|
48
|
+
|
49
|
+
&__wings
|
50
|
+
&--right
|
51
|
+
position: relative
|
52
|
+
|
53
|
+
@each $column in wings--left content wings--right
|
54
|
+
&__#{$column}
|
55
|
+
grid-area: #{$column}
|
@@ -0,0 +1,70 @@
|
|
1
|
+
@use "iglu/responsive"
|
2
|
+
@use "head/settings/colors"
|
3
|
+
|
4
|
+
.c-head-wing
|
5
|
+
display: none
|
6
|
+
// 320px is the min screen width we support.
|
7
|
+
// Our sidebar cannot be bigger, and it needs to leave some space
|
8
|
+
// at the right so that a click/tap there can close the sidebar.
|
9
|
+
max-width: 265px
|
10
|
+
height: 100%
|
11
|
+
z-index: 1000
|
12
|
+
position: absolute
|
13
|
+
background: colors.$granite-gray
|
14
|
+
color: colors.$white
|
15
|
+
|
16
|
+
&--left
|
17
|
+
// On rather large screens, always show the main menu in left sidebar
|
18
|
+
+responsive.xlarge-container
|
19
|
+
position: static
|
20
|
+
|
21
|
+
&[data-identifier="mainmenu"]
|
22
|
+
// We "force" this item to be active without having the `is-active` class.
|
23
|
+
display: block
|
24
|
+
// So we need some way to deactivate it again using JS.
|
25
|
+
&.is-force-deactive
|
26
|
+
display: none
|
27
|
+
|
28
|
+
&--right
|
29
|
+
right: 0
|
30
|
+
|
31
|
+
// On very very large screens, show notifications sidebar on the right.
|
32
|
+
+responsive.xxlarge-container
|
33
|
+
position: static
|
34
|
+
|
35
|
+
&[data-identifier="notifications"]
|
36
|
+
display: block
|
37
|
+
|
38
|
+
&.is-force-deactive
|
39
|
+
display: none
|
40
|
+
|
41
|
+
&.is-active
|
42
|
+
display: block
|
43
|
+
|
44
|
+
|
45
|
+
&__curtain
|
46
|
+
position: absolute
|
47
|
+
top: 0
|
48
|
+
left: 100%
|
49
|
+
width: 100vw
|
50
|
+
height: 100%
|
51
|
+
z-index: 1001
|
52
|
+
|
53
|
+
&--right
|
54
|
+
right: 100%
|
55
|
+
left: inherit
|
56
|
+
|
57
|
+
+responsive.xlarge-container
|
58
|
+
display: none
|
59
|
+
|
60
|
+
|
61
|
+
// +responsive.xxlarge
|
62
|
+
// .c-head-wing
|
63
|
+
|
64
|
+
// // We "force" this item to be active without having the `is-active` class.
|
65
|
+
// &[data-identifier="mainmenu"]
|
66
|
+
// display: block
|
67
|
+
|
68
|
+
// // So we need some way to deactivate it again using JS.
|
69
|
+
// &.is-force-deactive
|
70
|
+
// display: none
|
@@ -0,0 +1,28 @@
|
|
1
|
+
@use 'head/settings/icons'
|
2
|
+
|
3
|
+
.o-headicon
|
4
|
+
font-family: "headicons"
|
5
|
+
speak: none
|
6
|
+
font-style: normal
|
7
|
+
font-weight: normal
|
8
|
+
font-variant: normal
|
9
|
+
text-transform: none
|
10
|
+
|
11
|
+
// &:before
|
12
|
+
// vertical-align: middle
|
13
|
+
|
14
|
+
.o-headicon--bars-bold
|
15
|
+
&:before
|
16
|
+
content: icons.$bars-bold
|
17
|
+
|
18
|
+
.o-headicon--magnifier
|
19
|
+
&:before
|
20
|
+
content: icons.$magnifier
|
21
|
+
|
22
|
+
.o-headicon--bell
|
23
|
+
&:before
|
24
|
+
content: icons.$bell
|
25
|
+
|
26
|
+
.o-headicon--gear
|
27
|
+
&:before
|
28
|
+
content: icons.$gear
|
@@ -0,0 +1,14 @@
|
|
1
|
+
@use "sass:color"
|
2
|
+
|
3
|
+
$black: #222
|
4
|
+
$white: #fff
|
5
|
+
|
6
|
+
$paradise-pink: rgb(240, 30, 80)
|
7
|
+
$neon-yellow: #ffd400
|
8
|
+
$jade-green: rgb(0, 190, 130)
|
9
|
+
|
10
|
+
$granite-gray: rgb(70, 70, 70)
|
11
|
+
$steel-gray: color.adjust($granite-gray, $lightness: 25%)
|
12
|
+
$silver-gray: color.adjust($granite-gray, $lightness: 50%)
|
13
|
+
|
14
|
+
$transparent-gray: rgba(100, 100, 100, 0.5)
|
@@ -0,0 +1,17 @@
|
|
1
|
+
=state
|
2
|
+
&.is-loading,
|
3
|
+
&.is-saved,
|
4
|
+
&.is-failed
|
5
|
+
background-position: right 0.29rem bottom 0.29rem
|
6
|
+
background-repeat: no-repeat
|
7
|
+
background-size: 22px 22px
|
8
|
+
|
9
|
+
&.is-loading
|
10
|
+
background-image: url("data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" width=\"1024\" height=\"1024\" viewBox=\"0 0 1024 1024\"><path d=\"M512 213.333c147.328 0 251.349 119.339 237.525 289.28 74.453-1.963 189.141 32.043 189.141 158.72 0 82.347-66.987 149.333-149.333 149.333h-554.667c-82.347 0-149.333-66.987-149.333-149.333 0-119.339 105.771-163.541 189.141-158.72-7.125-179.968 94.208-289.28 237.525-289.28zM512 128c-170.923 0-310.059 134.016-319.104 302.592-109.653 19.755-192.896 115.456-192.896 230.741 0 129.579 105.088 234.667 234.667 234.667h554.667c129.579 0 234.667-105.088 234.667-234.667 0-115.285-83.243-210.987-192.896-230.741-9.045-168.576-148.181-302.592-319.104-302.592zM682.667 554.667h-128v170.667h-85.333v-170.667h-128l170.667-170.667 170.667 170.667z\" style=\"fill: rgba(139, 139, 139, 0.243)\"></path></svg>")
|
11
|
+
|
12
|
+
&.is-saved
|
13
|
+
background-image: url("data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" width=\"1024\" height=\"1024\" viewBox=\"0 0 1024 1024\"><path d=\"M512 213.333c147.328 0 251.349 119.339 237.525 289.28 74.453-1.963 189.141 32.043 189.141 158.72 0 82.347-66.987 149.333-149.333 149.333h-554.667c-82.347 0-149.333-66.987-149.333-149.333 0-119.339 105.771-163.541 189.141-158.72-7.125-179.968 94.208-289.28 237.525-289.28zM512 128c-170.923 0-310.059 134.016-319.104 302.592-109.653 19.755-192.896 115.456-192.896 230.741 0 129.579 105.088 234.667 234.667 234.667h554.667c129.579 0 234.667-105.088 234.667-234.667 0-115.285-83.243-210.987-192.896-230.741-9.045-168.576-148.181-302.592-319.104-302.592zM682.667 554.667h-128v170.667h-85.333v-170.667h-128l170.667-170.667 170.667 170.667z\" style=\"fill: rgb(0, 163, 0)\"></path></svg>")
|
14
|
+
|
15
|
+
&.is-failed
|
16
|
+
background-image: url("data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" width=\"1024\" height=\"1024\" viewBox=\"0 0 1024 1024\"><path d=\"M512 213.333c147.328 0 251.349 119.339 237.525 289.28 74.453-1.963 189.141 32.043 189.141 158.72 0 82.347-66.987 149.333-149.333 149.333h-554.667c-82.347 0-149.333-66.987-149.333-149.333 0-119.339 105.771-163.541 189.141-158.72-7.125-179.968 94.208-289.28 237.525-289.28zM512 128c-170.923 0-310.059 134.016-319.104 302.592-109.653 19.755-192.896 115.456-192.896 230.741 0 129.579 105.088 234.667 234.667 234.667h554.667c129.579 0 234.667-105.088 234.667-234.667 0-115.285-83.243-210.987-192.896-230.741-9.045-168.576-148.181-302.592-319.104-302.592zM682.667 554.667h-128v170.667h-85.333v-170.667h-128l170.667-170.667 170.667 170.667z\" style=\"fill: rgb(185, 1, 1)\"></path></svg>")
|
17
|
+
background-color: red
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Head
|
4
|
+
# A component that every other component inherits from in this gem.
|
5
|
+
# It adds convenience methods for initialization of a component.
|
6
|
+
class ApplicationComponent < ViewComponent::Base
|
7
|
+
extend Dry::Initializer
|
8
|
+
|
9
|
+
# By default, Dry::Initializer doesn't complain about invalid arguments.
|
10
|
+
# We want it to raise an error.
|
11
|
+
def initialize(...)
|
12
|
+
__check_for_unknown_options(...)
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def __check_for_unknown_options(*args, **kwargs)
|
19
|
+
return if __defined_options.empty?
|
20
|
+
|
21
|
+
# Checking params
|
22
|
+
opts = args.drop(__defined_params.length).first || kwargs
|
23
|
+
raise ArgumentError, "Unexpected argument #{opts}" unless opts.is_a? Hash
|
24
|
+
|
25
|
+
# Checking options
|
26
|
+
unknown_options = opts.keys - __defined_options
|
27
|
+
message = "Key(s) #{unknown_options} not found in #{__defined_options} of #{self.class}"
|
28
|
+
raise KeyError, message if unknown_options.any?
|
29
|
+
end
|
30
|
+
|
31
|
+
def __defined_options
|
32
|
+
self.class.dry_initializer.options.map(&:source)
|
33
|
+
end
|
34
|
+
|
35
|
+
def __defined_params
|
36
|
+
self.class.dry_initializer.params.map(&:source)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Head
|
4
|
+
class Knob < ApplicationComponent
|
5
|
+
erb_template <<~ERB
|
6
|
+
<%= link_to(url, class: classes, data: { identifier: id, group: group }, **options.except(:url)) do %>
|
7
|
+
<% if icon %>
|
8
|
+
<i class="o-headicon <%= icon_class%><%= %>"></i>
|
9
|
+
<% end %>
|
10
|
+
|
11
|
+
<%= content %>
|
12
|
+
<% end %>
|
13
|
+
ERB
|
14
|
+
|
15
|
+
option :preset, default: -> {}
|
16
|
+
option :right, default: -> { false }
|
17
|
+
option :id, as: :manual_id, default: -> { false }
|
18
|
+
option :icon, as: :manual_icon, default: -> {}
|
19
|
+
option :url, as: :manual_url, default: -> {}
|
20
|
+
option :options, default: -> { {} }
|
21
|
+
|
22
|
+
def id
|
23
|
+
manual_id || preset
|
24
|
+
end
|
25
|
+
|
26
|
+
def icon
|
27
|
+
return manual_icon if manual_icon
|
28
|
+
return :'bars-bold' if preset_mainmenu?
|
29
|
+
return :bell if preset_notifications?
|
30
|
+
return :gear if preset_settings?
|
31
|
+
|
32
|
+
:magnifier if preset_search?
|
33
|
+
end
|
34
|
+
|
35
|
+
def icon_class
|
36
|
+
"o-headicon--#{icon.to_sym.to_s.gsub('_', '-')}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def url
|
40
|
+
manual_url || options[:url] || '#'
|
41
|
+
end
|
42
|
+
|
43
|
+
def classes
|
44
|
+
result = %w[c-head-knob js-head-knob]
|
45
|
+
result.push 'c-head-knob--identicon' if preset_identicon?
|
46
|
+
result.push 'c-head-knob--avatar' if preset_avatar?
|
47
|
+
result
|
48
|
+
end
|
49
|
+
|
50
|
+
def group
|
51
|
+
left? ? :left : :right
|
52
|
+
end
|
53
|
+
|
54
|
+
def left?
|
55
|
+
!right?
|
56
|
+
end
|
57
|
+
|
58
|
+
def right?
|
59
|
+
@right
|
60
|
+
end
|
61
|
+
|
62
|
+
def preset_mainmenu?
|
63
|
+
preset == :mainmenu
|
64
|
+
end
|
65
|
+
|
66
|
+
def preset_search?
|
67
|
+
preset == :search
|
68
|
+
end
|
69
|
+
|
70
|
+
def preset_identicon?
|
71
|
+
preset == :identicon
|
72
|
+
end
|
73
|
+
|
74
|
+
def preset_avatar?
|
75
|
+
preset == :avatar
|
76
|
+
end
|
77
|
+
|
78
|
+
def preset_notifications?
|
79
|
+
preset == :notifications
|
80
|
+
end
|
81
|
+
|
82
|
+
def preset_settings?
|
83
|
+
preset == :settings
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Head
|
4
|
+
class Theater < ApplicationComponent
|
5
|
+
erb_template <<~ERB
|
6
|
+
<div class="c-head-theater">
|
7
|
+
<div class="c-head-theater__roof">
|
8
|
+
|
9
|
+
<div class="c-head-theater__knobs c-head-theater__knobs--left">
|
10
|
+
<% Array(knobs).select(&:left?).each do |knob| %>
|
11
|
+
<%= knob %>
|
12
|
+
<% end %>
|
13
|
+
</div>
|
14
|
+
|
15
|
+
<div class="c-head-theater__logo">
|
16
|
+
<%= logo %>
|
17
|
+
</div>
|
18
|
+
|
19
|
+
<div class="c-head-theater__knobs c-head-theater__knobs--right">
|
20
|
+
<% Array(knobs).select(&:right).each do |knob| %>
|
21
|
+
<%= knob %>
|
22
|
+
<% end %>
|
23
|
+
</div>
|
24
|
+
|
25
|
+
</div>
|
26
|
+
<div class="c-head-theater__stage">
|
27
|
+
|
28
|
+
<div class="c-head-theater__wings c-head-theater__wings--left">
|
29
|
+
<%# fail wings.first.content.inspect %>
|
30
|
+
<% Array(wings).select(&:left?).each do |wing| %>
|
31
|
+
<%= wing %>
|
32
|
+
<% end %>
|
33
|
+
</div>
|
34
|
+
|
35
|
+
<div class="c-head-theater__content">
|
36
|
+
<%= body %>
|
37
|
+
</div>
|
38
|
+
|
39
|
+
<div class="c-head-theater__wings c-head-theater__wings--right">
|
40
|
+
<% Array(wings).select(&:right?).each do |wing| %>
|
41
|
+
<%= wing %>
|
42
|
+
<% end %>
|
43
|
+
</div>
|
44
|
+
</div>
|
45
|
+
</div>
|
46
|
+
ERB
|
47
|
+
|
48
|
+
def with_mainmenu(&)
|
49
|
+
with_knob(preset: :mainmenu)
|
50
|
+
with_wing(id: :mainmenu, &)
|
51
|
+
end
|
52
|
+
|
53
|
+
def with_notifications(&)
|
54
|
+
with_knob(preset: :notifications, right: true)
|
55
|
+
with_wing(id: :notifications, right: true, &)
|
56
|
+
end
|
57
|
+
|
58
|
+
def with_settings(&)
|
59
|
+
with_knob(preset: :settings, right: true)
|
60
|
+
with_wing(id: :settings, right: true, &)
|
61
|
+
end
|
62
|
+
|
63
|
+
def with_search(**options)
|
64
|
+
with_knob(preset: :search, options:)
|
65
|
+
end
|
66
|
+
|
67
|
+
def with_identicon(username:, &)
|
68
|
+
with_knob(preset: :identicon, right: true) do
|
69
|
+
::Head::Identicon.new(username.to_s).to_svg
|
70
|
+
end
|
71
|
+
with_wing(id: :identicon, right: true, &)
|
72
|
+
end
|
73
|
+
|
74
|
+
def with_avatar(image:, &)
|
75
|
+
with_knob(preset: :avatar, right: true) do
|
76
|
+
image_tag(image)
|
77
|
+
end
|
78
|
+
with_wing(id: :avatar, right: true, &)
|
79
|
+
end
|
80
|
+
|
81
|
+
renders_many :knobs, ::Head::Knob
|
82
|
+
renders_many :wings, ::Head::Wing
|
83
|
+
|
84
|
+
renders_one :logo
|
85
|
+
renders_one :body
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Head
|
4
|
+
class Wing < ApplicationComponent
|
5
|
+
erb_template <<~ERB
|
6
|
+
<div class="<%= classes.join(' ') %>" data-identifier="<%= id %>" data-group="<%= group %>">
|
7
|
+
<%= content %>
|
8
|
+
<div class="c-head-wing__curtain c-head-wing__curtain--<%= group %> js-head-wing__curtain u-head-smokescreen">
|
9
|
+
</div>
|
10
|
+
</div>
|
11
|
+
ERB
|
12
|
+
|
13
|
+
option :id, as: :id, default: -> {}
|
14
|
+
option :right, default: -> { false }
|
15
|
+
|
16
|
+
def self.mainmenu
|
17
|
+
new(id: :mainmenu)
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
def classes
|
22
|
+
%W[c-head-wing c-head-wing--#{group} js-head-wing]
|
23
|
+
end
|
24
|
+
|
25
|
+
def group
|
26
|
+
left? ? :left : :right
|
27
|
+
end
|
28
|
+
|
29
|
+
def left?
|
30
|
+
!right?
|
31
|
+
end
|
32
|
+
|
33
|
+
def right?
|
34
|
+
@right
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/config/importmap.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
en:
|
data/lib/head/css.rb
ADDED
data/lib/head/engine.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails/engine'
|
4
|
+
|
5
|
+
module Head
|
6
|
+
# :nodoc:
|
7
|
+
class Engine < ::Rails::Engine
|
8
|
+
isolate_namespace Head
|
9
|
+
|
10
|
+
config.autoload_paths << root.join('lib')
|
11
|
+
|
12
|
+
initializer 'head.importmap', before: 'importmap' do |app|
|
13
|
+
app.config.importmap.paths << Engine.root.join('config/importmap.rb')
|
14
|
+
# Watch JS changes in development
|
15
|
+
app.config.importmap.cache_sweepers << Engine.root.join('app/assets/javascripts')
|
16
|
+
end
|
17
|
+
|
18
|
+
config.to_prepare do
|
19
|
+
# Our Head components are subclasses of `ViewComponent::Base`.
|
20
|
+
# When `ViewComponent::Base` is subclassed, two things happen:
|
21
|
+
#
|
22
|
+
# 1. Rails routes are included into the component
|
23
|
+
# 2. The ViewComponent configuration is accessed
|
24
|
+
#
|
25
|
+
# So we can only require our components, once Rails has booted
|
26
|
+
# AND the view_component gem has been fully initialized (configured).
|
27
|
+
#
|
28
|
+
# That's right here and now.
|
29
|
+
require_relative '../../app/components/head/application_component'
|
30
|
+
|
31
|
+
# Components
|
32
|
+
require_relative '../../app/components/head/wing'
|
33
|
+
require_relative '../../app/components/head/knob'
|
34
|
+
require_relative '../../app/components/head/theater'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'digest/md5'
|
4
|
+
|
5
|
+
module Head
|
6
|
+
class Identicon
|
7
|
+
DARK_COLORS = %w[#39FF14 #FF3131 #1F51FF #FFE700 #F000FF #7FFF00 #CCFF00 #FF5E00 #00FFFF].freeze
|
8
|
+
LIGHT_COLORS = [
|
9
|
+
'A799B7', # gray
|
10
|
+
'E384FF', # rose
|
11
|
+
'c300cE', # purple
|
12
|
+
'F8DE22', # yellow
|
13
|
+
'9EDDFF', # light blue
|
14
|
+
'FF004D', # red
|
15
|
+
'F72798', # pink
|
16
|
+
'FFAF00', # orange
|
17
|
+
'39FF14' # neon grass green
|
18
|
+
].freeze
|
19
|
+
GRID_SIZE = 5
|
20
|
+
HALF_GRID = (GRID_SIZE / 2.0).round
|
21
|
+
DENSITY = 0.5
|
22
|
+
|
23
|
+
def initialize(input, theme: :light)
|
24
|
+
@seed = Digest::MD5.hexdigest(input).to_i(16)
|
25
|
+
@random = Random.new(@seed)
|
26
|
+
colors = theme == :light ? LIGHT_COLORS : DARK_COLORS
|
27
|
+
@color = colors[@seed % (LIGHT_COLORS.size - 1)]
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_svg
|
31
|
+
svg = +%(<svg viewBox="0 0 5 5" xmlns="http://www.w3.org/2000/svg" fill="" shape-rendering="crispEdges">)
|
32
|
+
GRID_SIZE.times do |row|
|
33
|
+
HALF_GRID.times do |column|
|
34
|
+
add_pixel(column, row, svg) if @random.rand < DENSITY
|
35
|
+
end
|
36
|
+
end
|
37
|
+
svg << '</svg>'
|
38
|
+
svg.html_safe
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def add_pixel(column, row, svg)
|
44
|
+
positions = [[column, row]]
|
45
|
+
mirrored_column = GRID_SIZE - 1 - column
|
46
|
+
positions << [mirrored_column, row] unless column == mirrored_column
|
47
|
+
|
48
|
+
positions.each do |current_column, current_row|
|
49
|
+
svg << %(<rect x="#{current_column}" y="#{current_row}" width="1" height="1" fill="##{@color}"></rect>)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/head/version.rb
ADDED
data/lib/head.rb
ADDED
metadata
ADDED
@@ -0,0 +1,177 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: head
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- halo
|
8
|
+
bindir: bin
|
9
|
+
cert_chain: []
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
11
|
+
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: actionview
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - ">="
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '0'
|
19
|
+
type: :runtime
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - ">="
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: '0'
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: calls
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
- !ruby/object:Gem::Dependency
|
41
|
+
name: countries
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
type: :runtime
|
48
|
+
prerelease: false
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: dry-initializer
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
type: :runtime
|
62
|
+
prerelease: false
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
- !ruby/object:Gem::Dependency
|
69
|
+
name: holidays
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
type: :runtime
|
76
|
+
prerelease: false
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
name: importmap-rails
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
type: :runtime
|
90
|
+
prerelease: false
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
- !ruby/object:Gem::Dependency
|
97
|
+
name: view_component
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
type: :runtime
|
104
|
+
prerelease: false
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
description: With sidebars that work well on all screen widths.
|
111
|
+
email:
|
112
|
+
- github@posteo.org
|
113
|
+
executables: []
|
114
|
+
extensions: []
|
115
|
+
extra_rdoc_files: []
|
116
|
+
files:
|
117
|
+
- CHANGELOG.md
|
118
|
+
- LICENSE.txt
|
119
|
+
- README.md
|
120
|
+
- app/assets/fonts/head/headicons.woff
|
121
|
+
- app/assets/fonts/icomoon.json
|
122
|
+
- app/assets/javascript/head/index.js
|
123
|
+
- app/assets/javascript/head/knob.js
|
124
|
+
- app/assets/javascript/head/wing.js
|
125
|
+
- app/assets/stylesheets/head/components/knob.sass
|
126
|
+
- app/assets/stylesheets/head/components/theater.sass
|
127
|
+
- app/assets/stylesheets/head/components/wing.sass
|
128
|
+
- app/assets/stylesheets/head/generics/flip.sass
|
129
|
+
- app/assets/stylesheets/head/generics/fonts.sass
|
130
|
+
- app/assets/stylesheets/head/index.sass
|
131
|
+
- app/assets/stylesheets/head/objects/headicon.sass
|
132
|
+
- app/assets/stylesheets/head/package.json
|
133
|
+
- app/assets/stylesheets/head/settings/_colors.sass
|
134
|
+
- app/assets/stylesheets/head/settings/_icons.scss
|
135
|
+
- app/assets/stylesheets/head/tools/_cloud.sass
|
136
|
+
- app/assets/stylesheets/head/tools/_link.sass
|
137
|
+
- app/assets/stylesheets/head/tools/_mandatory.sass
|
138
|
+
- app/assets/stylesheets/head/tools/_terminal.sass
|
139
|
+
- app/assets/stylesheets/head/tools/_theme.sass
|
140
|
+
- app/assets/stylesheets/head/utilities/smokescreen.sass
|
141
|
+
- app/components/head/application_component.rb
|
142
|
+
- app/components/head/knob.rb
|
143
|
+
- app/components/head/theater.rb
|
144
|
+
- app/components/head/wing.rb
|
145
|
+
- config/importmap.rb
|
146
|
+
- config/locales/head.en.yml
|
147
|
+
- lib/head.rb
|
148
|
+
- lib/head/css.rb
|
149
|
+
- lib/head/engine.rb
|
150
|
+
- lib/head/identicon.rb
|
151
|
+
- lib/head/version.rb
|
152
|
+
homepage: https://github.com/halo/head
|
153
|
+
licenses:
|
154
|
+
- MIT
|
155
|
+
metadata:
|
156
|
+
homepage_uri: https://github.com/halo/head
|
157
|
+
source_code_uri: https://github.com/halo/head
|
158
|
+
changelog_uri: https://github.com/halo/halo/blob/main/CHANGELOG.md
|
159
|
+
rubygems_mfa_required: 'true'
|
160
|
+
rdoc_options: []
|
161
|
+
require_paths:
|
162
|
+
- lib
|
163
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
164
|
+
requirements:
|
165
|
+
- - ">="
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: '3.4'
|
168
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
169
|
+
requirements:
|
170
|
+
- - ">="
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: '0'
|
173
|
+
requirements: []
|
174
|
+
rubygems_version: 3.7.2
|
175
|
+
specification_version: 4
|
176
|
+
summary: A simple, opinionated navigation menu ViewComponent
|
177
|
+
test_files: []
|