summaryrefslogtreecommitdiff
path: root/public
diff options
context:
space:
mode:
Diffstat (limited to 'public')
-rw-r--r--public/javascripts/admin_interface.js230
-rw-r--r--public/javascripts/admin_search.js43
-rw-r--r--public/javascripts/related_assets.js28
-rw-r--r--public/stylesheets/admin.css195
-rw-r--r--public/stylesheets/ccc.css38
5 files changed, 442 insertions, 92 deletions
diff --git a/public/javascripts/admin_interface.js b/public/javascripts/admin_interface.js
index 9da5d28..b7bdc10 100644
--- a/public/javascripts/admin_interface.js
+++ b/public/javascripts/admin_interface.js
@@ -1,15 +1,3 @@
1function hide_all() {
2 $('#recent_changes_toggle').attr("class", "unselected");
3 $('#my_work_toggle').attr("class", "unselected");
4 $('#current_drafts_toggle').attr("class", "unselected");
5 $('#admin_sitemap_toggle').attr("class", "unselected");
6
7 $('#current_drafts_table').hide();
8 $('#my_work_table').hide();
9 $('#recent_changes_table').hide();
10 $('#admin_sitemap_table').hide();
11}
12
13$(document).ready(function () { 1$(document).ready(function () {
14 admin_search.initialize(); 2 admin_search.initialize();
15 3
@@ -19,15 +7,29 @@ $(document).ready(function () {
19 promotion: false, 7 promotion: false,
20 menubar: false, 8 menubar: false,
21 plugins: 'code link lists visualblocks', 9 plugins: 'code link lists visualblocks',
22 toolbar: 'bold italic underline | bullist numlist | link unlink | blocks | code', 10 toolbar: 'bold italic underline | bullist numlist | link unlink | insertpageimage | blocks | code',
23 extended_valid_elements: 'aggregate[children|tags|limit|order_by|order_direction|partial|conditions]', 11 extended_valid_elements: 'aggregate[children|tags|limit|order_by|order_direction|partial|conditions],a[href|target|rel|class|data-gallery],img[class|src|alt|title|width|height|style|border]',
24 relative_urls: false, 12 relative_urls: false,
25 entity_encoding: 'raw', 13 entity_encoding: 'raw',
26 valid_classes: { '*': '' }, 14 content_style: '.inline-image--full { width: 100%; margin: 1rem 0; } .inline-image--half { width: 48%; margin-bottom: 1rem; } .inline-image--left { float: left; margin-right: 1rem; } .inline-image--right { float: right; margin-left: 1rem; }',
15 valid_classes: {
16 '*': '',
17 'img': 'inline-image inline-image--full inline-image--half inline-image--left inline-image--right',
18 'a': 'glightbox'
19 },
27 setup: function(editor) { 20 setup: function(editor) {
28 editor.on('init', function() { 21 editor.on('init', function() {
29 cccms.setup_autosave(); 22 cccms.setup_autosave();
30 }); 23 });
24
25 editor.ui.registry.addButton('insertpageimage', {
26 icon: 'image',
27 text: 'Insert image',
28 tooltip: "Insert one of this page's attached images",
29 onAction: function() {
30 cccms.inline_images.open(editor);
31 }
32 });
31 } 33 }
32 }); 34 });
33 35
@@ -55,6 +57,10 @@ $(document).ready(function () {
55 move_to_search.initialize_search(); 57 move_to_search.initialize_search();
56 } 58 }
57 59
60 if ($("#restore_search_term").length != 0) {
61 restore_search.initialize_search();
62 }
63
58 if ($("#event_node_search_term").length != 0) { 64 if ($("#event_node_search_term").length != 0) {
59 event_search.initialize_search(); 65 event_search.initialize_search();
60 } 66 }
@@ -71,63 +77,13 @@ $(document).ready(function () {
71 cccms.preview.initialize(); 77 cccms.preview.initialize();
72 } 78 }
73 79
74 if ($('#recent_changes_toggle').length != 0) {
75 hide_all();
76 $('#recent_changes_toggle').attr("class", "selected");
77 $('#recent_changes_table').show();
78
79 $('#recent_changes_toggle').bind("click", function(){
80 hide_all();
81 $('#recent_changes_toggle').attr("class", "selected");
82 $('#recent_changes_table').show();
83 return false;
84 });
85
86 $('#my_work_toggle').bind("click", function(){
87 hide_all();
88 $('#my_work_toggle').attr("class", "selected");
89 $('#my_work_table').show();
90 return false;
91 });
92
93 $('#admin_wizard_my_work').bind("click", function(){
94 hide_all();
95 $('#my_work_toggle').attr("class", "selected");
96 $('#my_work_table').show();
97 return false;
98 });
99
100 $('#current_drafts_toggle').bind("click", function(){
101 hide_all();
102 $('#current_drafts_toggle').attr("class", "selected");
103 $('#current_drafts_table').show();
104 return false;
105 });
106
107 $('#admin_sitemap_toggle').bind("click", function(){
108 hide_all();
109 $('#admin_sitemap_toggle').attr("class", "selected");
110 $('#admin_sitemap_table').show();
111 return false;
112 });
113
114 $('#admin_wizard_create_page').bind("click", function(){
115 hide_all();
116 $('#admin_sitemap_toggle').attr("class", "selected");
117 $('#admin_sitemap_table').show();
118 return false;
119 });
120 }
121
122 jQuery.ajaxSetup({ 80 jQuery.ajaxSetup({
123 'beforeSend': function(xhr) {xhr.setRequestHeader("Accept", "text/javascript");} 81 'beforeSend': function(xhr) {xhr.setRequestHeader("Accept", "text/javascript");}
124 }); 82 });
125 83
126 $(document).ajaxSend(function(event, request, settings) { 84 $(document).ajaxSend(function(event, request, settings) {
127 if (typeof(AUTH_TOKEN) == "undefined") return; 85 var meta = document.querySelector("meta[name='csrf-token']");
128 // settings.data is a serialized string like "foo=bar&baz=boink" (or null) 86 if (meta) request.setRequestHeader("X-CSRF-Token", meta.content);
129 settings.data = settings.data || "";
130 settings.data += (settings.data ? "&" : "") + "authenticity_token=" + encodeURIComponent(AUTH_TOKEN);
131 }); 87 });
132 88
133}); 89});
@@ -172,6 +128,10 @@ cccms = {
172 options = options || {}; 128 options = options || {};
173 if (options.force || page.title_has_changed() || page.abstract_has_changed() || page.body_has_changed()) { 129 if (options.force || page.title_has_changed() || page.abstract_has_changed() || page.body_has_changed()) {
174 130
131 elements.body.find('a.glightbox').each(function() {
132 if ($(this).find('img').length === 0) { $(this).remove(); }
133 });
134
175 tinymce.triggerSave(); 135 tinymce.triggerSave();
176 page.cached_title = elements.title.val(); 136 page.cached_title = elements.title.val();
177 page.cached_abstract = elements.abstract.val(); 137 page.cached_abstract = elements.abstract.val();
@@ -252,6 +212,96 @@ cccms = {
252 refresh_if_open : function() { 212 refresh_if_open : function() {
253 if (cccms.preview.is_open) cccms.preview.refresh(); 213 if (cccms.preview.is_open) cccms.preview.refresh();
254 } 214 }
215 },
216
217 inline_images: {
218 ensure_overlay: function() {
219 if ($('#inline_image_picker').length) return;
220
221 var overlay = $(
222 '<div id="inline_image_picker" style="display:none">' +
223 '<div id="inline_image_picker_grid"></div>' +
224 '<div id="inline_image_picker_actions">' +
225 '<button type="button" data-placement="full">Insert full width</button>' +
226 '<button type="button" data-placement="left">Insert, align left</button>' +
227 '<button type="button" data-placement="right">Insert, align right</button>' +
228 '<button type="button" id="inline_image_picker_cancel">Cancel</button>' +
229 '</div>' +
230 '</div>'
231 );
232 $('body').append(overlay);
233
234 overlay.on('click', '#inline_image_picker_grid img', function() {
235 overlay.find('#inline_image_picker_grid img').removeClass('selected');
236 $(this).addClass('selected');
237 cccms.inline_images.selected_index = $(this).data('index');
238 });
239
240 overlay.on('click', '[data-placement]', function() {
241 cccms.inline_images.insert($(this).data('placement'));
242 });
243
244 overlay.on('click', '#inline_image_picker_cancel', function() {
245 overlay.hide();
246 });
247 },
248
249 open: function(editor) {
250 cccms.inline_images.ensure_overlay();
251 cccms.inline_images.editor = editor;
252
253 var showUrl = $("#page_editor > form").attr("data-show-url") || "";
254 var match = showUrl.match(/(\d+)$/);
255 cccms.inline_images.node_id = match ? match[1] : "";
256
257 var items = $('#related_asset_list li').map(function() {
258 return {
259 thumb: $(this).find('img').attr('src'),
260 large: $(this).data('large-url'),
261 original: $(this).data('original-url'),
262 name: $(this).data('name')
263 };
264 }).get();
265 cccms.inline_images.items = items;
266
267 var grid = $('#inline_image_picker_grid').empty();
268 if (items.length === 0) {
269 grid.append('<p>No images are attached to this page yet -- attach one from the Images section first.</p>');
270 cccms.inline_images.selected_index = null;
271 } else {
272 items.forEach(function(item, i) {
273 var wrapper = $('<div class="inline_image_picker_item"></div>');
274 wrapper.append($('<img>').attr('src', item.thumb).attr('data-index', i));
275 if (i === 0) {
276 wrapper.append($('<span>', { "class": "inline_image_picker_headline_badge" }).text("Headline"));
277 }
278 grid.append(wrapper);
279 });
280 cccms.inline_images.selected_index = 0;
281 grid.find('img').first().addClass('selected');
282 }
283
284 $('#inline_image_picker').show();
285 },
286
287 escape_attr: function(str) {
288 return String(str || '').replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
289 },
290
291 insert: function(placement) {
292 var item = cccms.inline_images.items[cccms.inline_images.selected_index];
293 if (!item) return;
294
295 var classes = placement === 'full'
296 ? 'inline-image inline-image--full'
297 : 'inline-image inline-image--half inline-image--' + placement;
298
299 var html = '<a href="' + item.original + '" class="glightbox" data-gallery="page-' + cccms.inline_images.node_id + '">' +
300 '<img src="' + item.large + '" class="' + classes + '" alt="' + cccms.inline_images.escape_attr(item.name) + '"></a>';
301
302 cccms.inline_images.editor.insertContent(html);
303 $('#inline_image_picker').hide();
304 }
255 } 305 }
256} 306}
257 307
@@ -367,8 +417,10 @@ rrule_builder = {
367 }); 417 });
368 $("#rrule_monthly_ordinal").bind("change", function() { 418 $("#rrule_monthly_ordinal").bind("change", function() {
369 $("#rrule_ordinal_fields").toggle($(this).is(":checked")); 419 $("#rrule_ordinal_fields").toggle($(this).is(":checked"));
420 rrule_builder.toggle_custom_ordinal_fields();
370 rrule_builder.sync(); 421 rrule_builder.sync();
371 }); 422 });
423 $("#rrule_ordinal").bind("change", rrule_builder.toggle_custom_ordinal_fields);
372 $("#rrule_exclude_month").bind("change", function() { 424 $("#rrule_exclude_month").bind("change", function() {
373 $("#rrule_excluded_month").toggle($(this).is(":checked")); 425 $("#rrule_excluded_month").toggle($(this).is(":checked"));
374 rrule_builder.sync(); 426 rrule_builder.sync();
@@ -385,6 +437,12 @@ rrule_builder = {
385 $("#rrule_monthly_options").show(); 437 $("#rrule_monthly_options").show();
386 }, 438 },
387 439
440 toggle_custom_ordinal_fields : function() {
441 $("#rrule_custom_ordinal_fields").toggle(
442 $("#rrule_monthly_ordinal").is(":checked") && $("#rrule_ordinal").val() === "custom"
443 );
444 },
445
388 sync : function() { 446 sync : function() {
389 var freq = $("input[name='rrule_freq']:checked").val(); 447 var freq = $("input[name='rrule_freq']:checked").val();
390 var parts = []; 448 var parts = [];
@@ -400,7 +458,16 @@ rrule_builder = {
400 } else { 458 } else {
401 parts.push("FREQ=MONTHLY"); 459 parts.push("FREQ=MONTHLY");
402 if ($("#rrule_monthly_ordinal").is(":checked")) { 460 if ($("#rrule_monthly_ordinal").is(":checked")) {
403 parts.push("BYDAY=" + $("#rrule_ordinal").val() + $("#rrule_ordinal_day").val()); 461 var ordinal = $("#rrule_ordinal").val();
462 if (ordinal === "custom") {
463 var customDays = [];
464 $("input[id^='rrule_custom_ordinal_']:checked").each(function() {
465 customDays.push($(this).attr("id").replace("rrule_custom_ordinal_", "") + $("#rrule_ordinal_day").val());
466 });
467 if (customDays.length > 0) parts.push("BYDAY=" + customDays.join(","));
468 } else {
469 parts.push("BYDAY=" + ordinal + $("#rrule_ordinal_day").val());
470 }
404 } 471 }
405 } 472 }
406 473
@@ -435,8 +502,33 @@ rrule_builder = {
435 } else if (parts.FREQ === "MONTHLY") { 502 } else if (parts.FREQ === "MONTHLY") {
436 $("input[name='rrule_freq'][value='monthly']").prop("checked", true); 503 $("input[name='rrule_freq'][value='monthly']").prop("checked", true);
437 rrule_builder.show_monthly_options(); 504 rrule_builder.show_monthly_options();
505 var ordinalDays = parts.BYDAY && parts.BYDAY.split(",");
506 var customOrdinalDay = null;
507 var customOrdinals = [];
508 var customOrdinalsValid = ordinalDays && ordinalDays.length > 0;
509 if (customOrdinalsValid) {
510 ordinalDays.forEach(function(value) {
511 var customMatch = value.match(/^([1-5])([A-Z]{2})$/);
512 if (!customMatch || (customOrdinalDay && customOrdinalDay !== customMatch[2])) {
513 customOrdinalsValid = false;
514 return;
515 }
516 customOrdinalDay = customMatch[2];
517 customOrdinals.push(customMatch[1]);
518 });
519 }
520
438 var match = parts.BYDAY && parts.BYDAY.match(/^(-?\d+)([A-Z]{2})$/); 521 var match = parts.BYDAY && parts.BYDAY.match(/^(-?\d+)([A-Z]{2})$/);
439 if (match) { 522 if (customOrdinalsValid && (customOrdinals.length > 1 || customOrdinals[0] === "5")) {
523 $("#rrule_monthly_ordinal").prop("checked", true);
524 $("#rrule_ordinal_fields").show();
525 $("#rrule_ordinal").val("custom");
526 $("#rrule_ordinal_day").val(customOrdinalDay);
527 customOrdinals.forEach(function(ordinal) {
528 $("#rrule_custom_ordinal_" + ordinal).prop("checked", true);
529 });
530 rrule_builder.toggle_custom_ordinal_fields();
531 } else if (match) {
440 $("#rrule_monthly_ordinal").prop("checked", true); 532 $("#rrule_monthly_ordinal").prop("checked", true);
441 $("#rrule_ordinal_fields").show(); 533 $("#rrule_ordinal_fields").show();
442 $("#rrule_ordinal").val(match[1]); 534 $("#rrule_ordinal").val(match[1]);
diff --git a/public/javascripts/admin_search.js b/public/javascripts/admin_search.js
index 7604bb7..b53c931 100644
--- a/public/javascripts/admin_search.js
+++ b/public/javascripts/admin_search.js
@@ -72,24 +72,20 @@ function initSearchPicker(options) {
72 found = false; 72 found = false;
73 for (var i = 0; i < data.length; i++) { 73 for (var i = 0; i < data.length; i++) {
74 (function(node) { 74 (function(node) {
75 var link; 75 var anchor = $("<a>").attr("href", onSelect ? "#" : node.node_path);
76 anchor.append(document.createTextNode(node.title || ""));
77 anchor.append($("<span>", { "class": "result_path" }).text(node.unique_name || ""));
78 var link = $("<p>").append(anchor);
79
76 if (onSelect) { 80 if (onSelect) {
77 link = $( 81 anchor.bind("click", function() {
78 "<p><a href='#'>" + node.title +
79 "<span class='result_path'>" + node.unique_name + "</span></a></p>"
80 );
81 link.find("a").bind("click", function() {
82 onSelect(node); 82 onSelect(node);
83 results.slideUp(); 83 results.slideUp();
84 results.empty(); 84 results.empty();
85 return false; 85 return false;
86 }); 86 });
87 } else {
88 link = $(
89 "<p><a href='" + node.node_path + "'>" + node.title +
90 "<span class='result_path'>" + node.unique_name + "</span></a></p>"
91 );
92 } 87 }
88
93 results.append(link); 89 results.append(link);
94 found = true; 90 found = true;
95 })(data[i]); 91 })(data[i]);
@@ -150,7 +146,9 @@ dashboard_search = {
150 results.append("<p class='search_group_label'>Tags</p>"); 146 results.append("<p class='search_group_label'>Tags</p>");
151 var tag_row = $("<div class='search_tag_row'></div>"); 147 var tag_row = $("<div class='search_tag_row'></div>");
152 data.tags.forEach(function(tag) { 148 data.tags.forEach(function(tag) {
153 tag_row.append("<a class='search_tag_pill' href='" + tag.tag_path + "'>" + tag.name + "</a>"); 149 tag_row.append(
150 $("<a>", { "class": "search_tag_pill" }).attr("href", tag.tag_path).text(tag.name || "")
151 );
154 found = true; 152 found = true;
155 }); 153 });
156 results.append(tag_row); 154 results.append(tag_row);
@@ -159,10 +157,10 @@ dashboard_search = {
159 if (data.nodes.length) { 157 if (data.nodes.length) {
160 results.append("<p class='search_group_label'>Pages</p>"); 158 results.append("<p class='search_group_label'>Pages</p>");
161 data.nodes.forEach(function(node) { 159 data.nodes.forEach(function(node) {
162 results.append( 160 var anchor = $("<a>").attr("href", node.node_path);
163 "<p><a href='" + node.node_path + "'>" + node.title + 161 anchor.append(document.createTextNode(node.title || ""));
164 "<span class='result_path'>" + node.unique_name + "</span></a></p>" 162 anchor.append($("<span>", { "class": "result_path" }).text(node.unique_name || ""));
165 ); 163 results.append($("<p>").append(anchor));
166 found = true; 164 found = true;
167 }); 165 });
168 } 166 }
@@ -264,6 +262,19 @@ move_to_search = {
264 } 262 }
265}; 263};
266 264
265restore_search = {
266 initialize_search : function() {
267 initSearchPicker({
268 inputSelector: "#restore_search_term",
269 resultsSelector: "#restore_search_results",
270 onSelect: function(node) {
271 $("#restore_search_term").val(node.title);
272 $("#parent_id").val(node.node_id);
273 }
274 });
275 }
276};
277
267event_search = { 278event_search = {
268 initialize_search : function() { 279 initialize_search : function() {
269 initSearchPicker({ 280 initSearchPicker({
diff --git a/public/javascripts/related_assets.js b/public/javascripts/related_assets.js
index 2955cbf..3340fa7 100644
--- a/public/javascripts/related_assets.js
+++ b/public/javascripts/related_assets.js
@@ -5,6 +5,8 @@ related_assets = {
5 var createUrl = container.data("create-url"); 5 var createUrl = container.data("create-url");
6 var list = $("#related_asset_list"); 6 var list = $("#related_asset_list");
7 7
8 related_assets.update_headline_badge(list);
9
8 initSearchPicker({ 10 initSearchPicker({
9 inputSelector: "#related_asset_search_term", 11 inputSelector: "#related_asset_search_term",
10 resultsSelector: "#related_asset_search_results", 12 resultsSelector: "#related_asset_search_results",
@@ -13,12 +15,9 @@ related_assets = {
13 renderResults: function(data, results) { 15 renderResults: function(data, results) {
14 var found = false; 16 var found = false;
15 data.forEach(function(asset) { 17 data.forEach(function(asset) {
16 var item = $( 18 var item = $("<a>", { href: "#", "class": "related_asset_result" });
17 "<a href='#' class='related_asset_result'>" + 19 item.append($("<img>", { src: asset.thumb_url, alt: "" }));
18 "<img src='" + asset.thumb_url + "' alt=''>" + 20 item.append($("<span>").text(asset.name || ""));
19 "<span>" + asset.name + "</span>" +
20 "</a>"
21 );
22 item.bind("click", function() { 21 item.bind("click", function() {
23 related_assets.attach(asset.id, createUrl, list); 22 related_assets.attach(asset.id, createUrl, list);
24 return false; 23 return false;
@@ -45,6 +44,7 @@ related_assets = {
45 url: ui.item.data("url"), 44 url: ui.item.data("url"),
46 data: "position=" + newPosition 45 data: "position=" + newPosition
47 }); 46 });
47 related_assets.update_headline_badge(list);
48 } 48 }
49 }); 49 });
50 50
@@ -55,11 +55,23 @@ related_assets = {
55 url: item.data("url"), 55 url: item.data("url"),
56 success: function() { 56 success: function() {
57 item.remove(); 57 item.remove();
58 related_assets.update_headline_badge(list);
58 } 59 }
59 }); 60 });
60 }); 61 });
61 }, 62 },
62 63
64 update_headline_badge: function(list) {
65 list.find(".related_asset_headline_badge").remove();
66 var first = list.children("li").first();
67 if (first.length) {
68 $("<span>", {
69 "class": "related_asset_headline_badge",
70 "title": "Shown automatically as this page's headline image"
71 }).text("Headline").insertBefore(first.find(".related_asset_remove"));
72 }
73 },
74
63 attach: function(assetId, createUrl, list) { 75 attach: function(assetId, createUrl, list) {
64 $.ajax({ 76 $.ajax({
65 type: "POST", 77 type: "POST",
@@ -69,9 +81,13 @@ related_assets = {
69 success: function(related) { 81 success: function(related) {
70 var item = $($("#related_asset_template").html().trim()); 82 var item = $($("#related_asset_template").html().trim());
71 item.attr("data-url", related.url); 83 item.attr("data-url", related.url);
84 item.attr("data-large-url", related.large_url);
85 item.attr("data-original-url", related.original_url);
86 item.attr("data-name", related.name);
72 item.find("img").attr("src", related.thumb_url); 87 item.find("img").attr("src", related.thumb_url);
73 list.append(item); 88 list.append(item);
74 list.sortable("refresh"); 89 list.sortable("refresh");
90 related_assets.update_headline_badge(list);
75 $("#related_asset_search_term").val(""); 91 $("#related_asset_search_term").val("");
76 $("#related_asset_search_results").slideUp().empty(); 92 $("#related_asset_search_results").slideUp().empty();
77 } 93 }
diff --git a/public/stylesheets/admin.css b/public/stylesheets/admin.css
index 5f7723b..05e47e7 100644
--- a/public/stylesheets/admin.css
+++ b/public/stylesheets/admin.css
@@ -37,10 +37,13 @@ td {
37 depend on this rule for vertical padding. table.node_table td resets 37 depend on this rule for vertical padding. table.node_table td resets
38 padding-top/bottom to 0 explicitly and does not depend on it. */ 38 padding-top/bottom to 0 explicitly and does not depend on it. */
39 39
40input[type=text], textarea { 40input[type=text],
41input[type=password],
42textarea {
41 font-size: 1rem; 43 font-size: 1rem;
42 font-family: Helvetica; 44 font-family: Helvetica;
43 border: 1px solid #989898; 45 border: 1px solid #989898;
46 border-radius: 2px;
44} 47}
45 48
46select { 49select {
@@ -764,6 +767,15 @@ table.user_table td.user_login {
764 display: block; 767 display: block;
765} 768}
766 769
770.node_content .inline-image--full,
771.node_content .inline-image--half {
772 max-width: 300px;
773 width: auto;
774 float: none;
775 display: block;
776 margin: 0.5rem 0;
777}
778
767.action_button, 779.action_button,
768form.button_to input[type="submit"], 780form.button_to input[type="submit"],
769form.button_to button[type="submit"] { 781form.button_to button[type="submit"] {
@@ -872,6 +884,10 @@ form.button_to button[type="submit"] {
872 margin-top: -5px; 884 margin-top: -5px;
873} 885}
874 886
887.aligned_action_row .action_button.action_button_no_margin_top {
888 margin-top: 0;
889}
890
875/* ============================================================ 891/* ============================================================
876 Page editor / metadata forms 892 Page editor / metadata forms
877 ============================================================ */ 893 ============================================================ */
@@ -1112,6 +1128,25 @@ div#draft_list table td.actions a {
1112 font-size: 0.9em; 1128 font-size: 0.9em;
1113} 1129}
1114 1130
1131#recent_changes_full_list {
1132 list-style: none;
1133 padding: 0;
1134 margin: 0;
1135}
1136
1137#recent_changes_full_list li {
1138 padding: 0.75rem 0;
1139 border-bottom: 1px solid #eee;
1140}
1141
1142#recent_changes_full_list li:last-child {
1143 border-bottom: none;
1144}
1145
1146#recent_changes_full_list li > div {
1147 margin-bottom: 0.25rem;
1148}
1149
1115/* ============================================================ 1150/* ============================================================
1116 Search widgets 1151 Search widgets
1117 ============================================================ */ 1152 ============================================================ */
@@ -1292,6 +1327,15 @@ div#image_browser ul li {
1292 height: 1rem; 1327 height: 1rem;
1293} 1328}
1294 1329
1330.related_asset_headline_badge {
1331 background: #fff3cd;
1332 color: #6b5900;
1333 border-radius: 999px;
1334 padding: 0.1rem 0.6rem;
1335 font-size: 0.75em;
1336 white-space: nowrap;
1337}
1338
1295.related_asset_remove { 1339.related_asset_remove {
1296 display: flex; 1340 display: flex;
1297 align-items: center; 1341 align-items: center;
@@ -1392,3 +1436,152 @@ div#image_browser ul li {
1392 border-color: #a9c6e8; 1436 border-color: #a9c6e8;
1393 color: #1a4d8f; 1437 color: #1a4d8f;
1394} 1438}
1439
1440/* ============================================================
1441 Image picker
1442 ============================================================ */
1443
1444#inline_image_picker {
1445 position: fixed;
1446 top: 10%;
1447 left: 50%;
1448 transform: translateX(-50%);
1449 background: #fff;
1450 border: 1px solid #ddd;
1451 border-radius: 8px;
1452 padding: 1rem;
1453 max-width: 480px;
1454 max-height: 70vh;
1455 overflow-y: auto;
1456 z-index: 1000;
1457 box-shadow: 0 4px 16px rgba(0,0,0,0.2);
1458}
1459
1460#inline_image_picker_grid {
1461 display: flex;
1462 flex-wrap: wrap;
1463 gap: 8px;
1464 margin-bottom: 1rem;
1465}
1466
1467.inline_image_picker_item {
1468 position: relative;
1469}
1470
1471#inline_image_picker_grid img {
1472 width: 80px;
1473 height: 80px;
1474 object-fit: cover;
1475 border-radius: 4px;
1476 cursor: pointer;
1477 border: 2px solid transparent;
1478 display: block;
1479}
1480
1481.inline_image_picker_headline_badge {
1482 position: absolute;
1483 bottom: 2px;
1484 left: 2px;
1485 right: 2px;
1486 background: rgba(255, 243, 205, 0.95);
1487 color: #6b5900;
1488 font-size: 0.65em;
1489 text-align: center;
1490 border-radius: 3px;
1491 padding: 1px 0;
1492 pointer-events: none;
1493}
1494
1495#inline_image_picker_grid img.selected {
1496 border-color: #1a4d8f;
1497}
1498
1499#inline_image_picker_actions {
1500 display: flex;
1501 gap: 8px;
1502 flex-wrap: wrap;
1503}
1504
1505/* ============================================================
1506 Action log
1507 ============================================================ */
1508
1509#node_action_list td.node_action_body {
1510 border-bottom: 1px solid #f1f1f1;
1511}
1512
1513.dashboard_widget .node_action_time span {
1514 display: block;
1515}
1516
1517#node_action_list td.node_action_time {
1518 white-space: nowrap;
1519 vertical-align: top;
1520 font-family: monospace;
1521 font-size: 0.8em;
1522 color: #777;
1523 padding-right: 1em;
1524}
1525
1526#node_action_list td.node_action_body {
1527 vertical-align: top;
1528}
1529
1530.node_action_inferred {
1531 opacity: 0.5;
1532 font-size: smaller;
1533 margin-left: 0.5em;
1534}
1535
1536.node_action_zoom {
1537 font-size: smaller;
1538 margin-left: 0.5em;
1539}
1540
1541.node_action_details summary {
1542 cursor: pointer;
1543 font-size: smaller;
1544 color: #777;
1545}
1546
1547.node_action_icon {
1548 color: #777;
1549 margin-right: 0.35em;
1550 vertical-align: text-bottom;
1551}
1552
1553.revision_lifecycle {
1554 font-size: 0.85rem;
1555 color: #777;
1556}
1557
1558/* ============================================================
1559 Trash section
1560 ============================================================ */
1561
1562.restore_form {
1563 display: flex;
1564 align-items: center;
1565 gap: 8px;
1566}
1567
1568.restore_picker {
1569 position: relative;
1570}
1571
1572.restore_picker input[type=text] {
1573 width: 22em;
1574}
1575
1576.restore_picker .search_results {
1577 position: absolute;
1578 top: 100%;
1579 left: 0;
1580 right: 0;
1581 z-index: 10;
1582 background: #fff;
1583 border: 1px solid #989898;
1584 border-top: none;
1585 max-height: 20em;
1586 overflow-y: auto;
1587}
diff --git a/public/stylesheets/ccc.css b/public/stylesheets/ccc.css
index fe2144f..cbeea17 100644
--- a/public/stylesheets/ccc.css
+++ b/public/stylesheets/ccc.css
@@ -610,3 +610,41 @@ label[for=light-mode] {
610 } 610 }
611} 611}
612 612
613.chapter_partial_layout {
614 display: flex;
615 gap: 12px;
616 align-items: flex-start;
617}
618
619.chapter_thumbnail img {
620 width: 64px;
621 height: 64px;
622 object-fit: cover;
623 border-radius: 4px;
624 display: block;
625}
626
627.chapter_partial_content {
628 min-width: 0;
629}
630
631
632.inline-image--full {
633 width: 100%;
634 margin: 1rem 0;
635}
636
637.inline-image--half {
638 width: 48%;
639 margin-bottom: 1rem;
640}
641
642.inline-image--left {
643 float: left;
644 margin-right: 1rem;
645}
646
647.inline-image--right {
648 float: right;
649 margin-left: 1rem;
650}