source: Klonkt/src/views/pages/admin-seo.ejs@ 02c6231

main
Last change on this file since 02c6231 was 3b4095f, checked in by roboburr <roboburr@…>, 2 months ago

feat(seo): og:image light/dark override setting

The auto-generated share card followed the site's default theme (1.2.0); Admin →
SEO now has an explicit override: Auto (follow site theme) / Light / Dark.

  • src/config/database.js — sites.og_theme column (NULL = auto).
  • src/services/OgImageService.js — og_theme wins over theme_override when set.
  • src/routes/og.js — select og_theme for the card route.
  • src/routes/admin-seo.js — save og_theme (validated to light/dark, else auto).
  • src/views/pages/admin-seo.ejs — select under the share-image field.
  • src/services/i18n.js — aseo.og_theme* (nl/en/de).
  • CHANGELOG(.nl/.de).md — under Added.

Closes prutfolio-src-krm.

Co-Authored-By: Claude <noreply@…>

  • Property mode set to 100644
File size: 8.5 KB
RevLine 
[6623453]1<div class="container admin-site-edit-page">
[bbf9d1a]2 <p><a href="/admin" class="btn">&larr; <%= t('aseo.back') %></a></p>
3 <h1><%= t('aseo.title') %></h1>
4 <p class="admin-tagline"><%= t('aseo.tagline_pre') %> <strong><%= site.title %></strong> <%= t('aseo.tagline_post') %></p>
[6623453]5
6 <% if (typeof success !== 'undefined' && success) { %><div class="audio-flash audio-flash--ok"><%= success %></div><% } %>
7 <% if (typeof error !== 'undefined' && error) { %><div class="audio-flash audio-flash--err"><%= error %></div><% } %>
8
9 <form method="post" action="/admin/seo" class="site-form">
10
11 <fieldset>
[bbf9d1a]12 <legend><%= t('aseo.index_legend') %></legend>
[03af7f8]13 <label class="cb">
[6623453]14 <input type="checkbox" name="robots_index" value="1" <%= site.robots_index ? 'checked' : '' %>>
[bbf9d1a]15 <span><%= t('aseo.index_label') %> <small class="form-hint-inline">— <%= t('aseo.index_hint_pre') %> <code>noindex</code> <%= t('aseo.index_hint_post') %></small></span>
[6623453]16 </label>
17 </fieldset>
18
19 <fieldset>
[bbf9d1a]20 <legend><%= t('aseo.title_legend') %></legend>
[6623453]21 <label>
[bbf9d1a]22 <span><%= t('aseo.title_template') %> <small class="form-hint-inline">— <%= t('aseo.title_template_hint_pre') %> <code>{title}</code> <%= t('aseo.title_template_hint_and') %> <code>{site}</code></small></span>
[6623453]23 <input type="text" name="title_template" value="<%= site.title_template || '{title} — {site}' %>" maxlength="200" placeholder="{title} — {site}">
24 </label>
25 <label>
[bbf9d1a]26 <span><%= t('aseo.default_desc') %> <small class="form-hint-inline">— <%= t('aseo.default_desc_hint') %></small></span>
27 <textarea name="default_description" rows="2" maxlength="500" placeholder="<%= t('aseo.default_desc_ph') %>"><%= site.default_description || '' %></textarea>
[6623453]28 </label>
29 <label>
[bbf9d1a]30 <span><%= t('aseo.canonical') %> <small class="form-hint-inline">— <%= t('aseo.canonical_hint') %></small></span>
[1ff0043]31 <input type="text" name="canonical" value="<%= site.canonical || '' %>" placeholder="https://yourdomain.com" maxlength="200">
[6623453]32 </label>
33 <label>
[bbf9d1a]34 <span><%= t('aseo.author') %> <small class="form-hint-inline">— <%= t('aseo.author_hint') %></small></span>
35 <input type="text" name="author" value="<%= site.author || '' %>" maxlength="120" placeholder="<%= t('aseo.author_ph') %>">
[6623453]36 </label>
37 </fieldset>
38
39 <fieldset>
[bbf9d1a]40 <legend><%= t('aseo.social_legend') %></legend>
[6623453]41 <label>
[bbf9d1a]42 <span><%= t('aseo.og_image') %> <small class="form-hint-inline">— <%= t('aseo.og_image_hint') %></small></span>
[1ff0043]43 <input type="text" name="og_image_default" value="<%= site.og_image_default || '' %>" placeholder="https://yourdomain.com/share.jpg" maxlength="500">
[6623453]44 </label>
[3b4095f]45 <label>
46 <span><%= t('aseo.og_theme') %> <small class="form-hint-inline">— <%= t('aseo.og_theme_hint') %></small></span>
47 <select name="og_theme">
48 <option value="" <%= !site.og_theme ? 'selected' : '' %>><%= t('aseo.og_theme_auto') %></option>
49 <option value="light" <%= site.og_theme === 'light' ? 'selected' : '' %>><%= t('aseo.og_theme_light') %></option>
50 <option value="dark" <%= site.og_theme === 'dark' ? 'selected' : '' %>><%= t('aseo.og_theme_dark') %></option>
51 </select>
52 </label>
[6623453]53 <label>
[bbf9d1a]54 <span><%= t('aseo.og_locale') %> <small class="form-hint-inline">— <%= t('aseo.og_locale_hint_pre') %> <code>nl_NL</code> <%= t('aseo.og_locale_hint_or') %> <code>en_US</code></small></span>
[6623453]55 <input type="text" name="og_locale" value="<%= site.og_locale || '' %>" placeholder="nl_NL" maxlength="32">
56 </label>
57 <label>
[bbf9d1a]58 <span><%= t('aseo.twitter') %> <small class="form-hint-inline">— <%= t('aseo.twitter_hint') %></small></span>
[6623453]59 <input type="text" name="twitter" value="<%= site.twitter || '' %>" placeholder="@jouwnaam" maxlength="64">
60 </label>
61 <label>
[bbf9d1a]62 <span><%= t('aseo.fb_app') %> <small class="form-hint-inline">— <%= t('aseo.fb_app_hint') %></small></span>
[6623453]63 <input type="text" name="facebook_app_id" value="<%= site.facebook_app_id || '' %>" maxlength="64">
64 </label>
65 </fieldset>
66
67 <fieldset>
[bbf9d1a]68 <legend><%= t('aseo.publisher_legend') %></legend>
[6623453]69 <label>
[bbf9d1a]70 <span><%= t('aseo.type') %></span>
[6623453]71 <select name="schema_type">
[bbf9d1a]72 <option value="Person" <%= site.schema_type === 'Organization' ? '' : 'selected' %>><%= t('aseo.type_person') %></option>
73 <option value="Organization" <%= site.schema_type === 'Organization' ? 'selected' : '' %>><%= t('aseo.type_org') %></option>
[6623453]74 </select>
75 </label>
76 <label>
[bbf9d1a]77 <span><%= t('aseo.publisher_name') %> <small class="form-hint-inline">— <%= t('aseo.publisher_name_hint') %></small></span>
[6623453]78 <input type="text" name="publisher_name" value="<%= site.publisher_name || '' %>" maxlength="200">
79 </label>
80 <label>
[bbf9d1a]81 <span><%= t('aseo.publisher_url') %></span>
[1ff0043]82 <input type="text" name="publisher_url" value="<%= site.publisher_url || '' %>" placeholder="https://yourdomain.com" maxlength="200">
[6623453]83 </label>
84 <label>
[bbf9d1a]85 <span><%= t('aseo.publisher_logo') %></span>
[1ff0043]86 <input type="text" name="publisher_logo" value="<%= site.publisher_logo || '' %>" placeholder="https://yourdomain.com/logo.png" maxlength="500">
[6623453]87 </label>
88 </fieldset>
89
90 <fieldset>
[bbf9d1a]91 <legend><%= t('aseo.verify_legend') %></legend>
[6623453]92 <label>
[bbf9d1a]93 <span><%= t('aseo.verify_google') %></span>
[6623453]94 <input type="text" name="google_verification" value="<%= site.google_verification || '' %>" maxlength="200">
95 </label>
96 <label>
[bbf9d1a]97 <span><%= t('aseo.verify_bing') %> <small class="form-hint-inline">— <%= t('aseo.verify_bing_hint') %></small></span>
[6623453]98 <input type="text" name="bing_verification" value="<%= site.bing_verification || '' %>" maxlength="200">
99 </label>
100 <label>
[bbf9d1a]101 <span><%= t('aseo.verify_pinterest') %> <small class="form-hint-inline">— <%= t('aseo.verify_pinterest_hint') %></small></span>
[6623453]102 <input type="text" name="pinterest_verification" value="<%= site.pinterest_verification || '' %>" maxlength="200">
103 </label>
104 <label>
[bbf9d1a]105 <span><%= t('aseo.verify_yandex') %></span>
[6623453]106 <input type="text" name="yandex_verification" value="<%= site.yandex_verification || '' %>" maxlength="200">
107 </label>
108 </fieldset>
109
[bbf9d1a]110 <button type="submit" class="btn btn-primary"><%= t('aseo.save') %></button>
[6623453]111 </form>
112</div>
[03af7f8]113
114<style>
115.admin-site-edit-page { max-width: 760px; margin: 3rem auto; padding: 0 1rem; }
116.admin-site-edit-page h1 { font-family: var(--font-display, serif); font-size: 1.8rem; margin: 0 0 0.4rem; }
117.admin-site-edit-page .admin-tagline { color: var(--ink-muted); margin: 0 0 1.75rem; }
118
[75c6919]119.site-form { display: flex; flex-direction: column; gap: 1.5rem; min-width: 0; }
[834bcc3]120/* <fieldset> does not shrink because the UA sets min-inline-size:min-content → mobile overflow.
121 min-width:0 forces it to shrink. */
[75c6919]122.site-form fieldset { min-width: 0; }
123.site-form input, .site-form textarea, .site-form select { min-width: 0; }
[03af7f8]124.site-form fieldset {
125 border: 1px solid var(--rule);
126 border-radius: 8px;
127 padding: 1rem 1.25rem;
128 background: var(--paper-2);
129 display: flex;
130 flex-direction: column;
131 gap: 0.85rem;
132}
133.site-form fieldset legend { font-family: var(--font-display, serif); font-size: 1rem; padding: 0 0.4rem; }
134.site-form label { display: flex; flex-direction: column; gap: 0.3rem; font-size: 0.85rem; color: var(--ink-muted, var(--ink-soft)); }
135.site-form label.cb { flex-direction: row; align-items: flex-start; gap: 0.55rem; font-size: 0.9rem; color: var(--ink); }
136.site-form label.cb input { margin-top: 0.15rem; }
137.site-form label > span { line-height: 1.35; }
138.form-hint-inline { font-weight: 400; color: var(--ink-muted); font-size: 0.82em; }
139.site-form code { background: var(--paper); padding: 0.05rem 0.35rem; border-radius: 3px; font-size: 0.85em; }
140.site-form input[type="text"], .site-form textarea, .site-form select {
141 padding: 0.55rem 0.85rem;
142 border: 1px solid var(--rule);
143 border-radius: 5px;
144 background: var(--paper);
145 color: var(--ink);
146 font-family: inherit;
147 font-size: 0.95rem;
148 width: 100%;
149 box-sizing: border-box;
150}
151.site-form textarea { resize: vertical; min-height: 2.6rem; }
152.site-form select { max-width: 320px; }
153.site-form input:focus, .site-form textarea:focus, .site-form select:focus {
154 outline: none; border-color: var(--accent);
155}
156.seo-pointer p { margin: 0; font-size: 0.9rem; color: var(--ink-muted); }
157.seo-pointer a { color: var(--accent); font-weight: 600; }
158.site-form > button[type="submit"] { align-self: flex-start; }
159</style>
Note: See TracBrowser for help on using the repository browser.