@acms-subir/core 0.3.30 → 0.3.31

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.
@@ -2,6 +2,8 @@
2
2
  import Admin from '../../layouts/Admin.astro';
3
3
  import AiSettings from '../../components/AiSettings';
4
4
  import MonitoringSettings from '../../components/MonitoringSettings';
5
+ import LegalSettings from '../../components/LegalSettings';
6
+ import { LEGAL } from '../../lib/legal/config';
5
7
  import { getRepo } from '../../lib/repo';
6
8
  import { accessFor } from '../../lib/permissions/access';
7
9
  import type { Permission } from '../../lib/permissions/catalog';
@@ -233,6 +235,7 @@ const groups = [
233
235
  { id: 'site', label: 'Title & description', terms: 'site title tagline url footer seo' },
234
236
  { id: 'localization', label: 'Timezone & language', terms: 'timezone locale language date' },
235
237
  { id: 'announcement', label: 'Announcement bar', terms: 'announcement banner bar' },
238
+ ...(can('site.settings') ? [{ id: 'legal', label: 'Legal', terms: 'legal privacy notice policy terms of service aviso de privacidad arco gdpr app store privacy data safety address' }] : []),
236
239
  ] },
237
240
  { label: 'Publishing', items: [
238
241
  ...(can('integrations.manage') ? [{ id: 'drafts-api', label: 'External drafts API', terms: 'api key drafts cors origins' }] : []),
@@ -381,6 +384,16 @@ const groups = [
381
384
  </form>
382
385
  </section>
383
386
 
387
+ {can('site.settings') && (
388
+ <section class="scard" id="legal">
389
+ <header class="scard-head">
390
+ <a class="scard-back" href="#" aria-label="All settings"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 6l-6 6 6 6" /></svg></a>
391
+ <div class="grow"><h2>Legal</h2><p>{LEGAL.enabled ? 'Your privacy notice and terms (/privacy, /terms): who you are, your own sections, and the answers for the app stores.' : 'The standard privacy and terms pages are off for this site.'}</p></div>
392
+ </header>
393
+ <LegalSettings client:visible />
394
+ </section>
395
+ )}
396
+
384
397
  <div class="set-group-title">Publishing</div>
385
398
 
386
399
  {can('integrations.manage') && (
@@ -0,0 +1,23 @@
1
+ import type { APIRoute } from 'astro';
2
+ import { getRepo } from '../../lib/repo';
3
+ import { ApiError, apiError, json, readJson } from '../../lib/api';
4
+ import { legalAdminState, saveLegal } from '../../lib/legal/admin';
5
+ import { requirePermission } from '../../lib/permissions/access';
6
+
7
+ // Settings → Legal (General settings permission, this site's admin only).
8
+ export const GET: APIRoute = async ({ request, cookies, locals, url }) => {
9
+ try {
10
+ const repo = await getRepo(locals);
11
+ await requirePermission(request, cookies, repo, 'site.settings');
12
+ return json(await legalAdminState(repo, url, locals));
13
+ } catch (e) { return apiError(e); }
14
+ };
15
+ export const POST: APIRoute = async ({ request, cookies, locals, url }) => {
16
+ try {
17
+ const repo = await getRepo(locals);
18
+ await requirePermission(request, cookies, repo, 'site.settings');
19
+ if (request.headers.get('origin') !== url.origin) throw new ApiError(403, 'Change this from this site’s admin.');
20
+ await saveLegal(repo, await readJson(request, 200_000));
21
+ return json(await legalAdminState(repo, url, locals));
22
+ } catch (e) { return apiError(e); }
23
+ };
@@ -0,0 +1,23 @@
1
+ /* Settings → Legal */
2
+ .lg { display: grid; gap: 20px; }
3
+ .lg-block { display: grid; gap: 10px; }
4
+ .lg-block h3 { margin: 0; font-size: 14px; }
5
+ .lg-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 10px 16px; }
6
+ .lg-wide { grid-column: 1 / -1; }
7
+ .lg-warn { margin: 0; padding: 10px 12px 10px 28px; border: 1px solid var(--line); border-radius: 8px; background: var(--soft); font-size: 13px; display: grid; gap: 4px; }
8
+ .lg-links { display: flex; flex-wrap: wrap; gap: 6px 16px; align-items: baseline; margin: 0; }
9
+ .lg-section { display: grid; gap: 8px; margin: 0; padding: 12px; border: 1px solid var(--line); border-radius: 8px; }
10
+ .lg-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
11
+ .lg-title { flex: 1 1 220px; }
12
+ .lg-section textarea, .lg-tr input, .lg-tr textarea { width: 100%; }
13
+ .lg-tr { display: grid; gap: 6px; }
14
+ .lg-tr summary { cursor: pointer; font-size: 13px; color: var(--muted); }
15
+ .lg-tr[open] { gap: 6px; }
16
+ .lg-tr[open] > * + * { margin-top: 6px; }
17
+ .lg-table { display: grid; border: 1px solid var(--line); border-radius: 8px; overflow: hidden; font-size: 13px; }
18
+ .lg-table > div { display: grid; grid-template-columns: minmax(140px, 1fr) 2fr 2fr; gap: 12px; padding: 10px 12px; border-top: 1px solid var(--line); }
19
+ .lg-table > div:first-child { border-top: 0; }
20
+ .lg-table small { display: block; margin-top: 2px; }
21
+ .lg-th { background: var(--soft); font-weight: 600; }
22
+ .lg-notes { margin: 0; padding-left: 18px; display: grid; gap: 4px; font-size: 13px; }
23
+ @media (max-width: 720px) { .lg-table > div { grid-template-columns: 1fr; gap: 4px; } }
package/src/virtual.d.ts CHANGED
@@ -18,7 +18,7 @@ declare module 'virtual:acms-config' {
18
18
  search?: { enabled: boolean };
19
19
  // resolved by integration.mjs; '' = pick from the environment (lib/maps/config.ts)
20
20
  maps?: { provider: '' | 'geoapify' | 'google' | 'mapbox' | 'locationiq' | 'stadia' | 'photon' | 'nominatim' | 'pelias' };
21
- legal?: { enabled: boolean; operatorName: string; contactEmail: string; updatedAt: string };
21
+ legal?: { enabled: boolean; operatorName: string; contactEmail: string; address: string; country: string; updatedAt: string };
22
22
  // resolved by integration.mjs (lib/roles.ts and lib/permissions/catalog.ts read them)
23
23
  roles?: { key: string; label: string; summary: string; admin: boolean; home: string }[];
24
24
  permissions?: { key: string; label: string; description: string; defaults: string[]; sensitive: boolean }[];