@commonpub/layer 0.23.1 → 0.23.3
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.
|
@@ -419,13 +419,31 @@ useJsonLd({
|
|
|
419
419
|
font-weight: 400;
|
|
420
420
|
}
|
|
421
421
|
|
|
422
|
-
/* ── AVATARS ──
|
|
422
|
+
/* ── AVATARS ──
|
|
423
|
+
* Two render modes share the .cpub-av class:
|
|
424
|
+
* <img class="cpub-av cpub-av-lg" ...> ← avatar photo
|
|
425
|
+
* <div class="cpub-av cpub-av-lg">JD</div> ← initials fallback when no avatar
|
|
426
|
+
*
|
|
427
|
+
* Sizing + border-radius is shared. But `display: flex` MUST NOT apply to
|
|
428
|
+
* the <img> — when a replaced element gets `display: flex` set, browsers
|
|
429
|
+
* (notably Chromium) treat the img content render-box inconsistently and
|
|
430
|
+
* the inline `object-fit: cover` is silently dropped, producing a squished
|
|
431
|
+
* (stretched-to-box) image instead of a center-cropped one. Visible on
|
|
432
|
+
* deveco.io blog pages where author avatars are vertical photos (e.g.
|
|
433
|
+
* 816×1456) rendered into a 44×44 square.
|
|
434
|
+
*
|
|
435
|
+
* Fix: scope display:flex centering to the div variant only.
|
|
436
|
+
*/
|
|
423
437
|
.cpub-av {
|
|
424
438
|
width: 28px;
|
|
425
439
|
height: 28px;
|
|
426
440
|
border-radius: 50%;
|
|
427
441
|
background: var(--surface3);
|
|
428
442
|
border: var(--border-width-default) solid var(--border);
|
|
443
|
+
flex-shrink: 0;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
div.cpub-av {
|
|
429
447
|
display: flex;
|
|
430
448
|
align-items: center;
|
|
431
449
|
justify-content: center;
|
|
@@ -433,7 +451,12 @@ useJsonLd({
|
|
|
433
451
|
font-weight: 600;
|
|
434
452
|
color: var(--text-dim);
|
|
435
453
|
font-family: var(--font-mono);
|
|
436
|
-
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/* Defensive: even when consumers forget the inline `object-fit:cover`,
|
|
457
|
+
img.cpub-av crops instead of stretching. */
|
|
458
|
+
img.cpub-av {
|
|
459
|
+
object-fit: cover;
|
|
437
460
|
}
|
|
438
461
|
|
|
439
462
|
.cpub-av-lg { width: 44px; height: 44px; font-size: 14px; }
|
|
@@ -763,12 +763,19 @@ async function handleBuild(): Promise<void> {
|
|
|
763
763
|
flex-wrap: wrap;
|
|
764
764
|
}
|
|
765
765
|
|
|
766
|
+
/* See ArticleView.vue's .cpub-av comment for why display:flex is scoped
|
|
767
|
+
* to the div-variant only — stops img-variant from squishing portrait
|
|
768
|
+
* avatars (object-fit:cover gets dropped on flex-set replaced elements). */
|
|
766
769
|
.cpub-av {
|
|
767
770
|
width: 28px;
|
|
768
771
|
height: 28px;
|
|
769
772
|
border-radius: 50%;
|
|
770
773
|
background: var(--surface3);
|
|
771
774
|
border: var(--border-width-default) solid var(--border);
|
|
775
|
+
flex-shrink: 0;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
div.cpub-av {
|
|
772
779
|
display: flex;
|
|
773
780
|
align-items: center;
|
|
774
781
|
justify-content: center;
|
|
@@ -776,7 +783,10 @@ async function handleBuild(): Promise<void> {
|
|
|
776
783
|
font-weight: 700;
|
|
777
784
|
color: var(--text-dim);
|
|
778
785
|
font-family: var(--font-mono);
|
|
779
|
-
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
img.cpub-av {
|
|
789
|
+
object-fit: cover;
|
|
780
790
|
}
|
|
781
791
|
|
|
782
792
|
.cpub-av-lg { width: 36px; height: 36px; font-size: 12px; }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@commonpub/layer",
|
|
3
|
-
"version": "0.23.
|
|
3
|
+
"version": "0.23.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./nuxt.config.ts",
|
|
6
6
|
"files": [
|
|
@@ -51,16 +51,16 @@
|
|
|
51
51
|
"vue": "^3.4.0",
|
|
52
52
|
"vue-router": "^4.3.0",
|
|
53
53
|
"zod": "^4.3.6",
|
|
54
|
-
"@commonpub/auth": "0.6.0",
|
|
55
54
|
"@commonpub/config": "0.15.0",
|
|
55
|
+
"@commonpub/docs": "0.6.3",
|
|
56
|
+
"@commonpub/learning": "0.5.2",
|
|
56
57
|
"@commonpub/editor": "0.7.11",
|
|
57
|
-
"@commonpub/explainer": "0.7.15",
|
|
58
58
|
"@commonpub/protocol": "0.12.0",
|
|
59
|
-
"@commonpub/server": "2.57.0",
|
|
60
59
|
"@commonpub/schema": "0.17.0",
|
|
61
|
-
"@commonpub/
|
|
60
|
+
"@commonpub/server": "2.57.0",
|
|
62
61
|
"@commonpub/ui": "0.9.0",
|
|
63
|
-
"@commonpub/
|
|
62
|
+
"@commonpub/auth": "0.6.0",
|
|
63
|
+
"@commonpub/explainer": "0.7.15"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
66
|
"@testing-library/jest-dom": "^6.9.1",
|
package/pages/index.vue
CHANGED
|
@@ -14,9 +14,22 @@ const sortedSections = computed(() =>
|
|
|
14
14
|
);
|
|
15
15
|
|
|
16
16
|
const { user: authUser } = useAuth();
|
|
17
|
-
const { hubs: hubsEnabled, contests: contestsEnabled, learning: learningEnabled, video: videoEnabled, docs: docsEnabled, editorial: editorialEnabled, layoutEngine:
|
|
17
|
+
const { hubs: hubsEnabled, contests: contestsEnabled, learning: learningEnabled, video: videoEnabled, docs: docsEnabled, editorial: editorialEnabled, layoutEngine: layoutEngineFlag } = useFeatures();
|
|
18
18
|
const { enabledTypeMeta } = useContentTypes();
|
|
19
19
|
|
|
20
|
+
// Layout engine path — only active when BOTH the flag is on AND a layout
|
|
21
|
+
// actually exists in the DB for this route. Prevents the "operator enables
|
|
22
|
+
// the flag without seeding a homepage layout → page goes blank" trap
|
|
23
|
+
// (reported by user, session 158 follow-up). When the flag's on but
|
|
24
|
+
// useLayout returns null (feature off OR no published layout for route),
|
|
25
|
+
// we fall through to the configurable/legacy render paths so the user
|
|
26
|
+
// still sees content. Admin can call POST /api/admin/layouts/seed-homepage
|
|
27
|
+
// to populate a default and start using the layout engine for real.
|
|
28
|
+
const { layout: homepageLayout } = useLayout('/');
|
|
29
|
+
const layoutEngineActive = computed(
|
|
30
|
+
() => layoutEngineFlag.value && homepageLayout.value !== null,
|
|
31
|
+
);
|
|
32
|
+
|
|
20
33
|
const activeTab = ref(authUser.value ? 'foryou' : 'latest');
|
|
21
34
|
const tabs = computed(() => [
|
|
22
35
|
{ value: 'foryou', label: 'For You', icon: 'fa-solid fa-sparkles' },
|
|
@@ -144,15 +157,16 @@ async function handleHubJoin(hubSlug: string): Promise<void> {
|
|
|
144
157
|
<template>
|
|
145
158
|
<div>
|
|
146
159
|
<!-- ═══ LAYOUT ENGINE (Phase 1c — feature-flagged) ═══
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
160
|
+
Renders DB-driven layout via <LayoutSlot> zones ONLY when BOTH
|
|
161
|
+
(a) features.layoutEngine is ON AND (b) a layout actually exists
|
|
162
|
+
at scope ('route', '/'). Falls through to the configurable or
|
|
163
|
+
legacy renderer otherwise — including when the flag's ON but
|
|
164
|
+
no layout has been seeded yet (the "blank page" trap reported
|
|
165
|
+
in session 158 follow-up).
|
|
166
|
+
|
|
167
|
+
To enable for real: POST /api/admin/layouts/seed-homepage,
|
|
168
|
+
then flip the flag. See docs/reference/guides/layout-engine.md. -->
|
|
169
|
+
<template v-if="layoutEngineActive">
|
|
156
170
|
<LayoutSlot route="/" zone="full-width" />
|
|
157
171
|
<div class="cpub-main-layout">
|
|
158
172
|
<main class="cpub-feed-col">
|
|
@@ -37,13 +37,15 @@ export default defineEventHandler(async (event) => {
|
|
|
37
37
|
|
|
38
38
|
const merged = { ...existing, ...body.overrides };
|
|
39
39
|
|
|
40
|
-
//
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
40
|
+
// NOTE: previously this block tried to "remove overrides that match the
|
|
41
|
+
// base config" as a dedup, but `config.features` is the EFFECTIVE config
|
|
42
|
+
// (with overrides ALREADY applied) — so re-saving a previously-overridden
|
|
43
|
+
// flag would see `base[key] === value` (because the override was applied
|
|
44
|
+
// to base) and delete the override. The flag would then revert to the
|
|
45
|
+
// build-time default on next read. User-visible symptom: "I flipped X on
|
|
46
|
+
// in the UI but it kept reverting off." The dedup is dropped — the user's
|
|
47
|
+
// explicit override is persisted verbatim. Future "reset to default" can
|
|
48
|
+
// be a separate DELETE-overrides handler.
|
|
47
49
|
|
|
48
50
|
await setInstanceSetting(db, 'features.overrides', merged, user.id, getRequestIP(event) ?? undefined);
|
|
49
51
|
|