pages_core 3.9.0 → 3.10.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.
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
+ }