active_admin_prism 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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +133 -0
- data/INTEGRATION.md +1012 -0
- data/LICENSE.txt +21 -0
- data/README.md +319 -0
- data/app/assets/javascripts/active_admin_prism/prism.js +1 -0
- data/app/assets/stylesheets/active_admin_prism/_variable_overrides.scss +43 -0
- data/app/assets/stylesheets/active_admin_prism/prism.css +1 -0
- data/app/views/active_admin/devise/confirmations/new.html.erb +26 -0
- data/app/views/active_admin/devise/passwords/edit.html.erb +29 -0
- data/app/views/active_admin/devise/passwords/new.html.erb +26 -0
- data/app/views/active_admin/devise/registrations/new.html.erb +32 -0
- data/app/views/active_admin/devise/sessions/new.html.erb +37 -0
- data/app/views/active_admin/devise/shared/_brand.html.erb +34 -0
- data/app/views/active_admin/devise/unlocks/new.html.erb +25 -0
- data/js-src/prism.js +270 -0
- data/lib/active_admin/views/filters_sidebar.rb +69 -0
- data/lib/active_admin/views/flash_messages.rb +77 -0
- data/lib/active_admin/views/index_table_actions.rb +46 -0
- data/lib/active_admin/views/prism_sidebar.rb +212 -0
- data/lib/active_admin_prism/configuration.rb +180 -0
- data/lib/active_admin_prism/engine.rb +18 -0
- data/lib/active_admin_prism/version.rb +5 -0
- data/lib/active_admin_prism.rb +33 -0
- data/lib/formtastic/inputs/prism_toggle_input.rb +31 -0
- data/lib/generators/active_admin_prism/error_pages/error_pages_generator.rb +49 -0
- data/lib/generators/active_admin_prism/error_pages/templates/404.html +164 -0
- data/lib/generators/active_admin_prism/error_pages/templates/500.html +173 -0
- data/lib/generators/active_admin_prism/install/install_generator.rb +69 -0
- data/lib/prism_icons.rb +82 -0
- data/lib/prism_login_helper.rb +31 -0
- data/lib/prism_toggle_tag.rb +35 -0
- data/scss-src/_base.scss +281 -0
- data/scss-src/_buttons.scss +134 -0
- data/scss-src/_forms.scss +272 -0
- data/scss-src/_icons.scss +27 -0
- data/scss-src/_login.scss +306 -0
- data/scss-src/_panels.scss +249 -0
- data/scss-src/_sidebar.scss +479 -0
- data/scss-src/_tables.scss +142 -0
- data/scss-src/_variables.scss +101 -0
- data/scss-src/prism.scss +15 -0
- metadata +157 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Prism — Page Not Found</title>
|
|
7
|
+
<style>
|
|
8
|
+
/*
|
|
9
|
+
Static public/ error page — Rails serves this straight off disk
|
|
10
|
+
(ActionDispatch::PublicExceptions), completely outside the asset
|
|
11
|
+
pipeline and any Rails view/layout, so it can't @import prism.css,
|
|
12
|
+
use ERB, or rely on any Ruby config. Colors below are copied from
|
|
13
|
+
this gem's scss-src/_variables.scss defaults (as of the version this
|
|
14
|
+
was generated from) rather than referencing them, and won't track a
|
|
15
|
+
host's own color customizations automatically — re-run the generator
|
|
16
|
+
(or hand-edit this file) after changing your palette if that matters
|
|
17
|
+
to you. No external requests (fonts, CDNs) on purpose — this page
|
|
18
|
+
needs to render even if the rest of the app/network is unhealthy.
|
|
19
|
+
*/
|
|
20
|
+
:root{
|
|
21
|
+
--primary:#6d5bd0;
|
|
22
|
+
--primary-dark:#5949b8;
|
|
23
|
+
--primary-light:#f2ecfd;
|
|
24
|
+
--bg:#f4f5f7;
|
|
25
|
+
--card:#ffffff;
|
|
26
|
+
--border:#e6e8ec;
|
|
27
|
+
--text:#1a1f36;
|
|
28
|
+
--muted:#6b7280;
|
|
29
|
+
--radius:10px;
|
|
30
|
+
}
|
|
31
|
+
*{box-sizing:border-box;}
|
|
32
|
+
html,body{height:100%;}
|
|
33
|
+
body{
|
|
34
|
+
margin:0;
|
|
35
|
+
font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
|
|
36
|
+
background:var(--bg);
|
|
37
|
+
color:var(--text);
|
|
38
|
+
display:flex;
|
|
39
|
+
align-items:center;
|
|
40
|
+
justify-content:center;
|
|
41
|
+
min-height:100vh;
|
|
42
|
+
overflow:hidden;
|
|
43
|
+
position:relative;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.bg-blobs{position:fixed;inset:0;z-index:0;overflow:hidden;}
|
|
47
|
+
.blob{position:absolute;border-radius:50%;filter:blur(70px);opacity:.35;will-change:transform;}
|
|
48
|
+
.blob-1{width:480px;height:480px;background:radial-gradient(circle at 30% 30%, var(--primary), transparent 70%);top:-160px;left:-140px;animation:float1 16s ease-in-out infinite;}
|
|
49
|
+
.blob-2{width:420px;height:420px;background:radial-gradient(circle at 70% 70%, #a78bfa, transparent 70%);bottom:-140px;right:-120px;animation:float2 18s ease-in-out infinite;}
|
|
50
|
+
.blob-3{width:300px;height:300px;background:radial-gradient(circle, #ff6b9a, transparent 70%);top:40%;right:10%;opacity:.18;animation:float3 14s ease-in-out infinite;}
|
|
51
|
+
@keyframes float1{0%,100%{transform:translate(0,0) scale(1);}50%{transform:translate(60px,40px) scale(1.1);}}
|
|
52
|
+
@keyframes float2{0%,100%{transform:translate(0,0) scale(1);}50%{transform:translate(-50px,-30px) scale(1.08);}}
|
|
53
|
+
@keyframes float3{0%,100%{transform:translate(0,0);}50%{transform:translate(-40px,30px);}}
|
|
54
|
+
|
|
55
|
+
.wrapper{position:relative;z-index:1;display:flex;flex-direction:column;align-items:center;animation:cardIn .7s cubic-bezier(.2,.8,.2,1) both;}
|
|
56
|
+
@keyframes cardIn{from{opacity:0;transform:translateY(18px) scale(.98);}to{opacity:1;transform:translateY(0) scale(1);}}
|
|
57
|
+
|
|
58
|
+
.card{
|
|
59
|
+
width:460px;
|
|
60
|
+
max-width:90vw;
|
|
61
|
+
background:var(--card);
|
|
62
|
+
border:1px solid var(--border);
|
|
63
|
+
border-radius:var(--radius);
|
|
64
|
+
box-shadow:0 20px 50px -20px rgba(76,63,180,.25), 0 2px 8px rgba(20,20,40,.04);
|
|
65
|
+
padding:44px 40px 36px;
|
|
66
|
+
text-align:center;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.prism-mark{width:88px;height:88px;margin:0 auto 8px;position:relative;}
|
|
70
|
+
.prism-mark svg{width:100%;height:100%;overflow:visible;}
|
|
71
|
+
.prism-tri{animation:drift 5s ease-in-out infinite;transform-origin:center;}
|
|
72
|
+
@keyframes drift{0%,100%{transform:translateY(0) rotate(0deg);}50%{transform:translateY(-4px) rotate(-2deg);}}
|
|
73
|
+
.beam{stroke-dasharray:40;animation:beamFlow 2.4s linear infinite;}
|
|
74
|
+
@keyframes beamFlow{to{stroke-dashoffset:-80;}}
|
|
75
|
+
.beam-dash{opacity:.55;animation:fadePulse 1.8s ease-in-out infinite;}
|
|
76
|
+
@keyframes fadePulse{0%,100%{opacity:.25;}50%{opacity:.7;}}
|
|
77
|
+
.qmark{animation:bob 2.4s ease-in-out infinite;transform-origin:center;}
|
|
78
|
+
@keyframes bob{0%,100%{transform:translateY(0);}50%{transform:translateY(-6px);}}
|
|
79
|
+
|
|
80
|
+
.error-code{
|
|
81
|
+
font-size:76px;
|
|
82
|
+
font-weight:800;
|
|
83
|
+
letter-spacing:-.03em;
|
|
84
|
+
line-height:1;
|
|
85
|
+
margin:6px 0 6px;
|
|
86
|
+
background:linear-gradient(135deg,var(--primary), #a78bfa, var(--primary));
|
|
87
|
+
background-size:200% 200%;
|
|
88
|
+
-webkit-background-clip:text;
|
|
89
|
+
background-clip:text;
|
|
90
|
+
color:transparent;
|
|
91
|
+
animation:gradientShift 6s ease infinite;
|
|
92
|
+
}
|
|
93
|
+
@keyframes gradientShift{0%,100%{background-position:0% 50%;}50%{background-position:100% 50%;}}
|
|
94
|
+
|
|
95
|
+
h1{margin:0 0 8px;font-size:19px;font-weight:700;}
|
|
96
|
+
p.desc{margin:0 0 28px;color:var(--muted);font-size:13.5px;line-height:1.6;}
|
|
97
|
+
|
|
98
|
+
.actions{display:flex;gap:10px;justify-content:center;flex-wrap:wrap;}
|
|
99
|
+
.btn-primary,.btn-secondary{
|
|
100
|
+
padding:11px 20px;
|
|
101
|
+
border-radius:10px;
|
|
102
|
+
font-size:14px;
|
|
103
|
+
font-weight:700;
|
|
104
|
+
font-family:inherit;
|
|
105
|
+
cursor:pointer;
|
|
106
|
+
text-decoration:none;
|
|
107
|
+
display:inline-block;
|
|
108
|
+
transition:background .18s ease, transform .12s ease, box-shadow .18s ease, border-color .18s ease;
|
|
109
|
+
}
|
|
110
|
+
.btn-primary{
|
|
111
|
+
background:var(--primary);
|
|
112
|
+
color:#fff;
|
|
113
|
+
border:none;
|
|
114
|
+
box-shadow:0 8px 20px -8px rgba(109,91,208,.6);
|
|
115
|
+
}
|
|
116
|
+
.btn-primary:hover{background:var(--primary-dark);}
|
|
117
|
+
.btn-primary:active{transform:scale(.98);}
|
|
118
|
+
.btn-secondary{
|
|
119
|
+
background:#fff;
|
|
120
|
+
color:var(--text);
|
|
121
|
+
border:1.5px solid var(--border);
|
|
122
|
+
}
|
|
123
|
+
.btn-secondary:hover{border-color:var(--primary);background:var(--primary-light);}
|
|
124
|
+
|
|
125
|
+
.footer-note{margin-top:20px;font-size:12px;color:var(--muted);text-align:center;}
|
|
126
|
+
</style>
|
|
127
|
+
</head>
|
|
128
|
+
<body>
|
|
129
|
+
|
|
130
|
+
<div class="bg-blobs">
|
|
131
|
+
<div class="blob blob-1"></div>
|
|
132
|
+
<div class="blob blob-2"></div>
|
|
133
|
+
<div class="blob blob-3"></div>
|
|
134
|
+
</div>
|
|
135
|
+
|
|
136
|
+
<div class="wrapper">
|
|
137
|
+
<div class="card">
|
|
138
|
+
<div class="prism-mark">
|
|
139
|
+
<svg viewBox="0 0 100 100">
|
|
140
|
+
<text class="qmark" x="66" y="18" font-size="18" font-weight="800" fill="#a78bfa">?</text>
|
|
141
|
+
<polygon class="prism-tri" points="24,72 50,20 76,72" fill="rgba(109,91,208,.10)" stroke="#6d5bd0" stroke-width="3"/>
|
|
142
|
+
<line class="beam-dash" x1="2" y1="55" x2="34" y2="55" stroke="#6d5bd0" stroke-width="4" stroke-linecap="round" stroke-dasharray="6 6"/>
|
|
143
|
+
<line class="beam" x1="62" y1="46" x2="92" y2="18" stroke="#e53935" stroke-width="3" stroke-linecap="round"/>
|
|
144
|
+
<line class="beam" x1="62" y1="53" x2="94" y2="53" stroke="#fdd835" stroke-width="3" stroke-linecap="round" style="animation-delay:.15s"/>
|
|
145
|
+
<line class="beam" x1="62" y1="60" x2="90" y2="90" stroke="#1e88e5" stroke-width="3" stroke-linecap="round" style="animation-delay:.3s"/>
|
|
146
|
+
</svg>
|
|
147
|
+
</div>
|
|
148
|
+
|
|
149
|
+
<div class="error-code">404</div>
|
|
150
|
+
<h1>Page not found</h1>
|
|
151
|
+
<p class="desc">The page you're looking for got refracted somewhere along the way. It may have been moved, renamed, or never existed.</p>
|
|
152
|
+
|
|
153
|
+
<div class="actions">
|
|
154
|
+
<!-- Static file, no Rails route helpers available — point this at your own admin root. -->
|
|
155
|
+
<a href="/" class="btn-primary">Back to Dashboard</a>
|
|
156
|
+
<!-- Placeholder — point this at your own support inbox/issue tracker, or remove it. -->
|
|
157
|
+
<a href="mailto:support@example.com" class="btn-secondary">Report Issue</a>
|
|
158
|
+
</div>
|
|
159
|
+
</div>
|
|
160
|
+
<p class="footer-note">Prism theme for ActiveAdmin</p>
|
|
161
|
+
</div>
|
|
162
|
+
|
|
163
|
+
</body>
|
|
164
|
+
</html>
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Prism — Server Error</title>
|
|
7
|
+
<style>
|
|
8
|
+
/* See 404.html's template for why this is plain, self-contained,
|
|
9
|
+
hand-copied CSS rather than anything referencing prism.css/Ruby. */
|
|
10
|
+
:root{
|
|
11
|
+
--primary:#6d5bd0;
|
|
12
|
+
--primary-dark:#5949b8;
|
|
13
|
+
--primary-light:#f2ecfd;
|
|
14
|
+
--bg:#f4f5f7;
|
|
15
|
+
--card:#ffffff;
|
|
16
|
+
--border:#e6e8ec;
|
|
17
|
+
--text:#1a1f36;
|
|
18
|
+
--muted:#6b7280;
|
|
19
|
+
--danger:#ef4444;
|
|
20
|
+
--warn:#f59e0b;
|
|
21
|
+
--radius:10px;
|
|
22
|
+
}
|
|
23
|
+
*{box-sizing:border-box;}
|
|
24
|
+
html,body{height:100%;}
|
|
25
|
+
body{
|
|
26
|
+
margin:0;
|
|
27
|
+
font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
|
|
28
|
+
background:var(--bg);
|
|
29
|
+
color:var(--text);
|
|
30
|
+
display:flex;
|
|
31
|
+
align-items:center;
|
|
32
|
+
justify-content:center;
|
|
33
|
+
min-height:100vh;
|
|
34
|
+
overflow:hidden;
|
|
35
|
+
position:relative;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.bg-blobs{position:fixed;inset:0;z-index:0;overflow:hidden;}
|
|
39
|
+
.blob{position:absolute;border-radius:50%;filter:blur(70px);opacity:.35;will-change:transform;}
|
|
40
|
+
.blob-1{width:480px;height:480px;background:radial-gradient(circle at 30% 30%, var(--warn), transparent 70%);top:-160px;left:-140px;opacity:.2;animation:float1 16s ease-in-out infinite;}
|
|
41
|
+
.blob-2{width:420px;height:420px;background:radial-gradient(circle at 70% 70%, #a78bfa, transparent 70%);bottom:-140px;right:-120px;animation:float2 18s ease-in-out infinite;}
|
|
42
|
+
.blob-3{width:300px;height:300px;background:radial-gradient(circle, var(--danger), transparent 70%);top:40%;right:10%;opacity:.16;animation:float3 14s ease-in-out infinite;}
|
|
43
|
+
@keyframes float1{0%,100%{transform:translate(0,0) scale(1);}50%{transform:translate(60px,40px) scale(1.1);}}
|
|
44
|
+
@keyframes float2{0%,100%{transform:translate(0,0) scale(1);}50%{transform:translate(-50px,-30px) scale(1.08);}}
|
|
45
|
+
@keyframes float3{0%,100%{transform:translate(0,0);}50%{transform:translate(-40px,30px);}}
|
|
46
|
+
|
|
47
|
+
.wrapper{position:relative;z-index:1;display:flex;flex-direction:column;align-items:center;animation:cardIn .7s cubic-bezier(.2,.8,.2,1) both;}
|
|
48
|
+
@keyframes cardIn{from{opacity:0;transform:translateY(18px) scale(.98);}to{opacity:1;transform:translateY(0) scale(1);}}
|
|
49
|
+
|
|
50
|
+
.card{
|
|
51
|
+
width:460px;
|
|
52
|
+
max-width:90vw;
|
|
53
|
+
background:var(--card);
|
|
54
|
+
border:1px solid var(--border);
|
|
55
|
+
border-radius:var(--radius);
|
|
56
|
+
box-shadow:0 20px 50px -20px rgba(76,63,180,.25), 0 2px 8px rgba(20,20,40,.04);
|
|
57
|
+
padding:44px 40px 36px;
|
|
58
|
+
text-align:center;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.prism-mark{width:88px;height:88px;margin:0 auto 8px;position:relative;animation:shake 4.5s ease-in-out infinite;}
|
|
62
|
+
.prism-mark svg{width:100%;height:100%;overflow:visible;}
|
|
63
|
+
@keyframes shake{
|
|
64
|
+
0%,92%,100%{transform:translate(0,0) rotate(0deg);}
|
|
65
|
+
93%{transform:translate(-2px,0) rotate(-1deg);}
|
|
66
|
+
94%{transform:translate(2px,0) rotate(1deg);}
|
|
67
|
+
95%{transform:translate(-2px,0) rotate(-1deg);}
|
|
68
|
+
96%{transform:translate(2px,0) rotate(1deg);}
|
|
69
|
+
97%{transform:translate(0,0) rotate(0deg);}
|
|
70
|
+
}
|
|
71
|
+
.prism-tri{
|
|
72
|
+
animation:flicker 2.6s ease-in-out infinite;
|
|
73
|
+
transform-origin:center;
|
|
74
|
+
}
|
|
75
|
+
@keyframes flicker{
|
|
76
|
+
0%,100%{filter:drop-shadow(0 0 0px rgba(239,68,68,0));}
|
|
77
|
+
45%{filter:drop-shadow(0 0 0px rgba(239,68,68,0));}
|
|
78
|
+
50%{filter:drop-shadow(0 0 8px rgba(239,68,68,.6));}
|
|
79
|
+
55%{filter:drop-shadow(0 0 0px rgba(239,68,68,0));}
|
|
80
|
+
}
|
|
81
|
+
.beam{stroke-dasharray:40;animation:beamFlow 2.4s linear infinite;}
|
|
82
|
+
@keyframes beamFlow{to{stroke-dashoffset:-80;}}
|
|
83
|
+
.warn-badge{animation:pop 2.6s ease-in-out infinite;transform-origin:center;}
|
|
84
|
+
@keyframes pop{0%,40%,100%{transform:scale(1);}50%{transform:scale(1.18);}}
|
|
85
|
+
|
|
86
|
+
.error-code{
|
|
87
|
+
font-size:76px;
|
|
88
|
+
font-weight:800;
|
|
89
|
+
letter-spacing:-.03em;
|
|
90
|
+
line-height:1;
|
|
91
|
+
margin:6px 0 6px;
|
|
92
|
+
background:linear-gradient(135deg,var(--warn), var(--danger), var(--primary));
|
|
93
|
+
background-size:200% 200%;
|
|
94
|
+
-webkit-background-clip:text;
|
|
95
|
+
background-clip:text;
|
|
96
|
+
color:transparent;
|
|
97
|
+
animation:gradientShift 5s ease infinite;
|
|
98
|
+
}
|
|
99
|
+
@keyframes gradientShift{0%,100%{background-position:0% 50%;}50%{background-position:100% 50%;}}
|
|
100
|
+
|
|
101
|
+
h1{margin:0 0 8px;font-size:19px;font-weight:700;}
|
|
102
|
+
p.desc{margin:0 0 28px;color:var(--muted);font-size:13.5px;line-height:1.6;}
|
|
103
|
+
|
|
104
|
+
.actions{display:flex;gap:10px;justify-content:center;flex-wrap:wrap;}
|
|
105
|
+
.btn-primary,.btn-secondary{
|
|
106
|
+
padding:11px 20px;
|
|
107
|
+
border-radius:10px;
|
|
108
|
+
font-size:14px;
|
|
109
|
+
font-weight:700;
|
|
110
|
+
font-family:inherit;
|
|
111
|
+
cursor:pointer;
|
|
112
|
+
text-decoration:none;
|
|
113
|
+
display:inline-block;
|
|
114
|
+
transition:background .18s ease, transform .12s ease, box-shadow .18s ease, border-color .18s ease;
|
|
115
|
+
}
|
|
116
|
+
.btn-primary{
|
|
117
|
+
background:var(--primary);
|
|
118
|
+
color:#fff;
|
|
119
|
+
border:none;
|
|
120
|
+
box-shadow:0 8px 20px -8px rgba(109,91,208,.6);
|
|
121
|
+
}
|
|
122
|
+
.btn-primary:hover{background:var(--primary-dark);}
|
|
123
|
+
.btn-primary:active{transform:scale(.98);}
|
|
124
|
+
.btn-secondary{
|
|
125
|
+
background:#fff;
|
|
126
|
+
color:var(--text);
|
|
127
|
+
border:1.5px solid var(--border);
|
|
128
|
+
}
|
|
129
|
+
.btn-secondary:hover{border-color:var(--primary);background:var(--primary-light);}
|
|
130
|
+
|
|
131
|
+
.footer-note{margin-top:20px;font-size:12px;color:var(--muted);text-align:center;}
|
|
132
|
+
</style>
|
|
133
|
+
</head>
|
|
134
|
+
<body>
|
|
135
|
+
|
|
136
|
+
<div class="bg-blobs">
|
|
137
|
+
<div class="blob blob-1"></div>
|
|
138
|
+
<div class="blob blob-2"></div>
|
|
139
|
+
<div class="blob blob-3"></div>
|
|
140
|
+
</div>
|
|
141
|
+
|
|
142
|
+
<div class="wrapper">
|
|
143
|
+
<div class="card">
|
|
144
|
+
<div class="prism-mark">
|
|
145
|
+
<svg viewBox="0 0 100 100">
|
|
146
|
+
<polygon class="prism-tri" points="24,72 50,20 76,72" fill="rgba(239,68,68,.10)" stroke="#ef4444" stroke-width="3"/>
|
|
147
|
+
<line class="beam" x1="2" y1="55" x2="38" y2="55" stroke="#6d5bd0" stroke-width="4" stroke-linecap="round"/>
|
|
148
|
+
<line class="beam" x1="62" y1="46" x2="99" y2="30" stroke="#f59e0b" stroke-width="3" stroke-linecap="round"/>
|
|
149
|
+
<line class="beam" x1="62" y1="53" x2="99" y2="46" stroke="#ef4444" stroke-width="3" stroke-linecap="round" style="animation-delay:.15s"/>
|
|
150
|
+
<line class="beam" x1="62" y1="60" x2="99" y2="62" stroke="#f59e0b" stroke-width="3" stroke-linecap="round" style="animation-delay:.3s"/>
|
|
151
|
+
<g class="warn-badge">
|
|
152
|
+
<circle cx="78" cy="18" r="12" fill="#f59e0b"/>
|
|
153
|
+
<rect x="76.5" y="11" width="3" height="8" rx="1.5" fill="#fff"/>
|
|
154
|
+
<circle cx="78" cy="23" r="1.6" fill="#fff"/>
|
|
155
|
+
</g>
|
|
156
|
+
</svg>
|
|
157
|
+
</div>
|
|
158
|
+
|
|
159
|
+
<div class="error-code">500</div>
|
|
160
|
+
<h1>Something broke on our end</h1>
|
|
161
|
+
<p class="desc">The signal scattered before it reached the server. Our team has been notified — try again in a moment.</p>
|
|
162
|
+
|
|
163
|
+
<div class="actions">
|
|
164
|
+
<a href="#" onclick="location.reload(); return false;" class="btn-primary">Retry</a>
|
|
165
|
+
<!-- Static file, no Rails route helpers available — point this at your own admin root. -->
|
|
166
|
+
<a href="/" class="btn-secondary">Back to Dashboard</a>
|
|
167
|
+
</div>
|
|
168
|
+
</div>
|
|
169
|
+
<p class="footer-note">Prism theme for ActiveAdmin</p>
|
|
170
|
+
</div>
|
|
171
|
+
|
|
172
|
+
</body>
|
|
173
|
+
</html>
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveAdminPrism
|
|
4
|
+
module Generators
|
|
5
|
+
# rails g active_admin_prism:install
|
|
6
|
+
#
|
|
7
|
+
# The only manual install step this theme needs: enabling the sidebar.
|
|
8
|
+
# Stylesheet/javascript registration is automatic (see
|
|
9
|
+
# ActiveAdminPrism::Engine) — nothing to add to an asset manifest.
|
|
10
|
+
class InstallGenerator < ::Rails::Generators::Base
|
|
11
|
+
desc "Enables the Prism sidebar and Sass palette overrides"
|
|
12
|
+
|
|
13
|
+
ENABLE_LINE = "ActiveAdminPrism.enable!\n"
|
|
14
|
+
INITIALIZER_PATH = "config/initializers/active_admin.rb"
|
|
15
|
+
|
|
16
|
+
STYLESHEET_PATH = "app/assets/stylesheets/active_admin.scss"
|
|
17
|
+
VARIABLE_IMPORT_LINE = '@import "active_admin_prism/variable_overrides";'
|
|
18
|
+
MIXINS_IMPORT_PATTERN = /@import\s+["']active_admin\/mixins["'];?/.freeze
|
|
19
|
+
|
|
20
|
+
def enable_active_admin_prism
|
|
21
|
+
unless File.exist?(File.join(destination_root, INITIALIZER_PATH))
|
|
22
|
+
say_status :error,
|
|
23
|
+
"#{INITIALIZER_PATH} not found — run `rails g active_admin:install` first",
|
|
24
|
+
:red
|
|
25
|
+
return
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
if File.read(File.join(destination_root, INITIALIZER_PATH)).include?("ActiveAdminPrism.enable!")
|
|
29
|
+
say_status :identical, INITIALIZER_PATH, :blue
|
|
30
|
+
else
|
|
31
|
+
append_to_file INITIALIZER_PATH, "\n#{ENABLE_LINE}"
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Injects the palette override import just before
|
|
36
|
+
# `@import "active_admin/mixins"` — order matters, since every
|
|
37
|
+
# variable in variable_overrides.scss is `!default` and only wins if
|
|
38
|
+
# it runs first. See that file for what it overrides and why.
|
|
39
|
+
def override_active_admin_sass_variables
|
|
40
|
+
full_path = File.join(destination_root, STYLESHEET_PATH)
|
|
41
|
+
|
|
42
|
+
unless File.exist?(full_path)
|
|
43
|
+
say_status :skip,
|
|
44
|
+
"#{STYLESHEET_PATH} not found — if you add one later, put " \
|
|
45
|
+
"`#{VARIABLE_IMPORT_LINE}` before your \"active_admin/mixins\" import",
|
|
46
|
+
:yellow
|
|
47
|
+
return
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
contents = File.read(full_path)
|
|
51
|
+
|
|
52
|
+
if contents.include?("active_admin_prism/variable_overrides")
|
|
53
|
+
say_status :identical, STYLESHEET_PATH, :blue
|
|
54
|
+
return
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
unless contents.match?(MIXINS_IMPORT_PATTERN)
|
|
58
|
+
say_status :skip,
|
|
59
|
+
"couldn't find an `@import \"active_admin/mixins\";` line in #{STYLESHEET_PATH} — " \
|
|
60
|
+
"add `#{VARIABLE_IMPORT_LINE}` above it yourself",
|
|
61
|
+
:yellow
|
|
62
|
+
return
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
inject_into_file STYLESHEET_PATH, "#{VARIABLE_IMPORT_LINE}\n", before: MIXINS_IMPORT_PATTERN
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
data/lib/prism_icons.rb
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveAdminPrism
|
|
4
|
+
# A small, self-contained set of outline icons in the common
|
|
5
|
+
# "24x24, currentColor stroke" line-icon style. Kept intentionally tiny —
|
|
6
|
+
# just what the sidebar chrome needs — rather than bundling an icon font.
|
|
7
|
+
module Icons
|
|
8
|
+
ICONS = {
|
|
9
|
+
dashboard: '<rect x="3" y="3" width="8" height="8" rx="1.5"/><rect x="13" y="3" width="8" height="5" rx="1.5"/>' \
|
|
10
|
+
'<rect x="13" y="10" width="8" height="11" rx="1.5"/><rect x="3" y="13" width="8" height="8" rx="1.5"/>',
|
|
11
|
+
users: '<circle cx="9" cy="7" r="3.25"/><path d="M3 20c0-3.3 2.7-6 6-6s6 2.7 6 6"/>' \
|
|
12
|
+
'<path d="M16 4.3a3.25 3.25 0 0 1 0 6.4"/><path d="M15 14c2.8.4 5 2.8 5 6"/>',
|
|
13
|
+
cart: '<circle cx="9" cy="20" r="1.5"/><circle cx="18" cy="20" r="1.5"/>' \
|
|
14
|
+
'<path d="M2.5 3h2.4l1.2 12.1a2 2 0 0 0 2 1.9h9.4a2 2 0 0 0 2-1.7L21 7.5H6.4"/>',
|
|
15
|
+
box: '<path d="M12 3 3 7.5 12 12l9-4.5Z"/><path d="M3 7.5v9L12 21l9-4.5v-9"/><path d="M12 12v9"/>',
|
|
16
|
+
receipt: '<path d="M6 2h12v20l-3-2-3 2-3-2-3 2Z"/><path d="M9 8h6M9 12h6M9 16h3"/>',
|
|
17
|
+
credit_card: '<rect x="2.5" y="5" width="19" height="14" rx="2"/><path d="M2.5 10h19"/><path d="M6 15h4"/>',
|
|
18
|
+
message: '<path d="M4 4h16v12H8l-4 4Z"/>',
|
|
19
|
+
settings: '<circle cx="12" cy="12" r="3.2"/>' \
|
|
20
|
+
'<path d="M12 3.5v2.4M12 18.1v2.4M20.5 12h-2.4M5.9 12H3.5' \
|
|
21
|
+
'M17.7 6.3l-1.7 1.7M8 16l-1.7 1.7M17.7 17.7 16 16M8 8 6.3 6.3"/>',
|
|
22
|
+
chevron_down: '<polyline points="6 9 12 15 18 9"/>',
|
|
23
|
+
check: '<polyline points="4 12 9 17 20 6"/>',
|
|
24
|
+
x: '<path d="M5 5 19 19M19 5 5 19"/>',
|
|
25
|
+
home: '<path d="M4 11 12 4l8 7"/><path d="M6 10v10h12V10"/><path d="M10 20v-6h4v6"/>',
|
|
26
|
+
list: '<path d="M9 6h11M9 12h11M9 18h11"/><circle cx="4.5" cy="6" r="1.1"/>' \
|
|
27
|
+
'<circle cx="4.5" cy="12" r="1.1"/><circle cx="4.5" cy="18" r="1.1"/>',
|
|
28
|
+
folder: '<path d="M3 6.5a1 1 0 0 1 1-1h5l2 2.5h9a1 1 0 0 1 1 1V18a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1Z"/>',
|
|
29
|
+
bell: '<path d="M6 10a6 6 0 1 1 12 0c0 4 1.2 5.5 1.2 5.5H4.8S6 14 6 10Z"/><path d="M10 19a2 2 0 0 0 4 0"/>',
|
|
30
|
+
search: '<circle cx="10.5" cy="10.5" r="6.5"/><path d="M20 20l-4.7-4.7"/>',
|
|
31
|
+
menu: '<path d="M4 6h16M4 12h16M4 18h16"/>',
|
|
32
|
+
logout: '<path d="M9 4H5a1 1 0 0 0-1 1v14a1 1 0 0 0 1 1h4"/><path d="M14 8l4 4-4 4"/><path d="M18 12H9"/>',
|
|
33
|
+
eye: '<path d="M2 12s3.6-7 10-7 10 7 10 7-3.6 7-10 7-10-7-10-7Z"/><circle cx="12" cy="12" r="3"/>',
|
|
34
|
+
pencil: '<path d="M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4Z"/><path d="M14.5 5.5l3 3"/>',
|
|
35
|
+
trash: '<path d="M4 7h16"/><path d="M9 7V4h6v3"/><path d="M6 7l1 13h10l1-13"/>' \
|
|
36
|
+
'<path d="M10 11v6M14 11v6"/>',
|
|
37
|
+
filter: '<path d="M4 5h16l-6.5 7.5v6l-3 1.5v-7.5Z"/>',
|
|
38
|
+
globe: '<circle cx="12" cy="12" r="9"/><path d="M3 12h18"/>' \
|
|
39
|
+
'<path d="M12 3c2.5 2.4 4 5.6 4 9s-1.5 6.6-4 9c-2.5-2.4-4-5.6-4-9s1.5-6.6 4-9Z"/>'
|
|
40
|
+
}.freeze
|
|
41
|
+
|
|
42
|
+
# Returns an inline <svg>...</svg> string for `name`, or nil if unknown.
|
|
43
|
+
def self.svg(name, css_class: "prism-icon", size: 18)
|
|
44
|
+
inner = ICONS[name.to_sym]
|
|
45
|
+
return nil unless inner
|
|
46
|
+
|
|
47
|
+
%(<svg class="#{css_class}" width="#{size}" height="#{size}" viewBox="0 0 24 24" ) +
|
|
48
|
+
%(fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" ) +
|
|
49
|
+
%(stroke-linejoin="round" aria-hidden="true">#{inner}</svg>)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# The default sign-in page mark (see ActiveAdminPrism::Configuration
|
|
53
|
+
# #login_logo) — a generic glass-prism-with-spectrum motif distinct from
|
|
54
|
+
# the 24x24 line-icon set above (bigger, multi-color, animated via
|
|
55
|
+
# scss-src/_login.scss's .prism-login-tri/.prism-login-beam classes).
|
|
56
|
+
# Not tied to any brand — a host overriding #login_logo with their own
|
|
57
|
+
# image_tag/svg is the norm for a real app.
|
|
58
|
+
def self.login_mark(size: 64)
|
|
59
|
+
<<~SVG
|
|
60
|
+
<svg class="prism-login-mark" width="#{size}" height="#{size}" viewBox="0 0 100 100" aria-hidden="true">
|
|
61
|
+
<polygon class="prism-login-tri" points="24,72 50,20 76,72" fill="currentColor" fill-opacity="0.08" stroke="currentColor" stroke-width="3"/>
|
|
62
|
+
<line class="prism-login-beam" x1="2" y1="55" x2="38" y2="55" stroke="currentColor" stroke-width="4" stroke-linecap="round"/>
|
|
63
|
+
<line class="prism-login-beam" x1="62" y1="46" x2="99" y2="30" stroke="#e53935" stroke-width="3" stroke-linecap="round"/>
|
|
64
|
+
<line class="prism-login-beam" x1="62" y1="53" x2="99" y2="46" stroke="#fdd835" stroke-width="3" stroke-linecap="round"/>
|
|
65
|
+
<line class="prism-login-beam" x1="62" y1="60" x2="99" y2="62" stroke="#1e88e5" stroke-width="3" stroke-linecap="round"/>
|
|
66
|
+
<line class="prism-login-beam" x1="61" y1="67" x2="99" y2="78" stroke="#8e24aa" stroke-width="3" stroke-linecap="round"/>
|
|
67
|
+
</svg>
|
|
68
|
+
SVG
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Exposed as a view helper so hosts can call `prism_icon(:cart)` directly
|
|
73
|
+
# from Arbre blocks (app/admin/*.rb) or ERB views.
|
|
74
|
+
module IconHelper
|
|
75
|
+
def prism_icon(name, css_class: "prism-icon", size: 18)
|
|
76
|
+
svg = ActiveAdminPrism::Icons.svg(name, css_class: css_class, size: size)
|
|
77
|
+
svg&.html_safe # rubocop:disable Rails/OutputSafety
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
ActiveAdmin::ViewHelpers.include(ActiveAdminPrism::IconHelper) if defined?(ActiveAdmin::ViewHelpers)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveAdminPrism
|
|
4
|
+
# Resolves ActiveAdminPrism::Configuration#login_logo/#login_app_name/
|
|
5
|
+
# #login_tagline for app/views/active_admin/devise/sessions/new.html.erb.
|
|
6
|
+
#
|
|
7
|
+
# Mixed into ActiveAdmin::ViewHelpers (see the bottom of this file), which
|
|
8
|
+
# ActiveAdmin::Devise::Controller already adds as a controller `helper` —
|
|
9
|
+
# so these methods, and `render_in_context`/`active_admin_application`
|
|
10
|
+
# (both part of ActiveAdmin::ViewHelpers already), are directly callable
|
|
11
|
+
# from the plain-ERB devise views with no extra wiring.
|
|
12
|
+
module LoginHelper
|
|
13
|
+
def prism_login_logo_html
|
|
14
|
+
custom = render_in_context(self, ActiveAdminPrism.configuration.login_logo)
|
|
15
|
+
return custom.to_s.html_safe if custom.present? # rubocop:disable Rails/OutputSafety
|
|
16
|
+
|
|
17
|
+
ActiveAdminPrism::Icons.login_mark.html_safe # rubocop:disable Rails/OutputSafety
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def prism_login_app_name
|
|
21
|
+
custom = render_in_context(self, ActiveAdminPrism.configuration.login_app_name)
|
|
22
|
+
custom.presence || active_admin_application.site_title(self)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def prism_login_tagline
|
|
26
|
+
render_in_context(self, ActiveAdminPrism.configuration.login_tagline)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
ActiveAdmin::ViewHelpers.include(ActiveAdminPrism::LoginHelper) if defined?(ActiveAdmin::ViewHelpers)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveAdminPrism
|
|
4
|
+
# A read-only toggle-switch visual for boolean values on index/show pages
|
|
5
|
+
# — the same look as the opt-in `f.input :x, as: :prism_toggle` form
|
|
6
|
+
# input, but for display rather than editing. ActiveAdmin's own default
|
|
7
|
+
# (status_tag "Yes"/"No") is untouched; this is an explicit opt-in helper
|
|
8
|
+
# a host calls from its own `column`/`row` block, e.g.:
|
|
9
|
+
#
|
|
10
|
+
# index do
|
|
11
|
+
# column :active do |product|
|
|
12
|
+
# prism_toggle_tag product.active
|
|
13
|
+
# end
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
# show do
|
|
17
|
+
# attributes_table do
|
|
18
|
+
# row :active do |product|
|
|
19
|
+
# prism_toggle_tag product.active
|
|
20
|
+
# end
|
|
21
|
+
# end
|
|
22
|
+
# end
|
|
23
|
+
module ToggleTagHelper
|
|
24
|
+
def prism_toggle_tag(value, on_label: "Yes", off_label: "No")
|
|
25
|
+
label = value ? on_label : off_label
|
|
26
|
+
|
|
27
|
+
content_tag(:span, class: "prism-toggle-tag #{value ? 'on' : 'off'}",
|
|
28
|
+
role: "img", "aria-label": label, title: label) do
|
|
29
|
+
content_tag(:span, "", class: "prism-toggle-track", "aria-hidden": "true")
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
ActiveAdmin::ViewHelpers.include(ActiveAdminPrism::ToggleTagHelper) if defined?(ActiveAdmin::ViewHelpers)
|