The CSS pay-down: 72 name families derived or dismissed with the consumer map in hand (milestone 302 step 4) #128
@@ -330,3 +330,24 @@
|
||||
.fs-input::placeholder { color: var(--fs-text-tertiary); }
|
||||
.fs-input:focus { outline: none; box-shadow: var(--fs-focus-ring); }
|
||||
.fs-input:disabled { opacity: var(--fs-disabled-opacity); cursor: not-allowed; }
|
||||
|
||||
/* Page scaffold + feedback text recipes (milestone 302, note 2917): name
|
||||
families the consumer map showed to be one recipe living in many views.
|
||||
A view keeps only its deviation as a scoped remainder/override. */
|
||||
.page-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.page-header h1 { margin: 0; }
|
||||
|
||||
.error-msg { color: var(--fs-error); font-size: 0.9rem; }
|
||||
.state-msg { color: var(--fs-text-tertiary); font-size: 0.9rem; }
|
||||
.empty-msg { color: var(--fs-text-tertiary); font-size: 0.875rem; }
|
||||
|
||||
.empty-title { font-size: 1rem; font-weight: 500; color: var(--fs-text-secondary); margin: 0 0 0.35rem; }
|
||||
.empty-sub { font-size: 0.85rem; color: var(--fs-text-tertiary); margin: 0 0 1rem; }
|
||||
|
||||
.required { color: var(--fs-error); }
|
||||
.field-hint { margin: 0.3rem 0 0; font-size: 0.8rem; color: var(--fs-text-tertiary); }
|
||||
|
||||
@@ -12,3 +12,4 @@
|
||||
font-style: italic;
|
||||
margin: 0 0 0.5rem 0;
|
||||
}
|
||||
.form-buttons { display: flex; gap: 0.5rem; }
|
||||
|
||||
@@ -185,5 +185,4 @@ onMounted(load);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.inception-actions { display: flex; justify-content: flex-end; margin-top: 0.5rem; }
|
||||
.error-msg { color: var(--fs-error); font-size: 0.9rem; }
|
||||
</style>
|
||||
|
||||
@@ -484,10 +484,10 @@ async function confirmDelete() {
|
||||
border: 1px dashed var(--fs-border-color);
|
||||
border-radius: var(--fs-radius-lg);
|
||||
}
|
||||
.empty-title { margin: 0; font-weight: 500; color: var(--fs-text-primary); }
|
||||
.empty-sub { margin: 0 0 0.5rem; font-size: 0.82rem; color: var(--fs-text-tertiary); max-width: 32ch; }
|
||||
/* remainders over the shared recipes (components.css, m302) */
|
||||
.empty-title { margin: 0; color: var(--fs-text-primary); }
|
||||
.empty-sub { margin: 0 0 0.5rem; font-size: 0.82rem; max-width: 32ch; }
|
||||
|
||||
.error-msg { color: var(--fs-error); font-size: 0.9rem; }
|
||||
|
||||
/* ── Skeleton ─────────────────────────────────────────────────── */
|
||||
@keyframes skel-shine { to { background-position: 200% center; } }
|
||||
|
||||
@@ -145,7 +145,6 @@ li:hover { background: var(--fs-surface-hover); }
|
||||
border: 1px solid var(--fs-border-color); border-radius: 6px;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
.form-buttons { display: flex; gap: 0.5rem; }
|
||||
.subscriptions {
|
||||
margin-top: 2rem;
|
||||
border-top: 1px solid var(--fs-border-color);
|
||||
|
||||
@@ -70,6 +70,5 @@ li:hover { background: var(--fs-surface-hover); }
|
||||
border: 1px solid var(--fs-border-color); border-radius: 6px;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
.form-buttons { display: flex; gap: 0.5rem; }
|
||||
button { cursor: pointer; }
|
||||
</style>
|
||||
|
||||
@@ -557,14 +557,14 @@ function isSelfContainedColour(value: string): boolean {
|
||||
<div class="field">
|
||||
<label class="field-label" for="first-title">Title</label>
|
||||
<input
|
||||
id="first-title" v-model="newTitle" class="input" type="text"
|
||||
id="first-title" v-model="newTitle" class="fs-input input" type="text"
|
||||
placeholder="Your house style" @keyup.enter="submitCreate"
|
||||
/>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="field-label" for="first-desc">Description</label>
|
||||
<input
|
||||
id="first-desc" v-model="newDescription" class="input" type="text"
|
||||
id="first-desc" v-model="newDescription" class="fs-input input" type="text"
|
||||
placeholder="What it covers"
|
||||
/>
|
||||
</div>
|
||||
@@ -612,20 +612,20 @@ function isSelfContainedColour(value: string): boolean {
|
||||
<div class="field">
|
||||
<label class="field-label" for="new-title">Title</label>
|
||||
<input
|
||||
id="new-title" v-model="newTitle" class="input" type="text"
|
||||
id="new-title" v-model="newTitle" class="fs-input input" type="text"
|
||||
placeholder="A house style, or one app in it" @keyup.enter="submitCreate"
|
||||
/>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="field-label" for="new-desc">Description</label>
|
||||
<input
|
||||
id="new-desc" v-model="newDescription" class="input" type="text"
|
||||
id="new-desc" v-model="newDescription" class="fs-input input" type="text"
|
||||
placeholder="What it covers"
|
||||
/>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="field-label" for="new-parent">Inherits from</label>
|
||||
<select id="new-parent" v-model="newParentId" class="input">
|
||||
<select id="new-parent" v-model="newParentId" class="fs-input input">
|
||||
<option :value="null">Nothing — this is a family system</option>
|
||||
<option v-for="s in systems" :key="s.id" :value="s.id">{{ s.title }}</option>
|
||||
</select>
|
||||
@@ -659,16 +659,16 @@ function isSelfContainedColour(value: string): boolean {
|
||||
|
||||
<div class="field">
|
||||
<label class="field-label" for="edit-title">Title</label>
|
||||
<input id="edit-title" v-model="editTitle" class="input" type="text" />
|
||||
<input id="edit-title" v-model="editTitle" class="fs-input input" type="text" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="field-label" for="edit-desc">Description</label>
|
||||
<input id="edit-desc" v-model="editDescription" class="input" type="text" />
|
||||
<input id="edit-desc" v-model="editDescription" class="fs-input input" type="text" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="field-label" for="edit-guidance">Guidance</label>
|
||||
<textarea
|
||||
id="edit-guidance" v-model="editGuidance" class="input" rows="5"
|
||||
id="edit-guidance" v-model="editGuidance" class="fs-input input" rows="5"
|
||||
placeholder="Aesthetic, voice and tone, what's deliberately out of scope…"
|
||||
></textarea>
|
||||
<p class="field-hint">
|
||||
@@ -678,7 +678,7 @@ function isSelfContainedColour(value: string): boolean {
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="field-label" for="edit-parent">Inherits from</label>
|
||||
<select id="edit-parent" v-model="editParentId" class="input">
|
||||
<select id="edit-parent" v-model="editParentId" class="fs-input input">
|
||||
<option :value="null">Nothing — this is a family system</option>
|
||||
<option v-for="s in parentOptions" :key="s.id" :value="s.id">{{ s.title }}</option>
|
||||
</select>
|
||||
@@ -887,19 +887,19 @@ function isSelfContainedColour(value: string): boolean {
|
||||
<div class="field">
|
||||
<label class="field-label" for="token-name">Name</label>
|
||||
<input
|
||||
id="token-name" v-model="tokenName" class="input mono" type="text"
|
||||
id="token-name" v-model="tokenName" class="fs-input input mono" type="text"
|
||||
placeholder="--surface-page"
|
||||
/>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<div class="field">
|
||||
<label class="field-label" for="token-group">Group</label>
|
||||
<input id="token-group" v-model="tokenGroup" class="input" type="text" placeholder="surface" />
|
||||
<input id="token-group" v-model="tokenGroup" class="fs-input input" type="text" placeholder="surface" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="field-label" for="token-purpose">Purpose</label>
|
||||
<input
|
||||
id="token-purpose" v-model="tokenPurpose" class="input" type="text"
|
||||
id="token-purpose" v-model="tokenPurpose" class="fs-input input" type="text"
|
||||
placeholder="page background, deepest surface"
|
||||
/>
|
||||
</div>
|
||||
@@ -908,7 +908,7 @@ function isSelfContainedColour(value: string): boolean {
|
||||
<div class="field">
|
||||
<label class="field-label" for="token-rationale">Why this value</label>
|
||||
<input
|
||||
id="token-rationale" v-model="tokenRationale" class="input" type="text"
|
||||
id="token-rationale" v-model="tokenRationale" class="fs-input input" type="text"
|
||||
placeholder="Matches the primary action colour, deliberately"
|
||||
/>
|
||||
<p class="field-hint">
|
||||
@@ -920,7 +920,7 @@ function isSelfContainedColour(value: string): boolean {
|
||||
<div class="field">
|
||||
<label class="field-label" for="token-supersedes">Use instead of</label>
|
||||
<input
|
||||
id="token-supersedes" v-model="tokenSupersedes" class="input mono" type="text"
|
||||
id="token-supersedes" v-model="tokenSupersedes" class="fs-input input mono" type="text"
|
||||
placeholder="#fff, #ffffff"
|
||||
/>
|
||||
<p class="field-hint">
|
||||
@@ -941,8 +941,8 @@ function isSelfContainedColour(value: string): boolean {
|
||||
</template>
|
||||
</p>
|
||||
<div v-for="(row, i) in tokenModes" :key="i" class="mode-row">
|
||||
<input v-model="row.mode" class="input mono mode-key" type="text" placeholder="base" />
|
||||
<input v-model="row.value" class="input mono" type="text" placeholder="#14171a" />
|
||||
<input v-model="row.mode" class="fs-input input mono mode-key" type="text" placeholder="base" />
|
||||
<input v-model="row.value" class="fs-input input mono" type="text" placeholder="#14171a" />
|
||||
<span
|
||||
v-if="isSelfContainedColour(row.value)" class="swatch"
|
||||
:style="{ background: row.value }" aria-hidden="true"
|
||||
@@ -1287,20 +1287,13 @@ function isSelfContainedColour(value: string): boolean {
|
||||
}
|
||||
|
||||
.field-hint {
|
||||
margin: 0.3rem 0 0;
|
||||
font-size: 0.8rem;
|
||||
color: var(--fs-text-tertiary);
|
||||
line-height: 1.5;
|
||||
line-height: 1.5; /* remainder over the shared recipe */
|
||||
}
|
||||
|
||||
/* remainder over .fs-input (components.css, canon #2336; m302) */
|
||||
.input {
|
||||
width: 100%;
|
||||
padding: 0.45rem 0.6rem;
|
||||
background: var(--fs-surface-page);
|
||||
border: 1px solid var(--fs-border-color);
|
||||
border-radius: var(--fs-radius-sm);
|
||||
color: var(--fs-text-primary);
|
||||
font: inherit;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -336,15 +336,6 @@ function overallPct(project: Project): { total: number; pct: number } {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.page-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.page-header h1 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Moss action-primary per Hybrid — list-view utility action,
|
||||
not a brand moment. Empty-state .empty-action below keeps accent. */
|
||||
@@ -376,20 +367,17 @@ function overallPct(project: Project): { total: number; pct: number } {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.loading-msg,
|
||||
.error-msg {
|
||||
.loading-msg {
|
||||
color: var(--fs-text-tertiary);
|
||||
font-size: 0.9rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
.error-msg {
|
||||
color: var(--fs-error);
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.empty-state-rich { text-align: center; padding: 3rem 1rem; color: var(--fs-text-tertiary); }
|
||||
.empty-icon { font-size: 2.5rem; margin-bottom: 0.75rem; opacity: 0.3; }
|
||||
.empty-title { font-size: 1rem; font-weight: 500; color: var(--fs-text-secondary); margin: 0 0 0.35rem; }
|
||||
.empty-sub { font-size: 0.85rem; margin: 0 0 1rem; }
|
||||
.empty-action { display: inline-block; padding: 0.4rem 1rem; border: 1px solid var(--fs-action-primary); border-radius: var(--fs-radius-sm); color: var(--fs-action-primary); background: none; cursor: pointer; font-size: 0.85rem; transition: background 0.15s, color 0.15s; }
|
||||
.empty-action:hover { background: var(--fs-action-primary); color: var(--fs-text-on-action); }
|
||||
|
||||
@@ -592,9 +580,6 @@ function overallPct(project: Project): { total: number; pct: number } {
|
||||
font-weight: 500;
|
||||
color: var(--fs-text-primary);
|
||||
}
|
||||
.required {
|
||||
color: var(--fs-error);
|
||||
}
|
||||
.modal-input,
|
||||
.modal-textarea {
|
||||
padding: 0.45rem 0.7rem;
|
||||
|
||||
@@ -1203,10 +1203,7 @@ async function confirmDelete() {
|
||||
/* ── Layout ─────────────────────────────────────────────────── */
|
||||
/* ── Nav bar ─────────────────────────────────────────────────── */
|
||||
.page-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 1.5rem;
|
||||
margin-bottom: 1.5rem; /* roomier than the shared recipe */
|
||||
}
|
||||
.page-header-actions { display: flex; gap: 0.5rem; align-items: center; }
|
||||
.plan-title-input {
|
||||
@@ -1816,7 +1813,7 @@ async function confirmDelete() {
|
||||
.note-title { font-weight: 500; min-width: 0; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.note-date { font-size: 0.75rem; color: var(--fs-text-tertiary); flex-shrink: 0; }
|
||||
|
||||
.empty-msg { color: var(--fs-text-tertiary); font-size: 0.875rem; text-align: center; padding: 1rem; }
|
||||
.empty-msg { text-align: center; padding: 1rem; } /* remainder over the shared recipe */
|
||||
/* Deliberately NOT styled like .empty-msg: "no tasks" and "the tasks did not
|
||||
load" look identical to a user, and conflating them is what let a silent
|
||||
failure read as an empty project. */
|
||||
|
||||
@@ -1236,7 +1236,7 @@ async function deleteUser(userId: number) {
|
||||
id="user-timezone"
|
||||
v-model="userTimezone"
|
||||
type="text"
|
||||
class="input"
|
||||
class="fs-input input"
|
||||
placeholder="e.g. America/New_York"
|
||||
/>
|
||||
<button class="btn-secondary" type="button" @click="detectTimezone">Detect</button>
|
||||
@@ -1263,7 +1263,7 @@ async function deleteUser(userId: number) {
|
||||
type="number"
|
||||
min="0"
|
||||
step="1"
|
||||
class="input"
|
||||
class="fs-input input"
|
||||
style="max-width: 8rem"
|
||||
/>
|
||||
<p class="field-hint">Set to <strong>0</strong> to keep deleted items forever (never auto-purge).</p>
|
||||
@@ -1301,7 +1301,7 @@ async function deleteUser(userId: number) {
|
||||
min="0"
|
||||
max="1"
|
||||
step="0.05"
|
||||
class="input"
|
||||
class="fs-input input"
|
||||
style="max-width: 8rem"
|
||||
/>
|
||||
<p class="field-hint">Minimum similarity to surface a note. Higher = stricter (fewer, more certain). Deliberately above the 0.45 used for searches you trigger yourself.</p>
|
||||
@@ -1315,7 +1315,7 @@ async function deleteUser(userId: number) {
|
||||
min="1"
|
||||
max="10"
|
||||
step="1"
|
||||
class="input"
|
||||
class="fs-input input"
|
||||
style="max-width: 8rem"
|
||||
/>
|
||||
<p class="field-hint">Ceiling on titles surfaced at once (1–10).</p>
|
||||
@@ -1345,7 +1345,7 @@ async function deleteUser(userId: number) {
|
||||
min="0"
|
||||
max="1"
|
||||
step="0.01"
|
||||
class="input"
|
||||
class="fs-input input"
|
||||
style="max-width: 8rem"
|
||||
/>
|
||||
<p class="field-hint">
|
||||
@@ -1374,7 +1374,7 @@ async function deleteUser(userId: number) {
|
||||
min="0"
|
||||
max="1"
|
||||
step="0.01"
|
||||
class="input"
|
||||
class="fs-input input"
|
||||
style="max-width: 8rem"
|
||||
/>
|
||||
<p class="field-hint">
|
||||
@@ -1394,7 +1394,7 @@ async function deleteUser(userId: number) {
|
||||
min="0"
|
||||
max="1"
|
||||
step="0.01"
|
||||
class="input"
|
||||
class="fs-input input"
|
||||
style="max-width: 8rem"
|
||||
/>
|
||||
<p class="field-hint">
|
||||
@@ -1415,7 +1415,7 @@ async function deleteUser(userId: number) {
|
||||
min="0"
|
||||
max="1"
|
||||
step="0.01"
|
||||
class="input"
|
||||
class="fs-input input"
|
||||
style="max-width: 8rem"
|
||||
/>
|
||||
<p class="field-hint">
|
||||
@@ -1457,7 +1457,7 @@ async function deleteUser(userId: number) {
|
||||
v-model="newEmail"
|
||||
type="email"
|
||||
placeholder="you@example.com"
|
||||
class="input"
|
||||
class="fs-input input"
|
||||
/>
|
||||
</div>
|
||||
<div class="field">
|
||||
@@ -1467,7 +1467,7 @@ async function deleteUser(userId: number) {
|
||||
v-model="emailPassword"
|
||||
type="password"
|
||||
autocomplete="current-password"
|
||||
class="input"
|
||||
class="fs-input input"
|
||||
/>
|
||||
<p class="field-hint">Required to confirm the change.</p>
|
||||
</div>
|
||||
@@ -1491,7 +1491,7 @@ async function deleteUser(userId: number) {
|
||||
v-model="currentPassword"
|
||||
type="password"
|
||||
autocomplete="current-password"
|
||||
class="input"
|
||||
class="fs-input input"
|
||||
/>
|
||||
</div>
|
||||
<div class="field">
|
||||
@@ -1501,7 +1501,7 @@ async function deleteUser(userId: number) {
|
||||
v-model="newPassword"
|
||||
type="password"
|
||||
autocomplete="new-password"
|
||||
class="input"
|
||||
class="fs-input input"
|
||||
/>
|
||||
<p class="field-hint">Must be at least 8 characters</p>
|
||||
</div>
|
||||
@@ -1512,7 +1512,7 @@ async function deleteUser(userId: number) {
|
||||
v-model="confirmNewPassword"
|
||||
type="password"
|
||||
autocomplete="new-password"
|
||||
class="input"
|
||||
class="fs-input input"
|
||||
:class="{ 'input-error': confirmNewPassword && newPassword !== confirmNewPassword }"
|
||||
/>
|
||||
<p v-if="confirmNewPassword && newPassword !== confirmNewPassword" class="error-hint">
|
||||
@@ -1555,20 +1555,20 @@ async function deleteUser(userId: number) {
|
||||
<div class="assistant-grid">
|
||||
<div class="field">
|
||||
<label>Display Name</label>
|
||||
<input v-model="profile.display_name" type="text" class="input" placeholder="e.g. Alex" />
|
||||
<input v-model="profile.display_name" type="text" class="fs-input input" placeholder="e.g. Alex" />
|
||||
<p class="field-hint">How the assistant addresses you.</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Job Title</label>
|
||||
<input v-model="profile.job_title" type="text" class="input" placeholder="e.g. Product Manager" />
|
||||
<input v-model="profile.job_title" type="text" class="fs-input input" placeholder="e.g. Product Manager" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Industry</label>
|
||||
<input v-model="profile.industry" type="text" class="input" placeholder="e.g. Technology" />
|
||||
<input v-model="profile.industry" type="text" class="fs-input input" placeholder="e.g. Technology" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Expertise Level</label>
|
||||
<select v-model="profile.expertise_level" class="input">
|
||||
<select v-model="profile.expertise_level" class="fs-input input">
|
||||
<option value="novice">Novice — explain things simply</option>
|
||||
<option value="intermediate">Intermediate — balanced explanations</option>
|
||||
<option value="expert">Expert — assume deep knowledge</option>
|
||||
@@ -1587,7 +1587,7 @@ async function deleteUser(userId: number) {
|
||||
<div class="assistant-grid">
|
||||
<div class="field">
|
||||
<label>Response Style</label>
|
||||
<select v-model="profile.response_style" class="input">
|
||||
<select v-model="profile.response_style" class="fs-input input">
|
||||
<option value="concise">Concise — short and direct</option>
|
||||
<option value="balanced">Balanced — default</option>
|
||||
<option value="detailed">Detailed — thorough explanations</option>
|
||||
@@ -1595,7 +1595,7 @@ async function deleteUser(userId: number) {
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Tone</label>
|
||||
<select v-model="profile.tone" class="input">
|
||||
<select v-model="profile.tone" class="fs-input input">
|
||||
<option value="casual">Casual — friendly and relaxed</option>
|
||||
<option value="professional">Professional — formal and precise</option>
|
||||
<option value="technical">Technical — jargon-friendly</option>
|
||||
@@ -1637,11 +1637,11 @@ async function deleteUser(userId: number) {
|
||||
<div class="assistant-grid" style="margin-top:0.75rem">
|
||||
<div class="field">
|
||||
<label>Start Time</label>
|
||||
<input v-model="profile.work_schedule.start" type="time" class="input" />
|
||||
<input v-model="profile.work_schedule.start" type="time" class="fs-input input" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>End Time</label>
|
||||
<input v-model="profile.work_schedule.end" type="time" class="input" />
|
||||
<input v-model="profile.work_schedule.end" type="time" class="fs-input input" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
@@ -1697,7 +1697,7 @@ async function deleteUser(userId: number) {
|
||||
<input
|
||||
v-model="searchQuery"
|
||||
type="text"
|
||||
class="input"
|
||||
class="fs-input input"
|
||||
placeholder="Enter a search query..."
|
||||
@keydown="onSearchKeydown"
|
||||
/>
|
||||
@@ -1763,17 +1763,17 @@ async function deleteUser(userId: number) {
|
||||
<div v-if="connFormOpen" class="smtp-grid">
|
||||
<div class="field">
|
||||
<label for="conn-kind">Forge</label>
|
||||
<select id="conn-kind" v-model="connForm.kind" class="input">
|
||||
<select id="conn-kind" v-model="connForm.kind" class="fs-input input">
|
||||
<option v-for="k in forgeKinds" :key="k" :value="k">{{ k }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="conn-base-url">Base URL</label>
|
||||
<input id="conn-base-url" v-model="connForm.base_url" type="text" placeholder="https://git.example.com" class="input" />
|
||||
<input id="conn-base-url" v-model="connForm.base_url" type="text" placeholder="https://git.example.com" class="fs-input input" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="conn-token">API Token (read scope)</label>
|
||||
<input id="conn-token" v-model="connForm.token" type="password" class="input" />
|
||||
<input id="conn-token" v-model="connForm.token" type="password" class="fs-input input" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
@@ -2063,7 +2063,7 @@ async function deleteUser(userId: number) {
|
||||
v-model="baseUrl"
|
||||
type="url"
|
||||
placeholder="https://notes.example.com"
|
||||
class="input"
|
||||
class="fs-input input"
|
||||
/>
|
||||
</div>
|
||||
<div class="actions">
|
||||
@@ -2088,7 +2088,7 @@ async function deleteUser(userId: number) {
|
||||
v-model="adminMarketplaceUrl"
|
||||
type="url"
|
||||
placeholder="https://git.example.com/you/Scribe.git"
|
||||
class="input"
|
||||
class="fs-input input"
|
||||
/>
|
||||
</div>
|
||||
<div class="actions">
|
||||
@@ -2115,7 +2115,7 @@ async function deleteUser(userId: number) {
|
||||
</div>
|
||||
<div class="field url-field">
|
||||
<label for="db-maint-hour">Run hour (UTC)</label>
|
||||
<select id="db-maint-hour" v-model.number="dbMaintHour" class="input">
|
||||
<select id="db-maint-hour" v-model.number="dbMaintHour" class="fs-input input">
|
||||
<option v-for="h in 24" :key="h - 1" :value="h - 1">
|
||||
{{ String(h - 1).padStart(2, '0') }}:00
|
||||
</option>
|
||||
@@ -2185,27 +2185,27 @@ async function deleteUser(userId: number) {
|
||||
<div class="smtp-grid">
|
||||
<div class="field">
|
||||
<label for="smtp-host">SMTP Host</label>
|
||||
<input id="smtp-host" v-model="smtp.smtp_host" type="text" placeholder="smtp.example.com" class="input" />
|
||||
<input id="smtp-host" v-model="smtp.smtp_host" type="text" placeholder="smtp.example.com" class="fs-input input" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="smtp-port">Port</label>
|
||||
<input id="smtp-port" v-model="smtp.smtp_port" type="text" placeholder="587" class="input" />
|
||||
<input id="smtp-port" v-model="smtp.smtp_port" type="text" placeholder="587" class="fs-input input" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="smtp-username">Username</label>
|
||||
<input id="smtp-username" v-model="smtp.smtp_username" type="text" class="input" />
|
||||
<input id="smtp-username" v-model="smtp.smtp_username" type="text" class="fs-input input" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="smtp-password">Password</label>
|
||||
<input id="smtp-password" v-model="smtp.smtp_password" type="password" class="input" />
|
||||
<input id="smtp-password" v-model="smtp.smtp_password" type="password" class="fs-input input" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="smtp-from-address">From Address</label>
|
||||
<input id="smtp-from-address" v-model="smtp.smtp_from_address" type="email" placeholder="noreply@example.com" class="input" />
|
||||
<input id="smtp-from-address" v-model="smtp.smtp_from_address" type="email" placeholder="noreply@example.com" class="fs-input input" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="smtp-from-name">From Name</label>
|
||||
<input id="smtp-from-name" v-model="smtp.smtp_from_name" type="text" placeholder="Fabled Scribe" class="input" />
|
||||
<input id="smtp-from-name" v-model="smtp.smtp_from_name" type="text" placeholder="Fabled Scribe" class="fs-input input" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="checkbox-field">
|
||||
@@ -2228,7 +2228,7 @@ async function deleteUser(userId: number) {
|
||||
v-model="testRecipient"
|
||||
type="email"
|
||||
placeholder="test@example.com"
|
||||
class="input"
|
||||
class="fs-input input"
|
||||
/>
|
||||
<button class="btn-primary" @click="sendTestEmail" :disabled="sendingTest || !testRecipient.trim()">
|
||||
{{ sendingTest ? "Sending..." : "Send Test" }}
|
||||
@@ -2249,7 +2249,7 @@ async function deleteUser(userId: number) {
|
||||
<div class="smtp-grid">
|
||||
<div class="field">
|
||||
<label for="forge-webhook-secret">Webhook Secret</label>
|
||||
<input id="forge-webhook-secret" v-model="forgeWebhookSecret" type="password" class="input" />
|
||||
<input id="forge-webhook-secret" v-model="forgeWebhookSecret" type="password" class="fs-input input" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
@@ -2295,7 +2295,7 @@ async function deleteUser(userId: number) {
|
||||
v-model="inviteEmail"
|
||||
type="email"
|
||||
placeholder="Email address"
|
||||
class="input invite-input"
|
||||
class="fs-input input invite-input"
|
||||
required
|
||||
:disabled="sendingInvite"
|
||||
/>
|
||||
@@ -2731,25 +2731,10 @@ async function deleteUser(userId: number) {
|
||||
margin-bottom: 0.35rem;
|
||||
color: var(--fs-text-primary);
|
||||
}
|
||||
/* remainder over .fs-input (components.css, canon #2336; m302) */
|
||||
.input {
|
||||
width: 100%;
|
||||
padding: 0.45rem 0.7rem;
|
||||
border: 1px solid var(--fs-border-color);
|
||||
border-radius: var(--fs-radius-sm);
|
||||
font-size: 0.9rem;
|
||||
background: var(--fs-surface-page);
|
||||
color: var(--fs-text-primary);
|
||||
box-sizing: border-box;
|
||||
font-family: inherit;
|
||||
}
|
||||
.input:focus {
|
||||
outline: none;
|
||||
border-color: var(--fs-accent);
|
||||
}
|
||||
.field-hint {
|
||||
margin: 0.3rem 0 0;
|
||||
font-size: 0.78rem;
|
||||
color: var(--fs-text-tertiary);
|
||||
}
|
||||
.field-hint-warn {
|
||||
display: block;
|
||||
|
||||
@@ -98,7 +98,7 @@ onMounted(async () => {
|
||||
}
|
||||
|
||||
.page-header {
|
||||
margin-bottom: 2rem;
|
||||
margin-bottom: 2rem; /* roomier than the shared recipe */
|
||||
}
|
||||
|
||||
.page-title {
|
||||
@@ -247,8 +247,6 @@ onMounted(async () => {
|
||||
.perm-admin { background: color-mix(in srgb, var(--fs-warning) 15%, transparent); color: var(--fs-warning); }
|
||||
|
||||
.empty-msg {
|
||||
color: var(--fs-text-tertiary);
|
||||
font-size: 0.88rem;
|
||||
margin: 0;
|
||||
padding: 1rem 0;
|
||||
}
|
||||
|
||||
@@ -220,14 +220,8 @@ async function confirmDelete() {
|
||||
color: var(--fs-accent);
|
||||
}
|
||||
|
||||
.state-msg {
|
||||
color: var(--fs-text-tertiary);
|
||||
font-size: 0.9rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
.state-msg,
|
||||
.error-msg {
|
||||
color: var(--fs-error);
|
||||
font-size: 0.9rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
|
||||
@@ -227,7 +227,7 @@ function cancel() {
|
||||
ref="nameRef"
|
||||
v-model="form.name"
|
||||
type="text"
|
||||
class="input mono"
|
||||
class="fs-input input mono"
|
||||
placeholder="useDebouncedRef"
|
||||
@keydown.escape="cancel"
|
||||
/>
|
||||
@@ -239,7 +239,7 @@ function cancel() {
|
||||
id="sn-when"
|
||||
v-model="form.when_to_use"
|
||||
type="text"
|
||||
class="input"
|
||||
class="fs-input input"
|
||||
placeholder="Debounce a reactive ref that updates too often"
|
||||
@keydown.escape="cancel"
|
||||
/>
|
||||
@@ -253,7 +253,7 @@ function cancel() {
|
||||
id="sn-lang"
|
||||
v-model="form.language"
|
||||
type="text"
|
||||
class="input"
|
||||
class="fs-input input"
|
||||
placeholder="typescript"
|
||||
@keydown.escape="cancel"
|
||||
/>
|
||||
@@ -264,7 +264,7 @@ function cancel() {
|
||||
id="sn-sig"
|
||||
v-model="form.signature"
|
||||
type="text"
|
||||
class="input mono"
|
||||
class="fs-input input mono"
|
||||
placeholder="useDebouncedRef(value, ms)"
|
||||
@keydown.escape="cancel"
|
||||
/>
|
||||
@@ -277,9 +277,9 @@ function cancel() {
|
||||
<span class="hint-inline">— where the reference implementation(s) live; a merged snippet keeps every call site</span>
|
||||
</legend>
|
||||
<div v-for="(loc, i) in locations" :key="i" class="loc-row">
|
||||
<input v-model="loc.repo" type="text" class="input mono" placeholder="repo" aria-label="Repo" @keydown.escape="cancel" />
|
||||
<input v-model="loc.path" type="text" class="input mono" placeholder="path" aria-label="Path" @keydown.escape="cancel" />
|
||||
<input v-model="loc.symbol" type="text" class="input mono" placeholder="symbol" aria-label="Symbol" @keydown.escape="cancel" />
|
||||
<input v-model="loc.repo" type="text" class="fs-input input mono" placeholder="repo" aria-label="Repo" @keydown.escape="cancel" />
|
||||
<input v-model="loc.path" type="text" class="fs-input input mono" placeholder="path" aria-label="Path" @keydown.escape="cancel" />
|
||||
<input v-model="loc.symbol" type="text" class="fs-input input mono" placeholder="symbol" aria-label="Symbol" @keydown.escape="cancel" />
|
||||
<button
|
||||
type="button"
|
||||
class="loc-remove"
|
||||
@@ -296,7 +296,7 @@ function cancel() {
|
||||
<textarea
|
||||
id="sn-code"
|
||||
v-model="form.code"
|
||||
class="input mono code-area"
|
||||
class="fs-input input mono code-area"
|
||||
rows="14"
|
||||
spellcheck="false"
|
||||
placeholder="Paste the reusable implementation…"
|
||||
@@ -309,7 +309,7 @@ function cancel() {
|
||||
id="sn-tags"
|
||||
v-model="tagsText"
|
||||
type="text"
|
||||
class="input"
|
||||
class="fs-input input"
|
||||
placeholder="composable, ui (comma-separated)"
|
||||
@keydown.escape="cancel"
|
||||
/>
|
||||
@@ -383,14 +383,6 @@ function cancel() {
|
||||
color: var(--fs-accent);
|
||||
}
|
||||
|
||||
.state-msg {
|
||||
color: var(--fs-text-tertiary);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.error-msg {
|
||||
color: var(--fs-error);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.form {
|
||||
display: flex;
|
||||
@@ -417,9 +409,6 @@ function cancel() {
|
||||
font-weight: 500;
|
||||
color: var(--fs-text-primary);
|
||||
}
|
||||
.required {
|
||||
color: var(--fs-error);
|
||||
}
|
||||
.hint {
|
||||
font-size: 0.75rem;
|
||||
color: var(--fs-text-tertiary);
|
||||
@@ -430,21 +419,10 @@ function cancel() {
|
||||
color: var(--fs-text-tertiary);
|
||||
}
|
||||
|
||||
/* remainder over .fs-input (components.css, canon #2336; m302) */
|
||||
.input {
|
||||
padding: 0.5rem 0.7rem;
|
||||
border: 1px solid var(--fs-border-color);
|
||||
border-radius: var(--fs-radius-sm);
|
||||
background: var(--fs-surface-page);
|
||||
color: var(--fs-text-primary);
|
||||
font-size: 0.9rem;
|
||||
font-family: inherit;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
}
|
||||
.input:focus {
|
||||
outline: none;
|
||||
border-color: var(--fs-accent);
|
||||
box-shadow: var(--fs-focus-ring);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.mono {
|
||||
font-family: var(--fs-font-mono);
|
||||
|
||||
@@ -520,13 +520,7 @@ function usageTitle(s: SnippetListItem): string {
|
||||
<style src="@/assets/dup-report.css" />
|
||||
<style scoped>
|
||||
.page-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 0.35rem;
|
||||
}
|
||||
.page-header h1 {
|
||||
margin: 0;
|
||||
margin-bottom: 0.35rem; /* tighter than the shared recipe: .page-sub follows */
|
||||
}
|
||||
.page-sub {
|
||||
margin: 0 0 1.25rem;
|
||||
@@ -616,8 +610,6 @@ function usageTitle(s: SnippetListItem): string {
|
||||
}
|
||||
|
||||
.error-msg {
|
||||
color: var(--fs-error);
|
||||
font-size: 0.9rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
@@ -632,15 +624,7 @@ function usageTitle(s: SnippetListItem): string {
|
||||
margin-bottom: 0.75rem;
|
||||
opacity: 0.35;
|
||||
}
|
||||
.empty-title {
|
||||
font-size: 1rem;
|
||||
font-weight: 500;
|
||||
color: var(--fs-text-secondary);
|
||||
margin: 0 0 0.35rem;
|
||||
}
|
||||
.empty-sub {
|
||||
font-size: 0.85rem;
|
||||
margin: 0 0 1rem;
|
||||
max-width: 44ch;
|
||||
margin-inline: auto;
|
||||
line-height: 1.5;
|
||||
|
||||
Reference in New Issue
Block a user