dsh-fonttune 0.6.2 → 0.7.1

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.
package/lib/shared.cjs CHANGED
@@ -1185,6 +1185,15 @@ function floatBoundsPick(rects, viewport) {
1185
1185
  if (!isFinite(vh) || vh <= 0) vh = FLOAT_VIEWPORT_H;
1186
1186
  var full = { left: 0, top: 0, right: vw, bottom: vh, width: vw, height: vh };
1187
1187
  var list = Array.isArray(rects) ? rects : [];
1188
+ // A region narrower than one dot used to count as "no region at all", and the
1189
+ // fallback was the WHOLE viewport — so in a narrow window the dot parked on the
1190
+ // window's own corner, over the sidebar, instead of on the conversation's. The
1191
+ // largest readable box is kept as a fallback, and it names itself in `index` so
1192
+ // the watcher holds the box whose size actually defines the region. `full` is
1193
+ // left for a page with no region at all — or only degenerate 0-area rects.
1194
+ var best = null;
1195
+ var bestIndex = -1;
1196
+ var bestArea = -1;
1188
1197
  for (var index = 0; index < list.length; index += 1) {
1189
1198
  var box = floatBoxOf(list[index]);
1190
1199
  if (box === null) continue;
@@ -1194,12 +1203,18 @@ function floatBoundsPick(rects, viewport) {
1194
1203
  var bottom = Math.max(0, Math.min(vh, box.bottom));
1195
1204
  var width = right - left;
1196
1205
  var height = bottom - top;
1206
+ if (width > 0 && height > 0 && width * height > bestArea) {
1207
+ bestArea = width * height;
1208
+ bestIndex = index;
1209
+ best = { left: left, top: top, right: right, bottom: bottom, width: width, height: height };
1210
+ }
1197
1211
  if (width < FLOAT_BOUNDS_MIN || height < FLOAT_BOUNDS_MIN) continue;
1198
1212
  return {
1199
1213
  index: index,
1200
1214
  bounds: { left: left, top: top, right: right, bottom: bottom, width: width, height: height },
1201
1215
  };
1202
1216
  }
1217
+ if (best !== null) return { index: bestIndex, bounds: best };
1203
1218
  return { index: -1, bounds: full };
1204
1219
  }
1205
1220
 
@@ -1318,6 +1333,36 @@ function floatTransformOrigin(quadrant) {
1318
1333
  return "100% 100%";
1319
1334
  }
1320
1335
 
1336
+ /**
1337
+ * Which side the open CARD grows towards: the one with more room for it.
1338
+ *
1339
+ * The card hangs off the dot, so it can only extend one way from it, and the
1340
+ * side that holds more of the card is the side the conversation has room for.
1341
+ * Each axis compares the room beyond the dot's own box on either side and sends
1342
+ * the card to the larger one — which is also the side its middle ends up on, so
1343
+ * "the panel goes to the corner it sits in" holds by construction.
1344
+ *
1345
+ * This is the CARD's rule, not the dot's: the dot keeps the corner it remembers
1346
+ * living in (see `floatCornerPoint`), while a rule shared by both is what made
1347
+ * the card jump whenever the dot crossed a line the card had not. The answer
1348
+ * depends on the dot and the region and on nothing else — never on a card it
1349
+ * just placed — so it cannot vote itself back and forth.
1350
+ * @param {unknown} bounds - the region, as `floatBoundsFrom` returns it.
1351
+ * @param {number} x - the dot's left edge, in CSS pixels.
1352
+ * @param {number} y - the dot's top edge, in CSS pixels.
1353
+ * @param {number} [dot] - the dot's diameter (defaults to FLOAT_DOT).
1354
+ * @returns {string} one of "tl", "tr", "bl", "br" — the quadrant the card is
1355
+ * anchored on, which is the corner it grows away from.
1356
+ */
1357
+ function floatCardCorner(bounds, x, y, dot) {
1358
+ var box = floatBoxOf(bounds);
1359
+ if (box === null) box = { left: 0, top: 0, right: FLOAT_VIEWPORT_W, bottom: FLOAT_VIEWPORT_H };
1360
+ var size = dot === undefined ? FLOAT_DOT : dot;
1361
+ var growRight = box.right - x >= x + size - box.left;
1362
+ var growDown = box.bottom - y >= y + size - box.top;
1363
+ return (growDown ? "t" : "b") + (growRight ? "l" : "r");
1364
+ }
1365
+
1321
1366
  /**
1322
1367
  * Which corner of the card lands on the dot, and where the expansion starts.
1323
1368
  *
@@ -1844,6 +1889,47 @@ function normalizeDarkValues(value, relative) {
1844
1889
  /** The three axes that share the weight scale (and its marker). */
1845
1890
  var WEIGHT_FIELDS = [WEIGHT_FIELD, WEIGHT_DIALOG_FIELD, CODE_WEIGHT_FIELD];
1846
1891
 
1892
+ /**
1893
+ * Return a copy of a sparse dark-theme override map with one field changed.
1894
+ *
1895
+ * The map holds only the fields the reader overrode for the dark theme; an
1896
+ * absent field inherits the light value. `undefined` therefore means "stop
1897
+ * overriding", not "set to empty" — that distinction is what lets the card show
1898
+ * "follows the light set" instead of a value the reader never chose.
1899
+ * @param {unknown} map - the current sparse map (anything object-shaped).
1900
+ * @param {string} field - a settings field name.
1901
+ * @param {string|number|boolean|undefined} value - the override, or undefined to clear it.
1902
+ * @returns {Record<string, string|number|boolean>} a new map; the input is untouched.
1903
+ */
1904
+ function withDarkOverride(map, field, value) {
1905
+ var source = map !== null && typeof map === "object" && !Array.isArray(map) ? map : {};
1906
+ var out = {};
1907
+ var key;
1908
+ for (key in source) {
1909
+ if (Object.prototype.hasOwnProperty.call(source, key)) out[key] = source[key];
1910
+ }
1911
+ if (value === undefined) delete out[field];
1912
+ else out[field] = value;
1913
+ return out;
1914
+ }
1915
+
1916
+ /**
1917
+ * Serialize a dark override map for storage, with its keys in a stable order.
1918
+ *
1919
+ * Stable order matters twice: the settings document is diffed as text (an
1920
+ * equivalent map written in a different key order would look like a change and
1921
+ * cost a whole-document write), and the preset snapshot compares the text too.
1922
+ * @param {unknown} map - the sparse map.
1923
+ * @returns {string} the JSON text the document stores.
1924
+ */
1925
+ function darkValuesText(map) {
1926
+ var source = map !== null && typeof map === "object" && !Array.isArray(map) ? map : {};
1927
+ var keys = Object.keys(source).sort();
1928
+ var out = {};
1929
+ for (var index = 0; index < keys.length; index += 1) out[keys[index]] = source[keys[index]];
1930
+ return JSON.stringify(out);
1931
+ }
1932
+
1847
1933
  /**
1848
1934
  * Convert the weight fields of saved preset snapshots to offsets.
1849
1935
  *
@@ -4573,6 +4659,7 @@ var shared = {
4573
4659
  floatExpandDirection: floatExpandDirection,
4574
4660
  floatTransformOrigin: floatTransformOrigin,
4575
4661
  floatCardAnchor: floatCardAnchor,
4662
+ floatCardCorner: floatCardCorner,
4576
4663
  floatClipStart: floatClipStart,
4577
4664
  floatClipRest: floatClipRest,
4578
4665
  isRestClip: isRestClip,
@@ -4676,6 +4763,8 @@ var shared = {
4676
4763
  quoteFamily: quoteFamily,
4677
4764
  normalizeConfig: normalizeConfig,
4678
4765
  normalizeDarkValues: normalizeDarkValues,
4766
+ withDarkOverride: withDarkOverride,
4767
+ darkValuesText: darkValuesText,
4679
4768
  normalizePresets: normalizePresets,
4680
4769
  normalizeValueSet: normalizeValueSet,
4681
4770
  clampOffset: clampOffset,
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "dsh-fonttune",
3
- "version": "0.6.2",
3
+ "version": "0.7.1",
4
4
  "description": "Font plugin for the DeepSeek Harness Web GUI: the conversation gets its own font, size, line height and weight, the interface font and weight follow it, code keeps its own axis with ligature control, and whole setups save as presets.",
5
5
  "type": "module",
6
+ "icon": "icon.svg",
6
7
  "main": "lib/index.js",
7
8
  "exports": {
8
9
  ".": "./lib/index.js",
@@ -14,6 +15,7 @@
14
15
  "lib",
15
16
  "locale",
16
17
  "cordis.patch.yml",
18
+ "icon.svg",
17
19
  "README.md",
18
20
  "README.en.md",
19
21
  "CHANGELOG.md",