Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 27 additions & 8 deletions src/components/PlaceholderTagAdder.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
<script setup lang="ts">
import { ref } from 'vue';
import { GF, StaticTagging, VariableTagging } from '../models';
import type { Location } from '../models';
import type { Axis, Location } from '../models';

interface AxisPosition {
axisValue: number;
// A number, or the keywords "min"/"max" which resolve to each font's own axis bounds.
axisValue: number | string;
score: number;
}

// Resolve a position's axis value against a specific font's axis.
// "min"/"max" map to that font's axis bounds; numeric strings are parsed.
// Returns null if the value can't be resolved to a number.
function resolveAxisValue(rawValue: number | string, axis: Axis): number | null {
if (typeof rawValue === 'number') return rawValue;
const v = rawValue.trim().toLowerCase();
if (v === 'min') return axis.min;
if (v === 'max') return axis.max;
const n = parseFloat(rawValue);
return isNaN(n) ? null : n;
}

interface AxisSpec {
axisName: string;
positions: AxisPosition[];
Expand Down Expand Up @@ -93,9 +106,11 @@ function submitVariable() {
return axisSpecs.value.every(spec => {
const axis = family.axis(spec.axisName);
if (!axis) return false;
const axisValues = spec.positions.map(p => p.axisValue);
const minAxis = Math.min(...axisValues);
const maxAxis = Math.max(...axisValues);
// "min"/"max" always resolve within range; only explicit numbers can fall outside it.
const axisValues = spec.positions.map(p => resolveAxisValue(p.axisValue, axis));
if (axisValues.some(v => v === null)) return false;
const minAxis = Math.min(...axisValues as number[]);
const maxAxis = Math.max(...axisValues as number[]);
return axis.min <= minAxis && axis.max >= maxAxis;
});
});
Expand All @@ -121,10 +136,14 @@ function submitVariable() {
}
const scores: { location: Location; score: number }[] = [];
for (const spec of axisSpecs.value) {
const axis = family.axis(spec.axisName);
if (!axis) continue;
for (const pos of spec.positions) {
const inherit = inheritedDefaultScore !== null && spec.axisName === 'wght' && pos.axisValue === 400;
const value = resolveAxisValue(pos.axisValue, axis);
if (value === null) continue;
const inherit = inheritedDefaultScore !== null && spec.axisName === 'wght' && value === 400;
scores.push({
location: { [spec.axisName]: pos.axisValue },
location: { [spec.axisName]: value },
score: inherit ? inheritedDefaultScore! : pos.score
});
}
Expand Down Expand Up @@ -170,7 +189,7 @@ function submitVariable() {
</div>
<div v-for="(pos, posIdx) in spec.positions" :key="posIdx" class="position-row">
<label>Axis value:</label>
<input type="number" v-model.number="pos.axisValue" style="width: 80px;" />
<input type="text" v-model="pos.axisValue" placeholder="number, min, max" style="width: 100px;" />
<label>Score:</label>
<input type="number" v-model.number="pos.score" min="0" max="100" style="width: 60px;" />
<button v-if="spec.positions.length > 2" @click="removePosition(spec, posIdx)">Remove</button>
Expand Down
21 changes: 21 additions & 0 deletions src/components/TagView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,24 @@ onBeforeMount(() => { EventBus.$emit('ensure-loaded', props.tagging?.font.name);
const removeTagging = () => { props.tagging?.font.removeTagging(props.tagging) }
const inputValue = (e: Event) => Number((e.target as HTMLInputElement).value);

function removePosition(idx: number) {
if (!props.tagging || !('scores' in props.tagging)) return;
props.tagging.scores.splice(idx, 1);
}

function addPosition() {
if (!props.tagging || !('scores' in props.tagging)) return;
const scores = props.tagging.scores;
// Base the new position on the axes already used by this tagging,
// seeding each axis at the font's minimum value.
const axes = scores.length > 0 ? Object.keys(scores[0].location) : [];
const location: Location = {};
for (const axis of axes) {
location[axis] = props.tagging.font.axis(axis)?.min ?? 0;
}
scores.push({ location, score: 0 });
}

const currentLocationIndex = ref(0);
const editing = ref(false);
let animationInterval: ReturnType<typeof setInterval> | null = null;
Expand Down Expand Up @@ -124,7 +142,10 @@ onBeforeUnmount(() => {
@focus="editing = true"
@change="entry.score = inputValue($event)"
@blur="editing = false" />
<button v-if="props.tagging.scores.length > 1" @click="removePosition(idx)"
class="remove-position-btn">X</button>
</div>
<button @click="addPosition" class="add-position-btn">+</button>
</span>
<button @click="removeTagging" class="remove-tag-btn">Remove</button>
</div>
Expand Down
Loading