servicemap 0.1.47 → 0.1.48

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.
Binary file
Binary file
@@ -0,0 +1,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) for portions of Lucide are held by Cole Bemis 2013-2022 as part of Feather (MIT). All other copyright (c) for Lucide are held by Lucide Contributors 2022.
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
@@ -0,0 +1,16 @@
1
+ # Service Map desktop icon
2
+
3
+ This icon reproduces the Service Map header in the SettleAI website source, rather than using a screenshot or the scanned project's logo.
4
+
5
+ Source: `app/internal/service-map/desktop/App.tsx` (`Network size={18}`) and `app/internal/service-map/desktop/styles.css` (`.brand__mark`) in the SettleAI website repository.
6
+ The SVG preserves the network paths, green gradient, mint stroke, rounded tile, and relative symbol size, with transparent padding for the Dock.
7
+ The Network paths come from Lucide and their license is included in `LICENSE.lucide`.
8
+
9
+ Regenerate the native assets using the Tauri CLI:
10
+
11
+ ```sh
12
+ tauri icon assets/desktop-icons/service-map.svg --output assets/desktop-icons
13
+ ```
14
+
15
+ Keep only the desktop PNG, ICNS, and ICO files used by `scripts/generate-desktop-app.mjs`; the command also generates unused mobile and Windows Store assets.
16
+ The generator copies these prebuilt files so consumers do not need image-conversion tools.
Binary file
Binary file
Binary file
@@ -0,0 +1,11 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="1024" height="1024" viewBox="0 0 48 48">
2
+ <defs><linearGradient id="tile" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#245b45"/><stop offset="1" stop-color="#132e24"/></linearGradient></defs>
3
+ <rect x="4" y="4" width="40" height="40" rx="12.22" fill="url(#tile)" stroke="#9df0cb" stroke-opacity=".2" stroke-width="1.11"/>
4
+ <g transform="translate(14 14) scale(.8333333333)" fill="none" stroke="#a9f3d2" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
5
+ <rect x="16" y="16" width="6" height="6" rx="1"/>
6
+ <rect x="2" y="16" width="6" height="6" rx="1"/>
7
+ <rect x="9" y="2" width="6" height="6" rx="1"/>
8
+ <path d="M5 16v-3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v3"/>
9
+ <path d="M12 12V8"/>
10
+ </g>
11
+ </svg>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "servicemap",
3
- "version": "0.1.47",
3
+ "version": "0.1.48",
4
4
  "description": "Generate an internal service map page or desktop app for a software project.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -27,3 +27,9 @@ npm run build
27
27
 
28
28
  Do not install global tooling automatically.
29
29
  If native packaging fails because Rust, platform SDKs, or Tauri prerequisites are missing, report that the app source was generated and the web build passed.
30
+
31
+ ## Desktop identity
32
+
33
+ The generated desktop app uses the shared green Service Map network logo for its Dock and application icons.
34
+ The project logo belongs inside the map and must not replace `src-tauri/icons` or the configured bundle icons.
35
+ The packaged icon source is `assets/desktop-icons/service-map.svg`, derived from the SettleAI website Service Map header.
@@ -1,6 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import { mkdir, readFile, writeFile } from 'node:fs/promises';
3
3
  import { dirname, join, resolve } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+
6
+ const desktopIcons = fileURLToPath(new URL('../assets/desktop-icons/', import.meta.url));
7
+ const iconFiles = ['32x32.png', '128x128.png', '128x128@2x.png', 'icon.png', 'icon.icns', 'icon.ico'];
4
8
  import { interactiveTsxPage, prepareProjectLogo } from './generate-page.mjs';
5
9
 
6
10
  const defaultInput = '.servicemap/internal-servicemap.json';
@@ -116,6 +120,7 @@ function tauriConfig(graph) {
116
120
  bundle: {
117
121
  active: true,
118
122
  targets: 'all',
123
+ icon: iconFiles.map((name) => `icons/${name}`),
119
124
  },
120
125
  }, null, 2)}\n`;
121
126
  }
@@ -170,6 +175,9 @@ async function main() {
170
175
 
171
176
  await mkdir(options.output, { recursive: true });
172
177
  await prepareProjectLogo(graph, options.output);
178
+ for (const name of iconFiles) {
179
+ await writeProjectFile(options.output, `src-tauri/icons/${name}`, await readFile(join(desktopIcons, name)));
180
+ }
173
181
  await writeProjectFile(options.output, 'package.json', packageJson(graph));
174
182
  await writeProjectFile(options.output, 'index.html', indexHtml());
175
183
  await writeProjectFile(options.output, 'vite.config.js', viteConfig());
@@ -290,7 +290,7 @@ export function interactiveTsxPage(graph, { desktop = false } = {}) {
290
290
  return `'use client';
291
291
 
292
292
  ${desktop ? "import ForceGraph3D from 'react-force-graph-3d';" : "import dynamic from 'next/dynamic';"}
293
- import { useCallback, useEffect, useMemo, useRef, useState, type CSSProperties, type PointerEvent } from 'react';
293
+ import { useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState, type CSSProperties, type PointerEvent } from 'react';
294
294
  import type { ForceGraphMethods, NodeObject } from 'react-force-graph-3d';
295
295
  import * as THREE from 'three';
296
296
  import SpriteText from 'three-spritetext';
@@ -689,11 +689,13 @@ function ServiceGraph3D({
689
689
  nodes,
690
690
  selectedId,
691
691
  resetKey,
692
+ controlsRef,
692
693
  onSelect,
693
694
  }: {
694
695
  nodes: ServiceNode[];
695
696
  selectedId: string | null;
696
697
  resetKey: number;
698
+ controlsRef: { current: { zoom: (factor: number) => void } | null };
697
699
  onSelect: (id: string | null) => void;
698
700
  }) {
699
701
  const containerRef = useRef<HTMLDivElement>(null);
@@ -807,6 +809,8 @@ function ServiceGraph3D({
807
809
  graphInstance.cameraPosition(nextPosition, target, 240);
808
810
  }, []);
809
811
 
812
+ useImperativeHandle(controlsRef, () => ({ zoom }), [zoom]);
813
+
810
814
  return (
811
815
  <div className="graph-3d" ref={containerRef}>
812
816
  <ForceGraph3D
@@ -861,10 +865,6 @@ function ServiceGraph3D({
861
865
  graphRef.current?.zoomToFit(700, 130);
862
866
  }}
863
867
  />
864
- <div className="graph-3d__zoom" aria-label="3D zoom controls">
865
- <button type="button" onClick={() => zoom(1 / 1.5)} title="Zoom in" aria-label="Zoom in">+</button>
866
- <button type="button" onClick={() => zoom(1.5)} title="Zoom out" aria-label="Zoom out">−</button>
867
- </div>
868
868
  <div className="graph-3d__help" aria-hidden="true">Drag to rotate <span /> Scroll to zoom <span /> Click a service</div>
869
869
  {selectedId && <div className="graph-3d__focus" aria-hidden="true">{activeTreeLinkIds.size} connections highlighted</div>}
870
870
  </div>
@@ -901,6 +901,7 @@ export default function InternalServiceMapPage() {
901
901
  const [panStart, setPanStart] = useState<{ pointerId: number; x: number; y: number; panX: number; panY: number } | null>(null);
902
902
  const [selectedId, setSelectedId] = useState<string | null>(null);
903
903
  const [reset3DKey, setReset3DKey] = useState(0);
904
+ const controls3DRef = useRef<{ zoom: (factor: number) => void } | null>(null);
904
905
  const startNodeDrag = (event: PointerEvent<HTMLButtonElement>, node: ServiceNode) => {
905
906
  if (event.button !== 0) return;
906
907
  event.stopPropagation();
@@ -946,8 +947,14 @@ export default function InternalServiceMapPage() {
946
947
  const selected = nodes.find((service) => service.id === selectedId) ?? null;
947
948
  const descendantIds = useMemo(() => collectDescendantIds(nodes, selectedId), [nodes, selectedId]);
948
949
  const highlightedChildIds = useMemo(() => selectedId === 'project' ? descendantIds : new Set<string>(), [descendantIds, selectedId]);
949
- const zoomIn = () => setZoom((current) => Math.min(1.45, current * 1.5));
950
- const zoomOut = () => setZoom((current) => current / 1.5);
950
+ const zoomIn = () => {
951
+ if (mode === '3d') controls3DRef.current?.zoom(1 / 1.5);
952
+ else setZoom((current) => Math.min(1.45, current * 1.5));
953
+ };
954
+ const zoomOut = () => {
955
+ if (mode === '3d') controls3DRef.current?.zoom(1.5);
956
+ else setZoom((current) => current / 1.5);
957
+ };
951
958
  const resetZoom = () => {
952
959
  setZoom(1);
953
960
  setPan({ x: 0, y: 0 });
@@ -1088,12 +1095,12 @@ export default function InternalServiceMapPage() {
1088
1095
  </div>
1089
1096
  </>
1090
1097
  ) : (
1091
- <ServiceGraph3D nodes={nodes} selectedId={selectedId} resetKey={reset3DKey} onSelect={setSelectedId} />
1098
+ <ServiceGraph3D nodes={nodes} selectedId={selectedId} resetKey={reset3DKey} controlsRef={controls3DRef} onSelect={setSelectedId} />
1092
1099
  )}
1093
1100
  <div className="zoom-controls" aria-label="Map zoom controls">
1094
1101
  <button type="button" className="zoom-button" onClick={zoomIn} aria-label="Zoom in">+</button>
1095
1102
  <button type="button" className="zoom-button" onClick={zoomOut} aria-label="Zoom out">−</button>
1096
- <button type="button" className="zoom-button" onClick={resetZoom} aria-label="Reset zoom"><span className="fit-icon" aria-hidden="true" /></button>
1103
+ <button type="button" className="zoom-button" onClick={centerMap} aria-label="Reset zoom"><span className="fit-icon" aria-hidden="true" /></button>
1097
1104
  </div>
1098
1105
  <footer className="scan-foot">
1099
1106
  <div>Generated {new Date(graph.generatedAt).toLocaleString()}</div>