pages_core 3.9.0 → 3.10.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +1 -3
  3. data/VERSION +1 -0
  4. data/app/assets/builds/pages_core/admin-dist.js +13 -13
  5. data/app/assets/stylesheets/pages/admin/controllers/pages.scss +6 -0
  6. data/app/controllers/admin/categories_controller.rb +3 -3
  7. data/app/controllers/admin/invites_controller.rb +1 -1
  8. data/app/controllers/admin/pages_controller.rb +1 -1
  9. data/app/controllers/admin/password_resets_controller.rb +7 -7
  10. data/app/controllers/admin/users_controller.rb +1 -1
  11. data/app/controllers/concerns/pages_core/error_reporting.rb +2 -0
  12. data/app/controllers/concerns/pages_core/ranged_response.rb +40 -0
  13. data/app/controllers/pages_core/attachments_controller.rb +6 -4
  14. data/app/controllers/pages_core/frontend/pages_controller.rb +1 -1
  15. data/app/controllers/sessions_controller.rb +5 -6
  16. data/app/javascript/components/ImageEditor/Form.jsx +1 -1
  17. data/app/javascript/components/ImageGrid.jsx +1 -1
  18. data/app/mailers/admin_mailer.rb +1 -1
  19. data/app/models/attachment.rb +1 -1
  20. data/app/models/concerns/pages_core/page_model/pathable.rb +1 -1
  21. data/app/models/invite.rb +0 -2
  22. data/app/models/page_category.rb +0 -1
  23. data/app/models/page_exporter.rb +2 -2
  24. data/app/models/password_reset_token.rb +0 -2
  25. data/app/models/tagging.rb +0 -2
  26. data/app/models/user.rb +1 -13
  27. data/app/views/admin/users/login.html.erb +2 -2
  28. data/app/views/admin/users/new_password.html.erb +1 -1
  29. data/app/views/admin_mailer/invite.text.erb +0 -2
  30. data/app/views/admin_mailer/password_reset.text.erb +0 -2
  31. data/app/views/feeds/pages.rss.builder +1 -1
  32. data/config/locales/en.yml +40 -14
  33. data/db/migrate/20220615160300_remove_username.rb +7 -0
  34. data/lib/pages_core/static_cache/page_cache_handler.rb +1 -1
  35. data/lib/pages_core/static_cache.rb +7 -3
  36. data/lib/rails/generators/pages_core/frontend/frontend_generator.rb +34 -34
  37. data/lib/rails/generators/pages_core/frontend/templates/{layout.html.erb → application.html.erb} +3 -0
  38. data/lib/rails/generators/pages_core/frontend/templates/javascript/lib/GridOverlay.js +66 -0
  39. data/lib/rails/generators/pages_core/frontend/templates/javascript/lib/ResponsiveEmbeds.js +72 -0
  40. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/application.sass.scss +15 -0
  41. data/lib/rails/generators/pages_core/frontend/templates/{base.scss.erb → stylesheets/components/base.scss} +9 -0
  42. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/config.scss +26 -0
  43. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/framework/breakpoints.scss +42 -0
  44. data/lib/rails/generators/pages_core/frontend/templates/{clearfix.scss.erb → stylesheets/framework/clearfix.scss} +0 -0
  45. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/framework/fonts.scss +32 -0
  46. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/framework/grid.scss +168 -0
  47. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/framework/grid_overlay.scss +44 -0
  48. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/global/colors.scss +8 -0
  49. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/global/typography.scss +90 -0
  50. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/vendor/normalize.css +349 -0
  51. metadata +26 -14
  52. data/lib/rails/generators/pages_core/frontend/templates/application.scss.erb +0 -3
  53. data/lib/rails/generators/pages_core/frontend/templates/breakpoints.scss.erb +0 -24
  54. data/lib/rails/generators/pages_core/frontend/templates/normalize.css.erb +0 -425
@@ -7,6 +7,9 @@
7
7
  <%# google_analytics_tags "UA-xxxxxxxx-1" %>
8
8
  <% end %>
9
9
  <body>
10
+ <% if Rails.env.development? %>
11
+ <div class="grid-overlay"></div>
12
+ <% end %>
10
13
  <%= yield %>
11
14
  </body>
12
15
  </html>
@@ -0,0 +1,66 @@
1
+ class GridOverlay {
2
+ constructor() {
3
+ this.gridOverlay = null;
4
+ this.showGrid = false;
5
+ this.init = this.init.bind(this);
6
+ }
7
+
8
+ bindHotkey() {
9
+ document.addEventListener("keyup", (evt) => {
10
+ if (evt.ctrlKey && evt.which == 71) {
11
+ this.toggle();
12
+ }
13
+ });
14
+ }
15
+
16
+ init() {
17
+ this.gridOverlay = document.querySelector(".grid-overlay");
18
+ if (this.gridOverlay) {
19
+ this.restoreState();
20
+ this.bindHotkey();
21
+ this.updateDOM();
22
+ }
23
+ }
24
+
25
+ ready(callback) {
26
+ if (document.readyState === "complete" ||
27
+ (document.readyState !== "loading" &&
28
+ !document.documentElement.doScroll)) {
29
+ callback();
30
+ } else {
31
+ document.addEventListener("DOMContentLoaded", callback);
32
+ }
33
+ }
34
+
35
+ restoreState() {
36
+ this.showGrid = window.localStorage.getItem("showGrid");
37
+ }
38
+
39
+ saveState() {
40
+ if (this.showGrid) {
41
+ window.localStorage.setItem("showGrid", "true");
42
+ } else {
43
+ window.localStorage.removeItem("showGrid");
44
+ }
45
+ }
46
+
47
+ start() {
48
+ this.ready(this.init);
49
+ }
50
+
51
+ toggle() {
52
+ this.showGrid = !this.showGrid;
53
+ this.saveState();
54
+ this.updateDOM();
55
+ }
56
+
57
+ updateDOM() {
58
+ if (this.showGrid) {
59
+ this.gridOverlay.classList.add("grid-overlay--active");
60
+ } else {
61
+ this.gridOverlay.classList.remove("grid-overlay--active");
62
+ }
63
+ }
64
+ }
65
+
66
+ export default new GridOverlay();
@@ -0,0 +1,72 @@
1
+ class ResponsiveEmbeds {
2
+ readyHandler(fn) {
3
+ if (document.readyState === "complete" || document.readyState === "interactive") {
4
+ setTimeout(fn, 1);
5
+ } else {
6
+ document.addEventListener("DOMContentLoaded", fn);
7
+ }
8
+ }
9
+
10
+ wrapEmbeds() {
11
+ let selectors = [ "iframe[src*=\"bandcamp.com\"]",
12
+ "iframe[src*=\"player.vimeo.com\"]",
13
+ "iframe[src*=\"youtube.com\"]",
14
+ "iframe[src*=\"youtube-nocookie.com\"]",
15
+ "iframe[src*=\"spotify.com\"]",
16
+ "iframe[src*=\"kickstarter.com\"][src*=\"video.html\"]" ];
17
+
18
+ let embeds = Array.prototype.slice.call(
19
+ document.querySelectorAll(selectors.join(","))
20
+ );
21
+
22
+ function wrapEmbed(embed) {
23
+ const parent = embed.parentNode;
24
+
25
+ // Recycle the existing container if the embed is already responsive.
26
+ if (parent.tagName === "DIV" &&
27
+ parent.childNodes.length === 1 &&
28
+ parent.style.position === "relative") {
29
+ return parent;
30
+ }
31
+
32
+ let wrapper = document.createElement("div");
33
+ if (parent.tagName === "P") {
34
+ parent.parentNode.replaceChild(wrapper, parent);
35
+ } else {
36
+ parent.replaceChild(wrapper, embed);
37
+ }
38
+ wrapper.appendChild(embed);
39
+ return wrapper;
40
+ }
41
+
42
+ embeds.forEach(function (embed) {
43
+ if (embed.parentNode &&
44
+ embed.parentNode.classList.contains("responsive-embed")) {
45
+ return;
46
+ }
47
+
48
+ let width = embed.offsetWidth;
49
+ let height = embed.offsetHeight;
50
+ let ratio = height / width;
51
+ let wrapper = wrapEmbed(embed);
52
+
53
+ wrapper.classList.add("responsive-embed");
54
+ wrapper.style.position = "relative";
55
+ wrapper.style.width = "100%";
56
+ wrapper.style.paddingTop = 0;
57
+ wrapper.style.paddingBottom = (ratio * 100) + "%";
58
+
59
+ embed.style.position = "absolute";
60
+ embed.style.width = "100%";
61
+ embed.style.height = "100%";
62
+ embed.style.top = "0";
63
+ embed.style.left = "0";
64
+ });
65
+ }
66
+
67
+ start() {
68
+ this.readyHandler(() => this.wrapEmbeds());
69
+ }
70
+ }
71
+
72
+ export default new ResponsiveEmbeds();
@@ -0,0 +1,15 @@
1
+ // Entry point for your Sass build
2
+ @import
3
+ 'vendor/normalize',
4
+ 'config',
5
+
6
+ 'framework/breakpoints',
7
+ 'framework/clearfix',
8
+ 'framework/grid',
9
+ 'framework/grid_overlay',
10
+ 'framework/fonts',
11
+
12
+ 'global/colors',
13
+ 'global/typography',
14
+
15
+ 'components/base';
@@ -1,3 +1,12 @@
1
1
  *, *:before, *:after {
2
2
  -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box;
3
3
  }
4
+
5
+ figure {
6
+ padding: 0px;
7
+ margin: 0px;
8
+ }
9
+
10
+ img {
11
+ display: block;
12
+ }
@@ -0,0 +1,26 @@
1
+ $breakpoints: (mobile: 900px,
2
+ large: 1400px);
3
+
4
+ $grids : (default: (column-count: 12,
5
+ column: 94px,
6
+ gutter: 24px,
7
+ padding: 24px),
8
+ mobile: (column-count: 4,
9
+ column: 60px,
10
+ gutter: 16px,
11
+ padding: 16px));
12
+
13
+ $spacings: (1: 8px,
14
+ 2: 16px,
15
+ 3: 24px,
16
+ 4: 32px,
17
+ 5: 40px,
18
+ 6: 48px,
19
+ 8: 64px,
20
+ 9: 72px,
21
+ 10: 80px,
22
+ 16: 128px,
23
+ 20: 160px);
24
+
25
+ // Uncomment to limit full width
26
+ // $limit-width: 1600px;
@@ -0,0 +1,42 @@
1
+ // ---- Defaults --------------------------------------------------------------
2
+
3
+ $breakpoints: (mobile: 900px,
4
+ large: 1400px) !default;
5
+
6
+
7
+ // ---- Mixins ----------------------------------------------------------------
8
+
9
+ @function breakpoint-value($value) {
10
+ @if type-of($value) == "string" {
11
+ @return map-get($breakpoints, $value);
12
+ }
13
+ @else {
14
+ @return $value;
15
+ }
16
+ }
17
+
18
+ @mixin breakpoint($min: "", $max: "", $orientation: "") {
19
+ $query: "screen";
20
+
21
+ @if $min != "" {
22
+ $query: $query + ' and (min-width: #{breakpoint-value($min)})';
23
+ }
24
+
25
+ @if $max != "" {
26
+ $query: $query + ' and (max-width: #{breakpoint-value($max)})';
27
+ }
28
+
29
+ @if $orientation != "" {
30
+ $query: $query + ' and (orientation: #{$orientation})';
31
+ }
32
+
33
+ @media #{$query} {
34
+ @content;
35
+ }
36
+ }
37
+
38
+ @mixin mobile {
39
+ @include breakpoint($max: mobile) {
40
+ @content
41
+ }
42
+ }
@@ -0,0 +1,32 @@
1
+ @use "sass:list";
2
+
3
+ @function font-extension($format) {
4
+ $font-extensions: (opentype: "otf", truetype: "ttf");
5
+ $value: map-get($font-extensions, $format);
6
+ @if $value {
7
+ @return $value;
8
+ }
9
+ @else {
10
+ @return $format;
11
+ }
12
+ }
13
+
14
+ @function font-sources($filename, $formats: ()) {
15
+ $urls: ();
16
+ @each $f in list.join((woff2 woff), $formats) {
17
+ $urls: list.append(
18
+ $urls,
19
+ url("#{$filename}.#{font-extension($f)}") format("#{$f}")
20
+ );
21
+ }
22
+ @return list.join($urls, (), comma);
23
+ }
24
+
25
+ @mixin font-face($name, $filename, $weight: 400, $style: normal, $formats: ()) {
26
+ @font-face {
27
+ font-family: $name;
28
+ font-style: $style;
29
+ font-weight: $weight;
30
+ src: font-sources($filename, $formats);
31
+ }
32
+ }
@@ -0,0 +1,168 @@
1
+ @use "sass:math";
2
+
3
+ // ---- Defaults --------------------------------------------------------------
4
+
5
+ $base-font-size: 16px !default;
6
+
7
+ $grids : (default: (column-count: 12,
8
+ column: 94px,
9
+ gutter: 24px,
10
+ padding: 24px),
11
+ mobile: (column-count: 4,
12
+ column: 60px,
13
+ gutter: 16px,
14
+ padding: 16px)) !default;
15
+
16
+ $spacings: (1: 12px,
17
+ 2: 24px,
18
+ 4: 40px,
19
+ 8: 80px) !default;
20
+
21
+ // Uncomment to limit full width
22
+ // $limit-width: 1600px !default;
23
+
24
+
25
+ // ---- Grid and sizing -------------------------------------------------------
26
+
27
+ @function grid-value($grid, $name) {
28
+ @return map-get(map-get($grids, $grid), $name);
29
+ }
30
+
31
+ // Inner width: Size of $grid in px, excluding outer padding
32
+ @function inner-width($grid: default) {
33
+ @return (grid-value($grid, column-count) * grid-value($grid, column)) +
34
+ ((grid-value($grid, column-count) - 1) * grid-value($grid, gutter));
35
+ }
36
+
37
+ // Full width in px including padding
38
+ @function full-width($grid: default) {
39
+ @return inner-width($grid) + (grid-value($grid, padding) * 2);
40
+ }
41
+
42
+ @function px-to-percent($size, $grid: default) {
43
+ @return percentage(math.div($size, full-width($grid)));
44
+ }
45
+
46
+ @function px-to-vw($size, $grid: default) {
47
+ @return (math.div($size, full-width($grid)) * 100) * 1vw;
48
+ }
49
+
50
+ @function relative-size($size-px, $container: 100%, $grid: default) {
51
+ @if unit($container) == '%' {
52
+ $container: (inner-width($grid) * math.div($container, 100%));
53
+ }
54
+ @if (unit($container) != "px") {
55
+ $container: columns-px($container, $grid: $grid);
56
+ }
57
+ @return percentage(math.div($size-px, $container));
58
+ }
59
+
60
+ @function rem-calc($value, $grid: default) {
61
+ @if unit($value) == "rem" {
62
+ @return $value;
63
+ }
64
+
65
+ // Assume px for values without units
66
+ @if unit($value) == "" {
67
+ $value: $value * 1px;
68
+ }
69
+
70
+ // Convert percentage to px
71
+ @if unit($value) == "%" {
72
+ $value: full-width($grid) * math.div($value, 100%);
73
+ }
74
+
75
+ @return math.div($value, $base-font-size) * 1rem;
76
+ }
77
+
78
+ @function spacing($key) {
79
+ @return rem-calc(map-get($spacings, $key));
80
+ }
81
+
82
+ // Width of gutter in px
83
+ @function gutter-px($grid: default) {
84
+ @return grid-value($grid, gutter);
85
+ }
86
+
87
+ // Width of $n columns in px
88
+ @function columns-px($n: 1, $grid: default) {
89
+ @return grid-value($grid, column) * $n + ((ceil($n) - 1) * gutter-px($grid));
90
+ }
91
+
92
+ // Gutter width, optionally relative to size of $container
93
+ @function gutter($container: 100%, $grid: default) {
94
+ @return relative-size(gutter-px($grid: $grid), $container, $grid: $grid);
95
+ }
96
+
97
+ // Width of $n columns as a percentage of $container.
98
+ @function columns($n: 1, $container: 100%, $grid: default) {
99
+ @return relative-size(columns-px($n, $grid: $grid), $container, $grid: $grid);
100
+ }
101
+
102
+ // Equal to columns($n) + gutter()
103
+ @function columns-and-gutter($n: 1, $container: 100%, $grid: default) {
104
+ @return columns($n, $container, $grid) + gutter($container, $grid);
105
+ }
106
+
107
+ @function grid-adjust($size, $columns: $total-columns, $grid: default) {
108
+ @return math.div($sizem math.div(columns($columns, $grid: $grid), 100%));
109
+ }
110
+
111
+ @function outer-padding($grid: default) {
112
+ @return px-to-percent(grid-value($grid, padding), $grid: $grid);
113
+ }
114
+
115
+ @function limit-width-scale($value) {
116
+ @return $value * math.div($limit-width, full-width());
117
+ }
118
+
119
+
120
+ // ---- Styles ----------------------------------------------------------------
121
+
122
+ @mixin mobile-full {
123
+ @include mobile {
124
+ width: 100%;
125
+ margin-left: 0px;
126
+ margin-right: 0px;
127
+ float: none;
128
+ @content;
129
+ }
130
+ }
131
+
132
+ @mixin mobile-offset {
133
+ @include mobile {
134
+ $offset: px-to-percent(grid-value(mobile, padding), $grid: mobile);
135
+
136
+ width: 100% + $offset;
137
+ margin-left: 0 - math.div($offset, 2);
138
+ margin-right: 0 - math.div($offset, 2);
139
+ }
140
+ }
141
+
142
+ @mixin grid-container-inner {
143
+ margin: 0px auto;
144
+ @if variable-exists(limit-width) {
145
+ @include breakpoint($min: rem-calc($limit-width)) {
146
+ max-width: rem-calc(limit-width-scale(inner-width()));
147
+ }
148
+ }
149
+ }
150
+
151
+ @mixin grid-container {
152
+ padding-left: outer-padding();
153
+ padding-right: outer-padding();
154
+
155
+ @include mobile {
156
+ padding-left: outer-padding(mobile);
157
+ padding-right: outer-padding(mobile);
158
+ }
159
+
160
+ @media print {
161
+ padding-left: 0px;
162
+ padding-right: 0px;
163
+ }
164
+
165
+ .inner {
166
+ @include grid-container-inner;
167
+ }
168
+ }
@@ -0,0 +1,44 @@
1
+ $grid-overlay-color: rgba(255, 0, 255, 0.05) !default;
2
+
3
+ @function grid-background($grid: default) {
4
+ $gradient: ();
5
+ @for $i from 1 to grid-value($grid, column-count) {
6
+ $gradient: join($gradient,
7
+ ($grid-overlay-color columns($i, $grid: $grid),
8
+ transparent columns($i, $grid: $grid),
9
+ transparent columns-and-gutter($i, $grid: $grid),
10
+ $grid-overlay-color (columns-and-gutter($i, $grid: $grid))),
11
+ comma);
12
+ }
13
+ @return linear-gradient(to right, #{$gradient});
14
+ }
15
+
16
+ .grid-overlay {
17
+ position: fixed;
18
+ z-index: 9000;
19
+ top: 0px;
20
+ left: 0px;
21
+ width: 100%;
22
+ height: 100%;
23
+ background-image: grid-background(default);
24
+ background-size: px-to-percent(inner-width(default)) 100%;
25
+ background-repeat: no-repeat;
26
+ background-position: 50% 50%;
27
+ pointer-events: none;
28
+ display: none;
29
+
30
+ @if variable-exists(limit-width) {
31
+ @include breakpoint($min: rem-calc($limit-width)) {
32
+ background-size: rem-calc(limit-width-scale(inner-width())) 100%;
33
+ }
34
+ }
35
+
36
+ @include mobile {
37
+ background-image: grid-background(mobile);
38
+ background-size: px-to-percent(inner-width(mobile), $grid: mobile) 100%;
39
+ }
40
+
41
+ &--active {
42
+ display: block;
43
+ }
44
+ }
@@ -0,0 +1,8 @@
1
+ $colors: (background: #ffffff,
2
+ text: #000000,
3
+ text-light: #a1a1a1,
4
+ border: #e0e0e0);
5
+
6
+ @function color($name) {
7
+ @return map-get($colors, $name);
8
+ }
@@ -0,0 +1,90 @@
1
+ $font-sans: 'Helvetica', sans-serif;
2
+
3
+ // ---- Mixins ----------------------------------------------------------------
4
+
5
+ @mixin child-margins {
6
+ &:first-child {
7
+ margin-top: 0px;
8
+ }
9
+ &:last-child {
10
+ margin-bottom: 0px;
11
+ }
12
+ }
13
+
14
+
15
+ // ---- Definitions -----------------------------------------------------------
16
+
17
+ %text-larger { font: normal 72px/1.00 $font-sans; }
18
+ %text-large { font: normal 54px/1.04 $font-sans; }
19
+ %text-medium { font: normal 24px/1.25 $font-sans; }
20
+ %text-normal { font: normal 16px/1.50 $font-sans; }
21
+ %text-small { font: normal 14px/1.5 $font-sans; }
22
+
23
+ @include mobile {
24
+ %text-large { font: normal 32px/1.13 $font-sans; }
25
+ %text-medium { font: normal 22px/1.27 $font-sans; }
26
+ %text-normal { font: normal 16px/1.31 $font-sans; }
27
+ %text-small-mobile,
28
+ %text-small { font: normal 13px/1.31 $font-sans; }
29
+ }
30
+
31
+
32
+ // ---- Rules -----------------------------------------------------------------
33
+
34
+ body {
35
+ @extend %text-normal;
36
+ }
37
+
38
+ h1, h2, h3, h4, h5, h6, ul, ol, p {
39
+ margin: 0px 0px spacing(2) 0px;
40
+ &:last-child {
41
+ margin-bottom: 0px;
42
+ }
43
+ }
44
+
45
+ h1 {
46
+ @extend %text-larger;
47
+ }
48
+
49
+ h2 {
50
+ @extend %text-large;
51
+ margin-top: spacing(10);
52
+ margin-bottom: spacing(10);
53
+ @include mobile {
54
+ margin-top: spacing(5);
55
+ margin-bottom: spacing(5);
56
+ }
57
+ @include child-margins;
58
+ }
59
+
60
+ h3 {
61
+ @extend %text-medium;
62
+ margin-top: spacing(5);
63
+ margin-bottom: spacing(5);
64
+ @include child-margins;
65
+ }
66
+
67
+ h4 {
68
+ font: inherit;
69
+ margin-top: spacing(5);
70
+ margin-bottom: 0px;
71
+ @include child-margins;
72
+ }
73
+
74
+ a, a:visited {
75
+ text-decoration: underline;
76
+ }
77
+
78
+ h1, h2, h3 {
79
+ a, a:visited {
80
+ text-decoration: none;
81
+ }
82
+ a:hover, a:focus {
83
+ text-decoration: underline;
84
+ }
85
+ }
86
+
87
+ figcaption {
88
+ @extend %text-small;
89
+ margin-top: spacing(2);
90
+ }