easyfaa 0.20.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +558 -0
- data/MIT-LICENSE +22 -0
- data/README.md +256 -0
- data/app/views/layouts/easyfaa.html.erb +24 -0
- data/app/views/recourses/_head.html.erb +3 -0
- data/art/autopilot.svg +9 -0
- data/art/cube.svg +9 -0
- data/art/design.svg +8 -0
- data/art/down.html.erb +95 -0
- data/art/easyfaa.svg +7 -0
- data/art/fountain.svg +9 -0
- data/art/goldrush.svg +7 -0
- data/art/houston.svg +8 -0
- data/art/icons.txt +185 -0
- data/art/index.html.erb +157 -0
- data/config/locales/easyfaa.en.yml +7 -0
- data/lib/easyfaa/copy.rb +5 -0
- data/lib/easyfaa/down.rb +19 -0
- data/lib/easyfaa/engine.rb +53 -0
- data/lib/easyfaa/helpers/flows.rb +53 -0
- data/lib/easyfaa/helpers/heads.rb +60 -0
- data/lib/easyfaa/helpers/logos.rb +43 -0
- data/lib/easyfaa/helpers.rb +11 -0
- data/lib/easyfaa/marks.rb +16 -0
- data/lib/easyfaa/version.rb +4 -0
- data/lib/easyfaa.rb +39 -0
- data/public/404.html +118 -0
- data/public/_headers +28 -0
- data/public/bh/css/bh.css +1 -0
- data/public/bh/js/bh.js +152 -0
- data/public/bh/theme/bootstrap.css +10 -0
- data/public/bh/theme/dawn.css +189 -0
- data/public/bh/theme/dracula.css +189 -0
- data/public/bh/theme/gruvbox.css +189 -0
- data/public/bh/theme/monokai.css +190 -0
- data/public/bh/theme/nord.css +189 -0
- data/public/bh/theme/one_dark.css +189 -0
- data/public/bh/theme/solarized.css +188 -0
- data/public/bh/theme/tokyo_night.css +189 -0
- data/public/css/easyfaa.css +1 -0
- data/public/down/autopilot.html +87 -0
- data/public/down/cube.html +87 -0
- data/public/down/design.html +87 -0
- data/public/down/easyfaa.html +84 -0
- data/public/down/fountain.html +87 -0
- data/public/down/goldrush.html +87 -0
- data/public/down/houston.html +87 -0
- data/public/favicon/autopilot-180.png +0 -0
- data/public/favicon/autopilot-192.png +0 -0
- data/public/favicon/autopilot-512.png +0 -0
- data/public/favicon/autopilot-96.png +0 -0
- data/public/favicon/autopilot-dev.svg +9 -0
- data/public/favicon/autopilot.ico +0 -0
- data/public/favicon/autopilot.svg +9 -0
- data/public/favicon/autopilot.webmanifest +12 -0
- data/public/favicon/cube-180.png +0 -0
- data/public/favicon/cube-192.png +0 -0
- data/public/favicon/cube-512.png +0 -0
- data/public/favicon/cube-96.png +0 -0
- data/public/favicon/cube-dev.svg +9 -0
- data/public/favicon/cube.ico +0 -0
- data/public/favicon/cube.svg +9 -0
- data/public/favicon/cube.webmanifest +12 -0
- data/public/favicon/design-180.png +0 -0
- data/public/favicon/design-192.png +0 -0
- data/public/favicon/design-512.png +0 -0
- data/public/favicon/design-96.png +0 -0
- data/public/favicon/design-dev.svg +8 -0
- data/public/favicon/design.ico +0 -0
- data/public/favicon/design.svg +8 -0
- data/public/favicon/design.webmanifest +12 -0
- data/public/favicon/easyfaa-180.png +0 -0
- data/public/favicon/easyfaa-192.png +0 -0
- data/public/favicon/easyfaa-512.png +0 -0
- data/public/favicon/easyfaa-96.png +0 -0
- data/public/favicon/easyfaa-dev.svg +7 -0
- data/public/favicon/easyfaa.ico +0 -0
- data/public/favicon/easyfaa.svg +7 -0
- data/public/favicon/easyfaa.webmanifest +12 -0
- data/public/favicon/fountain-180.png +0 -0
- data/public/favicon/fountain-192.png +0 -0
- data/public/favicon/fountain-512.png +0 -0
- data/public/favicon/fountain-96.png +0 -0
- data/public/favicon/fountain-dev.svg +9 -0
- data/public/favicon/fountain.ico +0 -0
- data/public/favicon/fountain.svg +9 -0
- data/public/favicon/fountain.webmanifest +12 -0
- data/public/favicon/goldrush-180.png +0 -0
- data/public/favicon/goldrush-192.png +0 -0
- data/public/favicon/goldrush-512.png +0 -0
- data/public/favicon/goldrush-96.png +0 -0
- data/public/favicon/goldrush-dev.svg +7 -0
- data/public/favicon/goldrush.ico +0 -0
- data/public/favicon/goldrush.svg +7 -0
- data/public/favicon/goldrush.webmanifest +12 -0
- data/public/favicon/houston-180.png +0 -0
- data/public/favicon/houston-192.png +0 -0
- data/public/favicon/houston-512.png +0 -0
- data/public/favicon/houston-96.png +0 -0
- data/public/favicon/houston-dev.svg +8 -0
- data/public/favicon/houston.ico +0 -0
- data/public/favicon/houston.svg +8 -0
- data/public/favicon/houston.webmanifest +12 -0
- data/public/favicon.ico +0 -0
- data/public/font/bootstrap-icons-6LILWPE2.woff2 +0 -0
- data/public/font/bootstrap-icons-FRBPO3H7.woff2 +0 -0
- data/public/font/ibm-plex-sans-500-latin-LA7QXWWL.woff2 +0 -0
- data/public/font/ibm-plex-sans-500-latin-ext-X4QHZICY.woff2 +0 -0
- data/public/font/ibm-plex-sans-500-latin-ext.woff2 +0 -0
- data/public/font/ibm-plex-sans-500-latin.woff2 +0 -0
- data/public/font/ibm-plex-sans-500-vietnamese-24B6BSND.woff2 +0 -0
- data/public/font/ibm-plex-sans-500-vietnamese.woff2 +0 -0
- data/public/index.html +165 -0
- data/public/js/easyfaa.js +1 -0
- data/public/logo/autopilot.png +0 -0
- data/public/logo/autopilot.svg +9 -0
- data/public/logo/cube.png +0 -0
- data/public/logo/cube.svg +9 -0
- data/public/logo/design.png +0 -0
- data/public/logo/design.svg +8 -0
- data/public/logo/easyfaa.png +0 -0
- data/public/logo/easyfaa.svg +7 -0
- data/public/logo/fountain.png +0 -0
- data/public/logo/fountain.svg +9 -0
- data/public/logo/goldrush.png +0 -0
- data/public/logo/goldrush.svg +7 -0
- data/public/logo/houston.png +0 -0
- data/public/logo/houston.svg +8 -0
- data/public/page/400.html +118 -0
- data/public/page/404.html +118 -0
- data/public/page/406-unsupported-browser.html +118 -0
- data/public/page/422.html +118 -0
- data/public/page/500.html +118 -0
- data/public/site.webmanifest +12 -0
- data/public/theme/bootstrap.css +10 -0
- data/public/theme/dawn.css +189 -0
- data/public/theme/dracula.css +189 -0
- data/public/theme/gruvbox.css +189 -0
- data/public/theme/monokai.css +190 -0
- data/public/theme/nord.css +189 -0
- data/public/theme/one_dark.css +189 -0
- data/public/theme/solarized.css +188 -0
- data/public/theme/tokyo_night.css +189 -0
- data/public/v0.20.0/bh/css/bh.css +1 -0
- data/public/v0.20.0/bh/js/bh.js +152 -0
- data/public/v0.20.0/bh/theme/bootstrap.css +10 -0
- data/public/v0.20.0/bh/theme/dawn.css +189 -0
- data/public/v0.20.0/bh/theme/dracula.css +189 -0
- data/public/v0.20.0/bh/theme/gruvbox.css +189 -0
- data/public/v0.20.0/bh/theme/monokai.css +190 -0
- data/public/v0.20.0/bh/theme/nord.css +189 -0
- data/public/v0.20.0/bh/theme/one_dark.css +189 -0
- data/public/v0.20.0/bh/theme/solarized.css +188 -0
- data/public/v0.20.0/bh/theme/tokyo_night.css +189 -0
- data/public/v0.20.0/css/easyfaa.css +1 -0
- data/public/v0.20.0/font/bootstrap-icons-FRBPO3H7.woff2 +0 -0
- data/public/v0.20.0/font/ibm-plex-sans-500-latin-LA7QXWWL.woff2 +0 -0
- data/public/v0.20.0/font/ibm-plex-sans-500-latin-ext-X4QHZICY.woff2 +0 -0
- data/public/v0.20.0/font/ibm-plex-sans-500-latin-ext.woff2 +0 -0
- data/public/v0.20.0/font/ibm-plex-sans-500-latin.woff2 +0 -0
- data/public/v0.20.0/font/ibm-plex-sans-500-vietnamese-24B6BSND.woff2 +0 -0
- data/public/v0.20.0/font/ibm-plex-sans-500-vietnamese.woff2 +0 -0
- data/public/v0.20.0/js/easyfaa.js +1 -0
- metadata +264 -0
data/README.md
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
# easyfaa design
|
|
2
|
+
|
|
3
|
+
What makes a page look like easyfaa's: the marks every app is known by, the lockup they
|
|
4
|
+
sit in, the wall a signup flow stands on, the palettes, the pages an app shows when it is down
|
|
5
|
+
or lost, and the one stylesheet and one script that carry all of it.
|
|
6
|
+
|
|
7
|
+
The Bootstrap 6 underneath is [`bh`](https://claudiob.github.io/bh/), which this gem depends on
|
|
8
|
+
and draws on top of rather than bundling: a page links bh's stylesheet and script first and this
|
|
9
|
+
one's after, so the house rules win and Bootstrap ships once. **The components are documented
|
|
10
|
+
there, not here** — the form builder, the combobox, the 6-digit code, the phone field, the
|
|
11
|
+
dialog, the toasts, the thread of messages and the twenty-two Stimulus controllers are Bootstrap
|
|
12
|
+
with the markup written once, and are worth the same to any Rails app. This gem is only what is
|
|
13
|
+
the house's.
|
|
14
|
+
|
|
15
|
+
Published three ways from this repo:
|
|
16
|
+
|
|
17
|
+
| Surface | Where | What it is for |
|
|
18
|
+
| --- | --- | --- |
|
|
19
|
+
| Site | https://design.easyfaa.com (staging: https://design.houseparty.dev) | A stable URL for every asset, and a showcase of them |
|
|
20
|
+
| Gem | `easyfaa` on RubyGems | A Rails engine: serves the same tree from the gem, and the helpers |
|
|
21
|
+
| npm | `easyfaa` | The same built stylesheet and script, for any CDN that carries it |
|
|
22
|
+
|
|
23
|
+
## How to install
|
|
24
|
+
|
|
25
|
+
### From RubyGems
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
gem install easyfaa
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
```ruby
|
|
32
|
+
# Gemfile
|
|
33
|
+
gem 'easyfaa', '~> 0.15.0'
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
bh comes with it; nothing else has to be named.
|
|
37
|
+
|
|
38
|
+
`~> 0.15.0` stops short of `0.16`, since below 1.0 a minor release may break whatever it likes.
|
|
39
|
+
Rails 8.1 and Ruby 3.2 are the minimum.
|
|
40
|
+
|
|
41
|
+
A page takes the gem's layout, and wears the same head:
|
|
42
|
+
|
|
43
|
+
```ruby
|
|
44
|
+
class Unauthenticated::AgentsController < ApplicationController
|
|
45
|
+
layout 'easyfaa'
|
|
46
|
+
end
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
```erb
|
|
50
|
+
<% content_for :title, 'Authenticating as admin' %>
|
|
51
|
+
<% content_for :head, tag.meta(name: 'robots', content: 'noindex') %>
|
|
52
|
+
<h1>Authenticating as admin</h1>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
<p>
|
|
56
|
+
<img src='screenshot/layout-light.png' width='49%' alt='The page in light mode'>
|
|
57
|
+
<img src='screenshot/layout-dark.png' width='49%' alt='The page in dark mode'>
|
|
58
|
+
</p>
|
|
59
|
+
|
|
60
|
+
The layout is the charset, the title, the CSRF and CSP metas, `easyfaa_head_tags`,
|
|
61
|
+
`yield :head`, then `yield` inside a `main.container-fluid` in the `<body>`, and `notices`
|
|
62
|
+
after it, and nothing else. A host wanting more copies
|
|
63
|
+
it into its own `app/views/layouts/`, which wins on being earlier in the view paths.
|
|
64
|
+
|
|
65
|
+
Which of the family an app is, the gem reads off the Rails application's own name: the
|
|
66
|
+
`Goldrush` of `Goldrush::Application`. That is what its tab wears, what `easyfaa_head_tags`
|
|
67
|
+
links without an argument, and whose page the engine answers `/down.html` with — the app's
|
|
68
|
+
mark in the middle and the house's at the foot. An app the family has no mark for wears the
|
|
69
|
+
horizon. The same page stands at `https://design.easyfaa.com/down/fountain` for Heroku's
|
|
70
|
+
`MAINTENANCE_PAGE_URL`, which has to be somewhere the app is not — without the `.html`,
|
|
71
|
+
which Pages redirects away from.
|
|
72
|
+
|
|
73
|
+
With the gem in the bundle an app serves `/css/easyfaa.css`, `/js/easyfaa.js`,
|
|
74
|
+
`/theme/*`, `/font/*`, `/logo/*` and `/favicon/*` itself — and its own version's copy under
|
|
75
|
+
`/v0.15.0/`, which is what the head helper links, cached for a year — answers a 400, 404, 406,
|
|
76
|
+
422 or 500 with the house's own page, and answers `/down.html` with this app's.
|
|
77
|
+
|
|
78
|
+
## Which app this is
|
|
79
|
+
|
|
80
|
+
Read off the Rails application's own name, the `Goldrush` of `Goldrush::Application`. That is
|
|
81
|
+
what its tab wears, what `easyfaa_head_tags` links without an argument, and whose page the
|
|
82
|
+
engine answers `/down.html` with — the app's mark in the middle and the house's at the foot. An
|
|
83
|
+
app the family has no mark for wears the horizon.
|
|
84
|
+
|
|
85
|
+
## The helpers
|
|
86
|
+
|
|
87
|
+
```erb
|
|
88
|
+
<%# In the <head>: the viewport, color-scheme and Turbo refresh metas, the stylesheet, the
|
|
89
|
+
script, and the icons a tab, a phone and a manifest ask for — this app's, by its name. %>
|
|
90
|
+
<%= easyfaa_head_tags %>
|
|
91
|
+
|
|
92
|
+
<%# The icons alone, for a head of the host's own: this app's unless another of the family is
|
|
93
|
+
named, the way a page for customers wears the house's horizon rather than the app's. A host of
|
|
94
|
+
recourse needs no call at all — the gem answers recourse's `recourses/head` with them. %>
|
|
95
|
+
<%= easyfaa_icons :easyfaa %>
|
|
96
|
+
|
|
97
|
+
<%# A mark beside its name, as one word and one link. Each drawing fills its 512 grid
|
|
98
|
+
differently, so equal sizes never align: every mark is rendered at a box of its own and
|
|
99
|
+
pushed down by its own nudge, and its ink then stands on the baseline. %>
|
|
100
|
+
<%= easyfaa_logo %>
|
|
101
|
+
<%= easyfaa_logo app: :fountain, href: root_path, class: 'fs-3' %>
|
|
102
|
+
|
|
103
|
+
<%# An asset on the design site, for a page this app does not serve — a mail, say. %>
|
|
104
|
+
<%= image_tag easyfaa_url('logo/fountain.png') %>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## The layout
|
|
108
|
+
|
|
109
|
+
A page takes the gem's layout and wears the same head:
|
|
110
|
+
|
|
111
|
+
```ruby
|
|
112
|
+
class Unauthenticated::AgentsController < ApplicationController
|
|
113
|
+
layout 'easyfaa'
|
|
114
|
+
end
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
```erb
|
|
118
|
+
<% content_for :title, 'Authenticating as admin' %>
|
|
119
|
+
<% content_for :head, tag.meta(name: 'robots', content: 'noindex') %>
|
|
120
|
+
<h1>Authenticating as admin</h1>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
<p>
|
|
124
|
+
<img src='screenshot/layout-light.png' width='49%' alt='The page in light mode'>
|
|
125
|
+
<img src='screenshot/layout-dark.png' width='49%' alt='The page in dark mode'>
|
|
126
|
+
</p>
|
|
127
|
+
|
|
128
|
+
It is the charset, the title, the CSRF and CSP metas, `easyfaa_head_tags`, `yield :head`,
|
|
129
|
+
then `yield` inside a `main.container-fluid`, and `notices` after it — and nothing else. A host
|
|
130
|
+
wanting more copies it into its own `app/views/layouts/`, which wins on being earlier in the
|
|
131
|
+
view paths.
|
|
132
|
+
|
|
133
|
+
## The flow, and the wall it stands on
|
|
134
|
+
|
|
135
|
+
`flow` is the page a signup flow lives on: the lockup over the cyanotype, a title, a line, one
|
|
136
|
+
card, and the way out under it. A layout of the app's own calls it and nests on the gem's:
|
|
137
|
+
|
|
138
|
+
```erb
|
|
139
|
+
<% content_for :logo, 'easyfaa' %>
|
|
140
|
+
|
|
141
|
+
<% content_for :content do %>
|
|
142
|
+
<%= flow href: root_path, links: [button_to('Sign out', session_path, method: :delete, class: 'btn btn-link')] do %>
|
|
143
|
+
<%= yield %>
|
|
144
|
+
<% end %>
|
|
145
|
+
<% end %>
|
|
146
|
+
|
|
147
|
+
<%= render template: 'layouts/easyfaa' %>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
`href:` is where the mark links, the house's front door unless said; `links:` the pieces of the
|
|
151
|
+
foot, joined by a middot, none drawing no foot. The mark and the wall are not asked for, being
|
|
152
|
+
what a house flow is. What the page says about itself — `content_for :title`, `:subtitle` and
|
|
153
|
+
`:width` — it says in its own view, and `content_for :logo` is which of the family's marks the
|
|
154
|
+
tab wears, for a page a customer reads rather than the app's own people.
|
|
155
|
+
|
|
156
|
+
The wall alone is one attribute, `data-controller='wall'`, on any element that should stand on
|
|
157
|
+
it: fourteen trade tools and the family's five marks drifting up in seven columns, on blueprint
|
|
158
|
+
blues of its own so it reads the same whatever the primary is. Under `prefers-reduced-motion`
|
|
159
|
+
the columns stand still.
|
|
160
|
+
|
|
161
|
+
## A code sent to a phone
|
|
162
|
+
|
|
163
|
+
The same words from every app, in each voice they are said in. `written` is the sentence a
|
|
164
|
+
person reads and, under it, the `@host #code` line that offers the code above the keyboard on
|
|
165
|
+
the phone it arrived on; `spoken` is the sentence alone, its digits one at a time so a listener
|
|
166
|
+
can write them down.
|
|
167
|
+
|
|
168
|
+
```ruby
|
|
169
|
+
Easyfaa.one_time_code(contact.pin).written
|
|
170
|
+
# => "Enter this 6-digit code to proceed: 482913\n\n@easyfaa.com #482913"
|
|
171
|
+
Easyfaa.one_time_code(contact.pin).spoken
|
|
172
|
+
# => "Enter this 6-digit code to proceed: 4, 8, 2, 9, 1, 3"
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Off the gem
|
|
176
|
+
|
|
177
|
+
A page not on the gem links the two files from the site, and nothing else:
|
|
178
|
+
|
|
179
|
+
```html
|
|
180
|
+
<link rel='stylesheet' href='https://design.easyfaa.com/css/easyfaa.css'>
|
|
181
|
+
<script type='module' src='https://design.easyfaa.com/js/easyfaa.js'></script>
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Those follow the latest release. Every release is also kept whole under its own version,
|
|
185
|
+
forever and cached for a year, for a page that would rather move on its own terms:
|
|
186
|
+
|
|
187
|
+
```html
|
|
188
|
+
<link rel='stylesheet' href='https://design.easyfaa.com/v0.20.0/css/easyfaa.css'>
|
|
189
|
+
<script type='module' src='https://design.easyfaa.com/v0.20.0/js/easyfaa.js'></script>
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
bh's layer goes under the house's, from the same place, since the house is drawn on top of it
|
|
193
|
+
and neither stands alone:
|
|
194
|
+
|
|
195
|
+
```html
|
|
196
|
+
<link rel='stylesheet' href='https://design.easyfaa.com/v0.20.0/bh/css/bh.css'>
|
|
197
|
+
<link rel='stylesheet' href='https://design.easyfaa.com/v0.20.0/css/easyfaa.css'>
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
The palettes are beside it, at `bh/theme/nord.css` and the rest — bh's nine, copied out of the
|
|
201
|
+
gem at build time. A version under `v` is never written again, so that URL is owed its bytes.
|
|
202
|
+
|
|
203
|
+
A host with a Content Security Policy allows whichever origin it names for `style-src`,
|
|
204
|
+
`script-src` and `font-src`.
|
|
205
|
+
|
|
206
|
+
## What is in the bundle
|
|
207
|
+
|
|
208
|
+
`css/easyfaa.css` is the house's layer alone: the rules this gem writes over bh's,
|
|
209
|
+
followed by Bootstrap Icons cut down to the glyphs `art/icons.txt` names (the ones `unicon`
|
|
210
|
+
maps and the few written out by name) and the house's three — the page, the lockup and the
|
|
211
|
+
wall. IBM Plex Sans, the lockup's face, is served from `/font` too; nothing on a page reaches
|
|
212
|
+
another origin. `js/easyfaa.js` is the house's script alone: `wall`, the one controller
|
|
213
|
+
that is its own, registered with the Stimulus application bh's script starts. bh's two files
|
|
214
|
+
are copied beside these at `bh/`, and a page links bh's first. Everything is drawn for light and dark alike: every color is a Bootstrap
|
|
215
|
+
token or a `light-dark()` pair, and `data-bs-theme` on `<html>` forces either. A phone is
|
|
216
|
+
formatted in the browser: the server hands over ten digits and
|
|
217
|
+
`data-controller='phone'`, and the controller decides `555-555-5555`.
|
|
218
|
+
|
|
219
|
+
## Development
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
bin/setup # bundle and npm install
|
|
223
|
+
bundle exec rake # build, test at 100% coverage, RuboCop, the file-length ceiling
|
|
224
|
+
./build-icons.sh # after editing a drawing under art/
|
|
225
|
+
rake icons # after editing art/icons.txt, the glyphs the icon font keeps
|
|
226
|
+
cd test/dummy && bin/rails server
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
The build reads bh's sources out of the gem — `bundle info bh --path` — rather than out of
|
|
230
|
+
`node_modules`, so the Gemfile is the one place bh's version is pinned. An edit to bh shows in
|
|
231
|
+
this bundle on the next `rake assets`.
|
|
232
|
+
|
|
233
|
+
The built `public/css`, `public/js`, `public/font` and `public/theme` are committed: the gem
|
|
234
|
+
serves them, and `spec.files` is `git ls-files`. `rake assets` rebuilds and fails until the
|
|
235
|
+
result is committed, so a source edit cannot ship without its build.
|
|
236
|
+
|
|
237
|
+
While the gem is read from a path, an app in development serves every file `no-cache`, so a
|
|
238
|
+
rebuild shows on the next reload; only a production app keeps the versioned copy for a year.
|
|
239
|
+
|
|
240
|
+
Every build also writes `public/v<version>/`, whole, with every URL inside pointing under
|
|
241
|
+
that prefix, until the tag `v<version>` exists; from then on the folder is never written
|
|
242
|
+
again, and a page that pinned it is owed the same bytes for good.
|
|
243
|
+
|
|
244
|
+
A release, in order: `CHANGELOG.md`, the version in `lib/easyfaa/version.rb` and
|
|
245
|
+
`package.json`, `bundle exec rake` so the versioned copy is the release's, then commit, tag
|
|
246
|
+
`v<version>`, `gem build` and `gem push`, and fast-forward `production` to `main` so the
|
|
247
|
+
site carries both the latest and the versioned copy.
|
|
248
|
+
|
|
249
|
+
## Cloudflare
|
|
250
|
+
|
|
251
|
+
The site is a Cloudflare Pages project named `design` on this repo: production branch
|
|
252
|
+
`production`, no build command, output directory `public`, custom domain
|
|
253
|
+
`design.easyfaa.com`. `main` deploys as the branch alias `main.design.pages.dev`, which
|
|
254
|
+
`design.houseparty.dev` is a CNAME to. `public/_headers` adds the CORS header a cross-origin
|
|
255
|
+
module script and font need, and marks the hashed fonts immutable; everything else keeps
|
|
256
|
+
Pages' default of revalidating on every load, so a URL never has to change between versions.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang='en'>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset='utf-8'>
|
|
5
|
+
<title><%= content_for(:title) || Easyfaa.app %></title>
|
|
6
|
+
<%- if protect_against_forgery? -%>
|
|
7
|
+
<meta name='csrf-param' content='<%= request_forgery_protection_token %>'>
|
|
8
|
+
<meta name='csrf-token' content='<%= form_authenticity_token %>'>
|
|
9
|
+
<%- end -%>
|
|
10
|
+
<%- if (csp = csp_meta_tag) -%>
|
|
11
|
+
<%= csp %>
|
|
12
|
+
<%- end -%>
|
|
13
|
+
<%= easyfaa_head_tags content_for(:logo).presence || Easyfaa.app %>
|
|
14
|
+
<%- if content_for?(:head) -%>
|
|
15
|
+
<%= yield :head %>
|
|
16
|
+
<%- end -%>
|
|
17
|
+
</head>
|
|
18
|
+
<body class='house-page d-flex flex-column'>
|
|
19
|
+
<main class='container-fluid py-4 flex-grow-1 d-flex flex-column'>
|
|
20
|
+
<%= content_for?(:content) ? yield(:content) : yield %>
|
|
21
|
+
</main>
|
|
22
|
+
<%= toasts %>
|
|
23
|
+
</body>
|
|
24
|
+
</html>
|
data/art/autopilot.svg
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
|
2
|
+
<g fill="none" stroke="#5aa9e6" stroke-width="28" stroke-linecap="round" stroke-linejoin="round">
|
|
3
|
+
<circle cx="256" cy="256" r="190"/>
|
|
4
|
+
<path d="M66 256 L206 256"/>
|
|
5
|
+
<path d="M306 256 L446 256"/>
|
|
6
|
+
<path d="M256 306 L256 446"/>
|
|
7
|
+
<circle cx="256" cy="256" r="50"/>
|
|
8
|
+
</g>
|
|
9
|
+
</svg>
|
data/art/cube.svg
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
|
2
|
+
<g fill="none" stroke="#5aa9e6" stroke-width="28" stroke-linecap="round" stroke-linejoin="round">
|
|
3
|
+
<path d="M256 302Q256 256 295.8 233L406.2 169.3Q446 146.3 446 192.3V319.7Q446 365.7 406.2 388.7L295.8 452.4Q256 475.4 256 429.4Z" fill="#0b1e3a"/>
|
|
4
|
+
<path d="M216.2 59.6Q256 36.6 295.8 59.6L406.2 123.3Q446 146.3 446 192.3V319.7Q446 365.7 406.2 388.7L295.8 452.4Q256 475.4 216.2 452.4L105.8 388.7Q66 365.7 66 319.7V192.3Q66 146.3 105.8 123.3Z"/>
|
|
5
|
+
<path d="M256 256 95.4 163.3"/>
|
|
6
|
+
<path d="M256 256 416.6 163.3"/>
|
|
7
|
+
<path d="M256 256V441.4"/>
|
|
8
|
+
</g>
|
|
9
|
+
</svg>
|
data/art/design.svg
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
|
2
|
+
<g fill="none" stroke="#5aa9e6" stroke-width="28" stroke-linecap="round" stroke-linejoin="round" transform="rotate(45 256 256)">
|
|
3
|
+
<path d="M196 60 L316 60 L316 372 L196 372 Z"/>
|
|
4
|
+
<path d="M196 120 L316 120"/>
|
|
5
|
+
<path d="M196 372 L256 470 L316 372"/>
|
|
6
|
+
<path d="M232 431 L256 470 L280 431 Z" fill="#0b1e3a"/>
|
|
7
|
+
</g>
|
|
8
|
+
</svg>
|
data/art/down.html.erb
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
<%# The page an app shows while it is down: its own mark and name in the middle, the house's
|
|
2
|
+
at the foot — or the house's alone, for an app not in the family — and nothing that
|
|
3
|
+
needs the app to be up — IBM Plex Sans and the icons from the design site, the two
|
|
4
|
+
blues written in. Rendered per app by `rake pages` into
|
|
5
|
+
public/down/<app>.html, and answered at /down.html by the engine once the host has named
|
|
6
|
+
itself in `Easyfaa.app`. -%>
|
|
7
|
+
<!doctype html>
|
|
8
|
+
<html lang='en'>
|
|
9
|
+
<head>
|
|
10
|
+
<meta charset='utf-8'>
|
|
11
|
+
<meta name='viewport' content='width=device-width, initial-scale=1'>
|
|
12
|
+
<title><%= app %></title>
|
|
13
|
+
<meta name='color-scheme' content='light dark'>
|
|
14
|
+
<link rel='icon' href='https://design.easyfaa.com/favicon/<%= app %>.svg' type='image/svg+xml'>
|
|
15
|
+
<link rel='icon' href='https://design.easyfaa.com/favicon/<%= app %>-96.png' type='image/png' sizes='96x96'>
|
|
16
|
+
<link rel='apple-touch-icon' href='https://design.easyfaa.com/favicon/<%= app %>-180.png'>
|
|
17
|
+
<style>
|
|
18
|
+
@font-face {
|
|
19
|
+
font-family: 'IBM Plex Sans'; font-style: normal; font-weight: 500; font-display: swap;
|
|
20
|
+
src: url('https://design.easyfaa.com/font/ibm-plex-sans-500-vietnamese.woff2') format('woff2');
|
|
21
|
+
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
|
22
|
+
}
|
|
23
|
+
@font-face {
|
|
24
|
+
font-family: 'IBM Plex Sans'; font-style: normal; font-weight: 500; font-display: swap;
|
|
25
|
+
src: url('https://design.easyfaa.com/font/ibm-plex-sans-500-latin-ext.woff2') format('woff2');
|
|
26
|
+
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
|
27
|
+
}
|
|
28
|
+
@font-face {
|
|
29
|
+
font-family: 'IBM Plex Sans'; font-style: normal; font-weight: 500; font-display: swap;
|
|
30
|
+
src: url('https://design.easyfaa.com/font/ibm-plex-sans-500-latin.woff2') format('woff2');
|
|
31
|
+
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
|
32
|
+
}
|
|
33
|
+
:root {
|
|
34
|
+
--bg: #fbfcfe;
|
|
35
|
+
--ink: #0b1e3a;
|
|
36
|
+
--mark: #5aa9e6;
|
|
37
|
+
}
|
|
38
|
+
@media (prefers-color-scheme: dark) {
|
|
39
|
+
:root {
|
|
40
|
+
--bg: #0f1622;
|
|
41
|
+
--ink: #cfe3f6;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
* { box-sizing: border-box; }
|
|
45
|
+
body {
|
|
46
|
+
margin: 0;
|
|
47
|
+
min-height: 100svh;
|
|
48
|
+
display: flex;
|
|
49
|
+
flex-direction: column;
|
|
50
|
+
background: var(--bg);
|
|
51
|
+
font-family: 'IBM Plex Sans', 'Helvetica Neue', Arial, sans-serif;
|
|
52
|
+
font-weight: 500;
|
|
53
|
+
letter-spacing: 0.01em;
|
|
54
|
+
}
|
|
55
|
+
main {
|
|
56
|
+
flex: 1;
|
|
57
|
+
display: grid;
|
|
58
|
+
place-items: center;
|
|
59
|
+
}
|
|
60
|
+
.lockup {
|
|
61
|
+
white-space: nowrap;
|
|
62
|
+
color: var(--ink);
|
|
63
|
+
line-height: 1;
|
|
64
|
+
}
|
|
65
|
+
/* The mark on the text baseline, sized and nudged by its own numbers, in ems so the
|
|
66
|
+
same pair reads right at both sizes on this page. */
|
|
67
|
+
.lockup svg {
|
|
68
|
+
position: relative;
|
|
69
|
+
vertical-align: baseline;
|
|
70
|
+
margin-right: 0.29em;
|
|
71
|
+
}
|
|
72
|
+
main .lockup { font-size: 48px; }
|
|
73
|
+
footer {
|
|
74
|
+
position: sticky;
|
|
75
|
+
bottom: 0;
|
|
76
|
+
background: var(--bg);
|
|
77
|
+
display: flex;
|
|
78
|
+
justify-content: center;
|
|
79
|
+
padding: 20px 0 26px;
|
|
80
|
+
}
|
|
81
|
+
footer .lockup { font-size: 20px; }
|
|
82
|
+
footer .easy { color: var(--mark); }
|
|
83
|
+
</style>
|
|
84
|
+
</head>
|
|
85
|
+
<body>
|
|
86
|
+
<main>
|
|
87
|
+
<p class='lockup'><%= mark[app] %><%= app == :easyfaa ? "<span class='easy'>easy</span>faa" : app %></p>
|
|
88
|
+
</main>
|
|
89
|
+
<%- unless app == :easyfaa -%>
|
|
90
|
+
<footer>
|
|
91
|
+
<p class='lockup'><%= mark[:easyfaa] %><span class='easy'>easy</span>faa</p>
|
|
92
|
+
</footer>
|
|
93
|
+
<%- end -%>
|
|
94
|
+
</body>
|
|
95
|
+
</html>
|
data/art/easyfaa.svg
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
|
2
|
+
<g fill="none" stroke="#5aa9e6" stroke-width="28" stroke-linecap="round" stroke-linejoin="round">
|
|
3
|
+
<path d="M74.5 340H437.5A200 200 0 0 1 74.5 340Z" fill="#0b1e3a" stroke="none"/>
|
|
4
|
+
<circle cx="256" cy="256" r="200"/>
|
|
5
|
+
<path d="M150 256H216L256 296L296 256H362"/>
|
|
6
|
+
</g>
|
|
7
|
+
</svg>
|
data/art/fountain.svg
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
|
2
|
+
<g fill="none" stroke="#5aa9e6" stroke-width="28" stroke-linecap="round">
|
|
3
|
+
<path d="M256 472V40"/>
|
|
4
|
+
<path d="M256 472C234 310 180 202 121 143"/>
|
|
5
|
+
<path d="M256 472C278 310 332 202 391 143"/>
|
|
6
|
+
<path d="M256 472C216 348 124 283 51 251"/>
|
|
7
|
+
<path d="M256 472C296 348 388 283 461 251"/>
|
|
8
|
+
</g>
|
|
9
|
+
</svg>
|
data/art/goldrush.svg
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
|
2
|
+
<g fill="none" stroke="#5aa9e6" stroke-width="28" stroke-linecap="round" stroke-linejoin="round">
|
|
3
|
+
<path d="M152 248 L190 128 L322 128 L360 248 Z"/>
|
|
4
|
+
<path d="M40 384 L78 264 L210 264 L248 384 Z"/>
|
|
5
|
+
<path d="M264 384 L302 264 L434 264 L472 384 Z"/>
|
|
6
|
+
</g>
|
|
7
|
+
</svg>
|
data/art/houston.svg
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
|
2
|
+
<g fill="none" stroke="#5aa9e6" stroke-width="28" stroke-linecap="round">
|
|
3
|
+
<circle cx="256" cy="256" r="224"/>
|
|
4
|
+
<path d="M32 256h448"/>
|
|
5
|
+
<path d="M256 32c142 63 142 385 0 448"/>
|
|
6
|
+
<path d="M256 32c-142 63-142 385 0 448"/>
|
|
7
|
+
</g>
|
|
8
|
+
</svg>
|
data/art/icons.txt
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# Every Bootstrap Icon a easyfaa page may draw: the ones unicon names for its concepts,
|
|
2
|
+
# and the few written out by name in recourse and here. The icon font and its stylesheet
|
|
3
|
+
# are cut down to these by rake icons; a name missing here is a blank box on a page.
|
|
4
|
+
airplane
|
|
5
|
+
alarm
|
|
6
|
+
archive
|
|
7
|
+
arrow-clockwise
|
|
8
|
+
arrow-counterclockwise
|
|
9
|
+
arrow-down
|
|
10
|
+
arrow-left
|
|
11
|
+
arrow-right
|
|
12
|
+
arrow-up
|
|
13
|
+
arrows-angle-contract
|
|
14
|
+
arrows-angle-expand
|
|
15
|
+
award
|
|
16
|
+
bag
|
|
17
|
+
bank
|
|
18
|
+
bar-chart
|
|
19
|
+
battery
|
|
20
|
+
bell
|
|
21
|
+
bicycle
|
|
22
|
+
book
|
|
23
|
+
bookmark
|
|
24
|
+
bookmark-fill
|
|
25
|
+
box
|
|
26
|
+
box-arrow-in-right
|
|
27
|
+
box-arrow-right
|
|
28
|
+
briefcase
|
|
29
|
+
brush
|
|
30
|
+
building
|
|
31
|
+
bus-front
|
|
32
|
+
c-circle
|
|
33
|
+
calendar
|
|
34
|
+
calendar-check
|
|
35
|
+
camera
|
|
36
|
+
camera-video
|
|
37
|
+
car-front
|
|
38
|
+
card-checklist
|
|
39
|
+
cart
|
|
40
|
+
cash
|
|
41
|
+
chat
|
|
42
|
+
check
|
|
43
|
+
check-circle
|
|
44
|
+
check-circle-fill
|
|
45
|
+
check2-square
|
|
46
|
+
chevron-down
|
|
47
|
+
chevron-left
|
|
48
|
+
chevron-right
|
|
49
|
+
chevron-up
|
|
50
|
+
circle
|
|
51
|
+
clipboard
|
|
52
|
+
clock
|
|
53
|
+
cloud
|
|
54
|
+
cloud-rain
|
|
55
|
+
collection-play
|
|
56
|
+
compass
|
|
57
|
+
copy
|
|
58
|
+
credit-card
|
|
59
|
+
dash
|
|
60
|
+
display
|
|
61
|
+
download
|
|
62
|
+
droplet
|
|
63
|
+
emoji-smile
|
|
64
|
+
envelope
|
|
65
|
+
exclamation-triangle
|
|
66
|
+
eye
|
|
67
|
+
eye-slash
|
|
68
|
+
file-earmark
|
|
69
|
+
file-earmark-text
|
|
70
|
+
fingerprint
|
|
71
|
+
fire
|
|
72
|
+
flag
|
|
73
|
+
folder
|
|
74
|
+
funnel
|
|
75
|
+
gear
|
|
76
|
+
geo
|
|
77
|
+
geo-alt
|
|
78
|
+
gift
|
|
79
|
+
globe
|
|
80
|
+
graph-up
|
|
81
|
+
grid
|
|
82
|
+
grip-vertical
|
|
83
|
+
hammer
|
|
84
|
+
hand-thumbs-down
|
|
85
|
+
hand-thumbs-up
|
|
86
|
+
hdd-rack
|
|
87
|
+
headphones
|
|
88
|
+
heart
|
|
89
|
+
hospital
|
|
90
|
+
hourglass
|
|
91
|
+
house
|
|
92
|
+
image
|
|
93
|
+
inbox
|
|
94
|
+
infinity
|
|
95
|
+
info-circle
|
|
96
|
+
key
|
|
97
|
+
keyboard
|
|
98
|
+
laptop
|
|
99
|
+
layout-sidebar
|
|
100
|
+
lightbulb
|
|
101
|
+
lightning
|
|
102
|
+
link
|
|
103
|
+
list
|
|
104
|
+
list-ul
|
|
105
|
+
lock
|
|
106
|
+
magic
|
|
107
|
+
map
|
|
108
|
+
megaphone
|
|
109
|
+
mic
|
|
110
|
+
moon
|
|
111
|
+
moon-fill
|
|
112
|
+
music-note
|
|
113
|
+
palette
|
|
114
|
+
paperclip
|
|
115
|
+
pause
|
|
116
|
+
pen
|
|
117
|
+
pencil
|
|
118
|
+
people
|
|
119
|
+
percent
|
|
120
|
+
person
|
|
121
|
+
person-circle
|
|
122
|
+
person-dash
|
|
123
|
+
person-plus
|
|
124
|
+
person-rolodex
|
|
125
|
+
person-vcard
|
|
126
|
+
phone
|
|
127
|
+
pie-chart
|
|
128
|
+
play
|
|
129
|
+
plus
|
|
130
|
+
power
|
|
131
|
+
printer
|
|
132
|
+
puzzle
|
|
133
|
+
qr-code
|
|
134
|
+
question-circle
|
|
135
|
+
receipt
|
|
136
|
+
repeat
|
|
137
|
+
reply
|
|
138
|
+
rulers
|
|
139
|
+
scissors
|
|
140
|
+
search
|
|
141
|
+
send
|
|
142
|
+
share
|
|
143
|
+
shield
|
|
144
|
+
shop
|
|
145
|
+
shuffle
|
|
146
|
+
signpost-split
|
|
147
|
+
skip-forward
|
|
148
|
+
sliders
|
|
149
|
+
snow
|
|
150
|
+
sort-down
|
|
151
|
+
sort-up
|
|
152
|
+
soundwave
|
|
153
|
+
speedometer
|
|
154
|
+
square
|
|
155
|
+
star
|
|
156
|
+
sticky
|
|
157
|
+
stop
|
|
158
|
+
stopwatch
|
|
159
|
+
sun
|
|
160
|
+
sun-fill
|
|
161
|
+
table
|
|
162
|
+
tag
|
|
163
|
+
telephone
|
|
164
|
+
terminal
|
|
165
|
+
three-dots
|
|
166
|
+
ticket
|
|
167
|
+
tools
|
|
168
|
+
train-front
|
|
169
|
+
trash
|
|
170
|
+
tree
|
|
171
|
+
trophy
|
|
172
|
+
truck
|
|
173
|
+
unlock
|
|
174
|
+
upc
|
|
175
|
+
upload
|
|
176
|
+
volume-up
|
|
177
|
+
wallet
|
|
178
|
+
wifi
|
|
179
|
+
window
|
|
180
|
+
wrench
|
|
181
|
+
x
|
|
182
|
+
x-circle
|
|
183
|
+
x-lg
|
|
184
|
+
zoom-in
|
|
185
|
+
zoom-out
|