@haposoft/cafekit 0.13.4 → 0.14.0
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/README.md +2 -23
- package/bin/lib/i18n.js +2 -2
- package/bin/lib/manifest.js +15 -0
- package/bin/lib/opencode-install.js +0 -14
- package/bin/phases/claude-runtime.js +4 -1
- package/bin/phases/claude-settings.js +38 -7
- package/bin/phases/root-config.js +5 -24
- package/package.json +1 -1
- package/src/claude/agents/ui-ux-designer.md +4 -4
- package/src/claude/gitignore +4 -11
- package/src/claude/hooks/__tests__/privacy-block.test.js +79 -0
- package/src/claude/hooks/__tests__/session-writeenv.test.js +68 -0
- package/src/claude/hooks/__tests__/spec-gate.test.js +270 -0
- package/src/claude/hooks/privacy-block.cjs +22 -2
- package/src/claude/hooks/session.cjs +5 -1
- package/src/claude/hooks/spec-gate.cjs +173 -0
- package/src/claude/hooks/spec-state.cjs +10 -17
- package/src/claude/hooks/task-scaffold-guard.cjs +4 -2
- package/src/claude/migration-manifest.json +5 -5
- package/src/claude/rules/skill-domain-routing.md +2 -3
- package/src/claude/rules/skill-workflow-routing.md +2 -11
- package/src/claude/rules/state-sync.md +4 -0
- package/src/claude/runtime.json +4 -0
- package/src/claude/scripts/validate-docs.cjs +4 -7
- package/src/claude/scripts/validate-spec-output.cjs +29 -9
- package/src/claude/settings/settings.json +4 -0
- package/src/claude/skills/ai-multimodal/.env.example +11 -13
- package/src/claude/skills/ai-multimodal/SKILL.md +1 -1
- package/src/claude/skills/ai-multimodal/references/audio-processing.md +25 -27
- package/src/claude/skills/ai-multimodal/references/video-analysis.md +23 -27
- package/src/claude/skills/ai-multimodal/references/vision-understanding.md +26 -26
- package/src/claude/skills/ai-multimodal/scripts/check_setup.py +1 -1
- package/src/claude/skills/ai-multimodal/scripts/gemini_batch_process.py +7 -9
- package/src/claude/skills/brainstorm/SKILL.md +1 -2
- package/src/claude/skills/docx/SKILL.md +1 -1
- package/src/claude/skills/frontend-design/SKILL.md +1 -1
- package/src/claude/skills/frontend-design/references/ai-multimodal-overview.md +4 -4
- package/src/claude/skills/frontend-design/references/analysis-techniques.md +3 -3
- package/src/claude/skills/frontend-design/references/asset-generation.md +2 -2
- package/src/claude/skills/frontend-design/references/design-extraction-overview.md +4 -4
- package/src/claude/skills/frontend-design/references/extraction-best-practices.md +3 -3
- package/src/claude/skills/frontend-design/references/technical-accessibility.md +1 -1
- package/src/claude/skills/frontend-design/references/technical-optimization.md +1 -1
- package/src/claude/skills/frontend-design/references/technical-overview.md +2 -2
- package/src/claude/skills/frontend-design/references/technical-workflows.md +6 -6
- package/src/claude/skills/frontend-design/references/visual-analysis-overview.md +3 -3
- package/src/claude/skills/inspect/SKILL.md +3 -3
- package/src/claude/skills/inspect/references/external-gemini-inspection.md +9 -9
- package/src/claude/skills/pdf/SKILL.md +1 -1
- package/src/claude/skills/pptx/SKILL.md +1 -1
- package/src/claude/skills/specs/SKILL.md +1 -1
- package/src/claude/skills/xlsx/SKILL.md +1 -1
- package/src/opencode/AGENTS.md +1 -2
- package/src/opencode/plugins/session.ts +2 -2
- package/src/opencode/plugins/spec-state.ts +244 -0
- package/src/opencode/plugins/task-scaffold-guard.ts +161 -0
- package/src/claude/scripts/browser-tool.cjs +0 -138
- package/src/claude/skills/delegate/SKILL.md +0 -124
- package/src/claude/skills/delegate/references/codex-delegation.md +0 -71
- package/src/claude/skills/delegate/references/grok-delegation.md +0 -84
- package/src/claude/skills/generate-graph/LICENSE +0 -21
- package/src/claude/skills/generate-graph/README.md +0 -523
- package/src/claude/skills/generate-graph/SKILL.md +0 -429
- package/src/claude/skills/generate-graph/agentloop-core.svg +0 -101
- package/src/claude/skills/generate-graph/agents/openai.yaml +0 -4
- package/src/claude/skills/generate-graph/assets/samples/sample-style1-flat.png +0 -0
- package/src/claude/skills/generate-graph/assets/samples/sample-style2-dark.png +0 -0
- package/src/claude/skills/generate-graph/assets/samples/sample-style3-blueprint.png +0 -0
- package/src/claude/skills/generate-graph/assets/samples/sample-style4-notion.png +0 -0
- package/src/claude/skills/generate-graph/assets/samples/sample-style5-glass.png +0 -0
- package/src/claude/skills/generate-graph/assets/samples/sample-style6-claude.png +0 -0
- package/src/claude/skills/generate-graph/assets/samples/sample-style7-openai.png +0 -0
- package/src/claude/skills/generate-graph/fixtures/agent-memory-types-style4.json +0 -181
- package/src/claude/skills/generate-graph/fixtures/api-flow-style7.json +0 -40
- package/src/claude/skills/generate-graph/fixtures/mem0-style1.json +0 -297
- package/src/claude/skills/generate-graph/fixtures/microservices-style3.json +0 -64
- package/src/claude/skills/generate-graph/fixtures/multi-agent-style5.json +0 -45
- package/src/claude/skills/generate-graph/fixtures/system-architecture-style6.json +0 -48
- package/src/claude/skills/generate-graph/fixtures/tool-call-style2.json +0 -182
- package/src/claude/skills/generate-graph/package.json +0 -42
- package/src/claude/skills/generate-graph/references/icons.md +0 -281
- package/src/claude/skills/generate-graph/references/style-1-flat-icon.md +0 -108
- package/src/claude/skills/generate-graph/references/style-2-dark-terminal.md +0 -107
- package/src/claude/skills/generate-graph/references/style-3-blueprint.md +0 -113
- package/src/claude/skills/generate-graph/references/style-4-notion-clean.md +0 -94
- package/src/claude/skills/generate-graph/references/style-5-glassmorphism.md +0 -125
- package/src/claude/skills/generate-graph/references/style-6-claude-official.md +0 -209
- package/src/claude/skills/generate-graph/references/style-7-openai.md +0 -215
- package/src/claude/skills/generate-graph/references/style-diagram-matrix.md +0 -135
- package/src/claude/skills/generate-graph/references/svg-layout-best-practices.md +0 -100
- package/src/claude/skills/generate-graph/scripts/generate-diagram.sh +0 -157
- package/src/claude/skills/generate-graph/scripts/generate-from-template.py +0 -1556
- package/src/claude/skills/generate-graph/scripts/test-all-styles.sh +0 -135
- package/src/claude/skills/generate-graph/scripts/validate-svg.sh +0 -292
- package/src/claude/skills/generate-graph/templates/agent-architecture.svg +0 -28
- package/src/claude/skills/generate-graph/templates/architecture.svg +0 -23
- package/src/claude/skills/generate-graph/templates/comparison-matrix.svg +0 -14
- package/src/claude/skills/generate-graph/templates/data-flow.svg +0 -28
- package/src/claude/skills/generate-graph/templates/er-diagram.svg +0 -21
- package/src/claude/skills/generate-graph/templates/flowchart.svg +0 -21
- package/src/claude/skills/generate-graph/templates/sequence.svg +0 -20
- package/src/claude/skills/generate-graph/templates/state-machine.svg +0 -20
- package/src/claude/skills/generate-graph/templates/timeline.svg +0 -19
- package/src/claude/skills/generate-graph/templates/use-case.svg +0 -21
- package/src/claude/skills/impact-analysis/SKILL.md +0 -276
- package/src/claude/skills/impact-analysis/references/change-detection.md +0 -270
- package/src/claude/skills/impact-analysis/references/dependency-scouting.md +0 -338
- package/src/claude/skills/impact-analysis/references/edge-case-identification.md +0 -439
- package/src/claude/skills/impact-analysis/references/industry-techniques.md +0 -695
- package/src/claude/skills/impact-analysis/references/practical-techniques-guide.md +0 -753
- package/src/claude/skills/impact-analysis/references/project-detection.md +0 -704
- package/src/claude/skills/impact-analysis/references/react-native-customization.md +0 -508
- package/src/claude/skills/impact-analysis/references/report-template.md +0 -604
- package/src/claude/skills/impact-analysis/references/test-scenario-generation.md +0 -459
- package/src/claude/skills/impact-analysis/scripts/README.md +0 -476
- package/src/claude/skills/impact-analysis/scripts/ast-analyze.js +0 -403
- package/src/claude/skills/impact-analysis/scripts/calculate-risk.js +0 -475
- package/src/claude/skills/impact-analysis/scripts/find-dependencies.sh +0 -202
- package/src/claude/skills/impact-analysis/scripts/run-analysis.sh +0 -312
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# Batch Test Script
|
|
3
|
-
# Renders regression fixtures, validates SVGs, and exports PNGs
|
|
4
|
-
|
|
5
|
-
set -euo pipefail
|
|
6
|
-
|
|
7
|
-
# Colors
|
|
8
|
-
RED='\033[0;31m'
|
|
9
|
-
GREEN='\033[0;32m'
|
|
10
|
-
YELLOW='\033[1;33m'
|
|
11
|
-
BLUE='\033[0;34m'
|
|
12
|
-
NC='\033[0m'
|
|
13
|
-
|
|
14
|
-
SKILL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
15
|
-
TEST_DIR="${SKILL_DIR}/test-output"
|
|
16
|
-
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
|
17
|
-
|
|
18
|
-
echo -e "${BLUE}=== Fireworks Tech Graph - Batch Test ===${NC}"
|
|
19
|
-
echo "Test directory: $TEST_DIR"
|
|
20
|
-
echo "Timestamp: $TIMESTAMP"
|
|
21
|
-
echo ""
|
|
22
|
-
|
|
23
|
-
# Create test directory
|
|
24
|
-
mkdir -p "$TEST_DIR"
|
|
25
|
-
|
|
26
|
-
# Test configuration
|
|
27
|
-
STYLES=(1 2 3 4 5 6 7)
|
|
28
|
-
STYLE_NAMES=("Flat Icon" "Dark Terminal" "Blueprint" "Notion Clean" "Glassmorphism" "Claude Official" "OpenAI Official")
|
|
29
|
-
|
|
30
|
-
# Summary counters
|
|
31
|
-
TOTAL=0
|
|
32
|
-
PASSED=0
|
|
33
|
-
FAILED=0
|
|
34
|
-
|
|
35
|
-
FIXTURES_DIR="${SKILL_DIR}/fixtures"
|
|
36
|
-
|
|
37
|
-
echo -e "${BLUE}Testing all styles...${NC}"
|
|
38
|
-
echo "----------------------------------------"
|
|
39
|
-
|
|
40
|
-
for i in "${!STYLES[@]}"; do
|
|
41
|
-
STYLE="${STYLES[$i]}"
|
|
42
|
-
STYLE_NAME="${STYLE_NAMES[$i]}"
|
|
43
|
-
|
|
44
|
-
echo -e "\n${YELLOW}Style $STYLE: $STYLE_NAME${NC}"
|
|
45
|
-
|
|
46
|
-
# Check if style reference exists
|
|
47
|
-
STYLE_FILE=$(find "${SKILL_DIR}/references" -maxdepth 1 -type f -name "style-${STYLE}-*.md" | head -n 1)
|
|
48
|
-
if [ -z "${STYLE_FILE:-}" ] || [ ! -f "$STYLE_FILE" ]; then
|
|
49
|
-
echo -e "${RED}✗ Style file not found: $STYLE_FILE${NC}"
|
|
50
|
-
FAILED=$((FAILED + 1))
|
|
51
|
-
TOTAL=$((TOTAL + 1))
|
|
52
|
-
continue
|
|
53
|
-
fi
|
|
54
|
-
|
|
55
|
-
echo -e "${GREEN}✓ Style file found${NC}"
|
|
56
|
-
|
|
57
|
-
if [ ! -d "$FIXTURES_DIR" ]; then
|
|
58
|
-
echo -e "${YELLOW}⚠ Fixtures directory not found: $FIXTURES_DIR${NC}"
|
|
59
|
-
continue
|
|
60
|
-
fi
|
|
61
|
-
|
|
62
|
-
FIXTURE_FILES=$(find "$FIXTURES_DIR" -maxdepth 1 -type f -name "*.json" | sort || true)
|
|
63
|
-
MATCHED_FIXTURES=()
|
|
64
|
-
for FIXTURE in $FIXTURE_FILES; do
|
|
65
|
-
FIXTURE_STYLE=$(python3 - "$FIXTURE" <<'PY'
|
|
66
|
-
import json
|
|
67
|
-
import sys
|
|
68
|
-
from pathlib import Path
|
|
69
|
-
data = json.loads(Path(sys.argv[1]).read_text(encoding='utf-8'))
|
|
70
|
-
print(data.get("style", ""))
|
|
71
|
-
PY
|
|
72
|
-
)
|
|
73
|
-
if [ "$FIXTURE_STYLE" = "$STYLE" ]; then
|
|
74
|
-
MATCHED_FIXTURES+=("$FIXTURE")
|
|
75
|
-
fi
|
|
76
|
-
done
|
|
77
|
-
|
|
78
|
-
if [ "${#MATCHED_FIXTURES[@]}" -eq 0 ]; then
|
|
79
|
-
echo -e "${YELLOW}⚠ No regression fixtures found for style $STYLE${NC}"
|
|
80
|
-
continue
|
|
81
|
-
fi
|
|
82
|
-
|
|
83
|
-
# Render, validate, and export each fixture
|
|
84
|
-
for FIXTURE in "${MATCHED_FIXTURES[@]}"; do
|
|
85
|
-
BASENAME=$(basename "$FIXTURE" .json)
|
|
86
|
-
SVG_FILE="${TEST_DIR}/${BASENAME}_${TIMESTAMP}.svg"
|
|
87
|
-
PNG_FILE="${TEST_DIR}/${BASENAME}_${TIMESTAMP}.png"
|
|
88
|
-
TEMPLATE_TYPE=$(python3 - "$FIXTURE" <<'PY'
|
|
89
|
-
import json
|
|
90
|
-
import sys
|
|
91
|
-
from pathlib import Path
|
|
92
|
-
data = json.loads(Path(sys.argv[1]).read_text(encoding='utf-8'))
|
|
93
|
-
print(data.get("template_type", "architecture"))
|
|
94
|
-
PY
|
|
95
|
-
)
|
|
96
|
-
|
|
97
|
-
echo -n " Rendering $BASENAME... "
|
|
98
|
-
TOTAL=$((TOTAL + 1))
|
|
99
|
-
|
|
100
|
-
if python3 "${SKILL_DIR}/scripts/generate-from-template.py" "$TEMPLATE_TYPE" "$SVG_FILE" "$(cat "$FIXTURE")" > /dev/null 2>&1 \
|
|
101
|
-
&& "${SKILL_DIR}/scripts/validate-svg.sh" "$SVG_FILE" > /dev/null 2>&1; then
|
|
102
|
-
if command -v rsvg-convert &> /dev/null \
|
|
103
|
-
&& rsvg-convert -w 1920 "$SVG_FILE" -o "$PNG_FILE" 2>/dev/null; then
|
|
104
|
-
PNG_SIZE=$(du -h "$PNG_FILE" | cut -f1)
|
|
105
|
-
echo -e "${GREEN}✓ Pass${NC} (${PNG_SIZE})"
|
|
106
|
-
else
|
|
107
|
-
echo -e "${GREEN}✓ Pass${NC}"
|
|
108
|
-
fi
|
|
109
|
-
PASSED=$((PASSED + 1))
|
|
110
|
-
else
|
|
111
|
-
echo -e "${RED}✗ Fail${NC}"
|
|
112
|
-
FAILED=$((FAILED + 1))
|
|
113
|
-
if [ -f "$SVG_FILE" ]; then
|
|
114
|
-
"${SKILL_DIR}/scripts/validate-svg.sh" "$SVG_FILE" 2>&1 | grep -E "✗|Error" | sed 's/^/ /' || true
|
|
115
|
-
fi
|
|
116
|
-
fi
|
|
117
|
-
done
|
|
118
|
-
done
|
|
119
|
-
|
|
120
|
-
# Print summary
|
|
121
|
-
echo ""
|
|
122
|
-
echo "========================================"
|
|
123
|
-
echo -e "${BLUE}Test Summary${NC}"
|
|
124
|
-
echo "----------------------------------------"
|
|
125
|
-
echo "Total tests: $TOTAL"
|
|
126
|
-
echo -e "${GREEN}Passed: $PASSED${NC}"
|
|
127
|
-
echo -e "${RED}Failed: $FAILED${NC}"
|
|
128
|
-
|
|
129
|
-
if [ "$FAILED" -eq 0 ]; then
|
|
130
|
-
echo -e "\n${GREEN}✓ All tests passed!${NC}"
|
|
131
|
-
exit 0
|
|
132
|
-
else
|
|
133
|
-
echo -e "\n${RED}✗ Some tests failed${NC}"
|
|
134
|
-
exit 1
|
|
135
|
-
fi
|
|
@@ -1,292 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# SVG Validation Script
|
|
3
|
-
# Checks SVG syntax and reports detailed errors
|
|
4
|
-
|
|
5
|
-
set -euo pipefail
|
|
6
|
-
|
|
7
|
-
# Colors for output
|
|
8
|
-
RED='\033[0;31m'
|
|
9
|
-
GREEN='\033[0;32m'
|
|
10
|
-
YELLOW='\033[1;33m'
|
|
11
|
-
NC='\033[0m' # No Color
|
|
12
|
-
|
|
13
|
-
if [ $# -eq 0 ]; then
|
|
14
|
-
echo "Usage: $0 <svg-file>"
|
|
15
|
-
exit 1
|
|
16
|
-
fi
|
|
17
|
-
|
|
18
|
-
SVG_FILE="$1"
|
|
19
|
-
|
|
20
|
-
if [ ! -f "$SVG_FILE" ]; then
|
|
21
|
-
echo -e "${RED}Error: File not found: $SVG_FILE${NC}"
|
|
22
|
-
exit 1
|
|
23
|
-
fi
|
|
24
|
-
|
|
25
|
-
echo "Validating SVG: $SVG_FILE"
|
|
26
|
-
echo "----------------------------------------"
|
|
27
|
-
|
|
28
|
-
FAILURES=0
|
|
29
|
-
|
|
30
|
-
# Check 0: XML syntax
|
|
31
|
-
echo -n "Checking XML syntax... "
|
|
32
|
-
if command -v xmllint &> /dev/null; then
|
|
33
|
-
if xmllint --noout "$SVG_FILE" 2>/dev/null; then
|
|
34
|
-
echo -e "${GREEN}✓ Pass${NC}"
|
|
35
|
-
else
|
|
36
|
-
echo -e "${RED}✗ Fail${NC}"
|
|
37
|
-
xmllint --noout "$SVG_FILE" 2>&1 || true
|
|
38
|
-
FAILURES=$((FAILURES + 1))
|
|
39
|
-
fi
|
|
40
|
-
else
|
|
41
|
-
echo -e "${YELLOW}⚠ Skipped${NC} (xmllint not found)"
|
|
42
|
-
fi
|
|
43
|
-
|
|
44
|
-
# Check 1: Tag balance
|
|
45
|
-
echo -n "Checking tag balance... "
|
|
46
|
-
OPEN_TAGS=$( { grep -o '<[A-Za-z][A-Za-z0-9:-]*' "$SVG_FILE" || true; } | { grep -v '</' || true; } | wc -l | tr -d ' ' )
|
|
47
|
-
SELF_CLOSING=$( { grep -o '/>' "$SVG_FILE" || true; } | wc -l | tr -d ' ' )
|
|
48
|
-
CLOSE_TAGS=$( { grep -o '</[A-Za-z][A-Za-z0-9:-]*>' "$SVG_FILE" || true; } | wc -l | tr -d ' ' )
|
|
49
|
-
TOTAL_CLOSE=$((SELF_CLOSING + CLOSE_TAGS))
|
|
50
|
-
|
|
51
|
-
if [ "$OPEN_TAGS" -eq "$TOTAL_CLOSE" ]; then
|
|
52
|
-
echo -e "${GREEN}✓ Pass${NC} (${OPEN_TAGS} tags)"
|
|
53
|
-
else
|
|
54
|
-
echo -e "${RED}✗ Fail${NC} (${OPEN_TAGS} open, ${TOTAL_CLOSE} close)"
|
|
55
|
-
FAILURES=$((FAILURES + 1))
|
|
56
|
-
fi
|
|
57
|
-
|
|
58
|
-
# Check 2: Quote check
|
|
59
|
-
echo -n "Checking attribute quotes... "
|
|
60
|
-
UNQUOTED=$( { grep -oE '[a-z-]+=[^"'\''> ]' "$SVG_FILE" || true; } | wc -l | tr -d ' ' )
|
|
61
|
-
if [ "$UNQUOTED" -eq 0 ]; then
|
|
62
|
-
echo -e "${GREEN}✓ Pass${NC}"
|
|
63
|
-
else
|
|
64
|
-
echo -e "${RED}✗ Fail${NC} (${UNQUOTED} unquoted attributes)"
|
|
65
|
-
grep -n -oE '[a-z-]+=[^"'\''> ]' "$SVG_FILE" | head -5 || true
|
|
66
|
-
FAILURES=$((FAILURES + 1))
|
|
67
|
-
fi
|
|
68
|
-
|
|
69
|
-
# Check 3: Unescaped entities in text
|
|
70
|
-
echo -n "Checking text entities... "
|
|
71
|
-
SPECIAL=$(python3 - "$SVG_FILE" <<'PY'
|
|
72
|
-
from pathlib import Path
|
|
73
|
-
import re
|
|
74
|
-
import sys
|
|
75
|
-
|
|
76
|
-
text = Path(sys.argv[1]).read_text(encoding='utf-8')
|
|
77
|
-
issues = 0
|
|
78
|
-
for chunk in re.findall(r'>([^<]*)<', text, flags=re.S):
|
|
79
|
-
cleaned = re.sub(r'&(amp|lt|gt|quot|apos);', '', chunk)
|
|
80
|
-
if '&' in cleaned:
|
|
81
|
-
issues += 1
|
|
82
|
-
print(issues)
|
|
83
|
-
PY
|
|
84
|
-
)
|
|
85
|
-
if [ "$SPECIAL" -eq 0 ]; then
|
|
86
|
-
echo -e "${GREEN}✓ Pass${NC}"
|
|
87
|
-
else
|
|
88
|
-
echo -e "${YELLOW}⚠ Warning${NC} (${SPECIAL} potential unescaped entities)"
|
|
89
|
-
fi
|
|
90
|
-
|
|
91
|
-
# Check 4: Marker references
|
|
92
|
-
echo -n "Checking marker references... "
|
|
93
|
-
MARKER_REFS=$( { grep -oE 'marker-end="url\(#[^)]+\)"' "$SVG_FILE" || true; } | { grep -oE '#[^)]+' || true; } | tr -d '#' | sort -u )
|
|
94
|
-
MARKER_DEFS=$( { grep -oE '<marker id="[^"]+"' "$SVG_FILE" || true; } | { grep -oE 'id="[^"]+"' || true; } | tr -d 'id="' | sort -u )
|
|
95
|
-
|
|
96
|
-
MISSING=0
|
|
97
|
-
for ref in $MARKER_REFS; do
|
|
98
|
-
if ! echo "$MARKER_DEFS" | grep -q "^${ref}$"; then
|
|
99
|
-
echo -e "${RED}✗ Missing marker: $ref${NC}"
|
|
100
|
-
MISSING=$((MISSING + 1))
|
|
101
|
-
fi
|
|
102
|
-
done
|
|
103
|
-
|
|
104
|
-
if [ "$MISSING" -eq 0 ]; then
|
|
105
|
-
echo -e "${GREEN}✓ Pass${NC}"
|
|
106
|
-
else
|
|
107
|
-
echo -e "${RED}✗ Fail${NC} (${MISSING} missing markers)"
|
|
108
|
-
FAILURES=$((FAILURES + 1))
|
|
109
|
-
fi
|
|
110
|
-
|
|
111
|
-
# Check 5: Arrow-component collision
|
|
112
|
-
echo -n "Checking arrow collisions... "
|
|
113
|
-
COLLISIONS=$(python3 - "$SVG_FILE" <<'PY'
|
|
114
|
-
from pathlib import Path
|
|
115
|
-
import re
|
|
116
|
-
import sys
|
|
117
|
-
import xml.etree.ElementTree as ET
|
|
118
|
-
|
|
119
|
-
SVG_NS = {'svg': 'http://www.w3.org/2000/svg'}
|
|
120
|
-
|
|
121
|
-
def strip(tag):
|
|
122
|
-
return tag.split('}', 1)[-1]
|
|
123
|
-
|
|
124
|
-
def to_float(value, default=0.0):
|
|
125
|
-
try:
|
|
126
|
-
return float(value)
|
|
127
|
-
except (TypeError, ValueError):
|
|
128
|
-
return default
|
|
129
|
-
|
|
130
|
-
def is_container_rect(el):
|
|
131
|
-
if el.get('stroke-dasharray'):
|
|
132
|
-
return True
|
|
133
|
-
width = to_float(el.get('width'))
|
|
134
|
-
height = to_float(el.get('height'))
|
|
135
|
-
if width > 700 or height > 500:
|
|
136
|
-
return True
|
|
137
|
-
if width < 70 or height < 30:
|
|
138
|
-
return True
|
|
139
|
-
return False
|
|
140
|
-
|
|
141
|
-
def shape_bounds(el):
|
|
142
|
-
tag = strip(el.tag)
|
|
143
|
-
if tag == 'rect':
|
|
144
|
-
if is_container_rect(el):
|
|
145
|
-
return None
|
|
146
|
-
x = to_float(el.get('x'))
|
|
147
|
-
y = to_float(el.get('y'))
|
|
148
|
-
w = to_float(el.get('width'))
|
|
149
|
-
h = to_float(el.get('height'))
|
|
150
|
-
return (x, y, x + w, y + h)
|
|
151
|
-
if tag == 'circle':
|
|
152
|
-
r = to_float(el.get('r'))
|
|
153
|
-
if r < 20:
|
|
154
|
-
return None
|
|
155
|
-
cx = to_float(el.get('cx'))
|
|
156
|
-
cy = to_float(el.get('cy'))
|
|
157
|
-
return (cx - r, cy - r, cx + r, cy + r)
|
|
158
|
-
if tag == 'ellipse':
|
|
159
|
-
rx = to_float(el.get('rx'))
|
|
160
|
-
ry = to_float(el.get('ry'))
|
|
161
|
-
if rx < 20 or ry < 20:
|
|
162
|
-
return None
|
|
163
|
-
cx = to_float(el.get('cx'))
|
|
164
|
-
cy = to_float(el.get('cy'))
|
|
165
|
-
return (cx - rx, cy - ry, cx + rx, cy + ry)
|
|
166
|
-
return None
|
|
167
|
-
|
|
168
|
-
def parse_path_points(d):
|
|
169
|
-
tokens = re.findall(r'[ML]|-?\d+(?:\.\d+)?', d or '')
|
|
170
|
-
if not tokens:
|
|
171
|
-
return []
|
|
172
|
-
points = []
|
|
173
|
-
command = None
|
|
174
|
-
index = 0
|
|
175
|
-
while index < len(tokens):
|
|
176
|
-
token = tokens[index]
|
|
177
|
-
if token in {'M', 'L'}:
|
|
178
|
-
command = token
|
|
179
|
-
index += 1
|
|
180
|
-
continue
|
|
181
|
-
if command not in {'M', 'L'} or index + 1 >= len(tokens):
|
|
182
|
-
return []
|
|
183
|
-
x = float(tokens[index])
|
|
184
|
-
y = float(tokens[index + 1])
|
|
185
|
-
points.append((x, y))
|
|
186
|
-
index += 2
|
|
187
|
-
return points
|
|
188
|
-
|
|
189
|
-
def segment_hits_bounds(p1, p2, bounds):
|
|
190
|
-
x1, y1 = p1
|
|
191
|
-
x2, y2 = p2
|
|
192
|
-
left, top, right, bottom = bounds
|
|
193
|
-
eps = 1e-6
|
|
194
|
-
|
|
195
|
-
if abs(y1 - y2) < eps:
|
|
196
|
-
y = y1
|
|
197
|
-
if not (top + eps < y < bottom - eps):
|
|
198
|
-
return False
|
|
199
|
-
seg_left = min(x1, x2)
|
|
200
|
-
seg_right = max(x1, x2)
|
|
201
|
-
overlap_left = max(seg_left, left)
|
|
202
|
-
overlap_right = min(seg_right, right)
|
|
203
|
-
if overlap_right - overlap_left <= eps:
|
|
204
|
-
return False
|
|
205
|
-
if abs(overlap_left - x1) < eps or abs(overlap_right - x2) < eps:
|
|
206
|
-
return False
|
|
207
|
-
if abs(overlap_left - x2) < eps or abs(overlap_right - x1) < eps:
|
|
208
|
-
return False
|
|
209
|
-
return True
|
|
210
|
-
|
|
211
|
-
if abs(x1 - x2) < eps:
|
|
212
|
-
x = x1
|
|
213
|
-
if not (left + eps < x < right - eps):
|
|
214
|
-
return False
|
|
215
|
-
seg_top = min(y1, y2)
|
|
216
|
-
seg_bottom = max(y1, y2)
|
|
217
|
-
overlap_top = max(seg_top, top)
|
|
218
|
-
overlap_bottom = min(seg_bottom, bottom)
|
|
219
|
-
if overlap_bottom - overlap_top <= eps:
|
|
220
|
-
return False
|
|
221
|
-
if abs(overlap_top - y1) < eps or abs(overlap_bottom - y2) < eps:
|
|
222
|
-
return False
|
|
223
|
-
if abs(overlap_top - y2) < eps or abs(overlap_bottom - y1) < eps:
|
|
224
|
-
return False
|
|
225
|
-
return True
|
|
226
|
-
|
|
227
|
-
return False
|
|
228
|
-
|
|
229
|
-
root = ET.fromstring(Path(sys.argv[1]).read_text(encoding='utf-8'))
|
|
230
|
-
obstacles = [bounds for element in root.iter() if (bounds := shape_bounds(element)) is not None]
|
|
231
|
-
|
|
232
|
-
collisions = 0
|
|
233
|
-
for element in root.iter():
|
|
234
|
-
tag = strip(element.tag)
|
|
235
|
-
if tag == 'line' and element.get('marker-end'):
|
|
236
|
-
points = [
|
|
237
|
-
(to_float(element.get('x1')), to_float(element.get('y1'))),
|
|
238
|
-
(to_float(element.get('x2')), to_float(element.get('y2'))),
|
|
239
|
-
]
|
|
240
|
-
elif tag == 'path' and element.get('marker-end'):
|
|
241
|
-
points = parse_path_points(element.get('d'))
|
|
242
|
-
else:
|
|
243
|
-
continue
|
|
244
|
-
|
|
245
|
-
for p1, p2 in zip(points, points[1:]):
|
|
246
|
-
if any(segment_hits_bounds(p1, p2, bounds) for bounds in obstacles):
|
|
247
|
-
collisions += 1
|
|
248
|
-
break
|
|
249
|
-
|
|
250
|
-
print(collisions)
|
|
251
|
-
PY
|
|
252
|
-
)
|
|
253
|
-
if [ "$COLLISIONS" -eq 0 ]; then
|
|
254
|
-
echo -e "${GREEN}✓ Pass${NC}"
|
|
255
|
-
else
|
|
256
|
-
echo -e "${RED}✗ Fail${NC} (${COLLISIONS} arrow path collision(s))"
|
|
257
|
-
FAILURES=$((FAILURES + 1))
|
|
258
|
-
fi
|
|
259
|
-
|
|
260
|
-
# Check 6: Closing </svg> tag
|
|
261
|
-
echo -n "Checking closing tag... "
|
|
262
|
-
if grep -q '</svg>' "$SVG_FILE"; then
|
|
263
|
-
echo -e "${GREEN}✓ Pass${NC}"
|
|
264
|
-
else
|
|
265
|
-
echo -e "${RED}✗ Fail${NC} (missing </svg>)"
|
|
266
|
-
FAILURES=$((FAILURES + 1))
|
|
267
|
-
fi
|
|
268
|
-
|
|
269
|
-
# Check 7: rsvg-convert validation
|
|
270
|
-
echo -n "Running rsvg-convert validation... "
|
|
271
|
-
if command -v rsvg-convert &> /dev/null; then
|
|
272
|
-
if rsvg-convert "$SVG_FILE" -o /tmp/test-output.png 2>/dev/null; then
|
|
273
|
-
echo -e "${GREEN}✓ Pass${NC}"
|
|
274
|
-
rm -f /tmp/test-output.png
|
|
275
|
-
else
|
|
276
|
-
echo -e "${RED}✗ Fail${NC}"
|
|
277
|
-
echo "rsvg-convert error:"
|
|
278
|
-
rsvg-convert "$SVG_FILE" -o /tmp/test-output.png 2>&1 || true
|
|
279
|
-
FAILURES=$((FAILURES + 1))
|
|
280
|
-
fi
|
|
281
|
-
else
|
|
282
|
-
echo -e "${YELLOW}⚠ Skipped${NC} (rsvg-convert not found)"
|
|
283
|
-
fi
|
|
284
|
-
|
|
285
|
-
echo "----------------------------------------"
|
|
286
|
-
if [ "$FAILURES" -eq 0 ]; then
|
|
287
|
-
echo "Validation complete"
|
|
288
|
-
exit 0
|
|
289
|
-
fi
|
|
290
|
-
|
|
291
|
-
echo -e "${RED}Validation failed (${FAILURES} error(s))${NC}"
|
|
292
|
-
exit 1
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 700">
|
|
2
|
-
<defs>
|
|
3
|
-
<marker id="arrowBlue" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
|
|
4
|
-
<polygon points="0 0, 10 3.5, 0 7" fill="#2563eb"/>
|
|
5
|
-
</marker>
|
|
6
|
-
<marker id="arrowPurple" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
|
|
7
|
-
<polygon points="0 0, 10 3.5, 0 7" fill="#7c3aed"/>
|
|
8
|
-
</marker>
|
|
9
|
-
<marker id="arrowGreen" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
|
|
10
|
-
<polygon points="0 0, 10 3.5, 0 7" fill="#059669"/>
|
|
11
|
-
</marker>
|
|
12
|
-
<marker id="arrowOrange" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
|
|
13
|
-
<polygon points="0 0, 10 3.5, 0 7" fill="#ea580c"/>
|
|
14
|
-
</marker>
|
|
15
|
-
</defs>
|
|
16
|
-
<style>
|
|
17
|
-
text { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
|
|
18
|
-
.title { font-size: 24px; font-weight: 700; fill: #1e293b; }
|
|
19
|
-
.node-label { font-size: 16px; font-weight: 600; fill: #1e293b; }
|
|
20
|
-
.sub-label { font-size: 13px; font-weight: 400; fill: #64748b; }
|
|
21
|
-
.arrow-label { font-size: 12px; font-weight: 400; fill: #475569; }
|
|
22
|
-
</style>
|
|
23
|
-
<rect width="960" height="700" fill="#ffffff"/>
|
|
24
|
-
<text x="480" y="60" text-anchor="middle" class="title">{{TITLE}}</text>
|
|
25
|
-
<!-- NODES -->
|
|
26
|
-
<!-- ARROWS -->
|
|
27
|
-
<!-- LEGEND -->
|
|
28
|
-
</svg>
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 700">
|
|
2
|
-
<defs>
|
|
3
|
-
<marker id="arrowBlue" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
|
|
4
|
-
<polygon points="0 0, 10 3.5, 0 7" fill="#2563eb"/>
|
|
5
|
-
</marker>
|
|
6
|
-
<marker id="arrowGreen" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
|
|
7
|
-
<polygon points="0 0, 10 3.5, 0 7" fill="#059669"/>
|
|
8
|
-
</marker>
|
|
9
|
-
</defs>
|
|
10
|
-
<style>
|
|
11
|
-
text { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
|
|
12
|
-
.title { font-size: 24px; font-weight: 700; fill: #1e293b; }
|
|
13
|
-
.layer-label { font-size: 16px; font-weight: 600; fill: #475569; }
|
|
14
|
-
.node-label { font-size: 16px; font-weight: 600; fill: #1e293b; }
|
|
15
|
-
.sub-label { font-size: 13px; font-weight: 400; fill: #64748b; }
|
|
16
|
-
.arrow-label { font-size: 12px; font-weight: 400; fill: #475569; }
|
|
17
|
-
</style>
|
|
18
|
-
<rect width="960" height="700" fill="#ffffff"/>
|
|
19
|
-
<text x="480" y="60" text-anchor="middle" class="title">{{TITLE}}</text>
|
|
20
|
-
<!-- NODES -->
|
|
21
|
-
<!-- ARROWS -->
|
|
22
|
-
<!-- LEGEND -->
|
|
23
|
-
</svg>
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 700">
|
|
2
|
-
<style>
|
|
3
|
-
text { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; }
|
|
4
|
-
.title { font-size: 24px; font-weifill: #1e293b; }
|
|
5
|
-
.header { font-size: 14px; font-weight: 600; fill: #1e293b; }
|
|
6
|
-
.row-label { font-size: 13px; font-weight: 500; fill: #475569; }
|
|
7
|
-
.cell-text { font-size: 13px; font-weight: 400; fill: #1e293b; }
|
|
8
|
-
</style>
|
|
9
|
-
<rect width="960" height="700" fill="#ffffff"/>
|
|
10
|
-
<text x="480" y="60" text-anchor="middle" class="title">{{TITLE}}</text>
|
|
11
|
-
<!-- HEADERS -->
|
|
12
|
-
<!-- ROWS -->
|
|
13
|
-
<!-- CELLS -->
|
|
14
|
-
</svg>
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 700">
|
|
2
|
-
<defs>
|
|
3
|
-
<marker id="arrowBlue" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
|
|
4
|
-
<polygon points="0 0, 10 3.5, 0 7" fill="#2563eb"/>
|
|
5
|
-
</marker>
|
|
6
|
-
<marker id="arrowPurple" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
|
|
7
|
-
<polygon points="0 0, 10 3.5, 0 7" fill="#7c3aed"/>
|
|
8
|
-
</marker>
|
|
9
|
-
<marker id="arrowGreen" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
|
|
10
|
-
<polygon points="0 0, 10 3.5, 0 7" fill="#059669"/>
|
|
11
|
-
</marker>
|
|
12
|
-
<marker id="arrowOrange" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
|
|
13
|
-
<polygon points="0 0, 10 3.5, 0 7" fill="#ea580c"/>
|
|
14
|
-
</marker>
|
|
15
|
-
</defs>
|
|
16
|
-
<style>
|
|
17
|
-
text { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
|
|
18
|
-
.title { font-size: 24px; font-weight: 700; fill: #1e293b; }
|
|
19
|
-
.node-label { font-size: 16px; font-weight: 600; fill: #1e293b; }
|
|
20
|
-
.sub-label { font-size: 13px; font-weight: 400; fill: #64748b; }
|
|
21
|
-
.arrow-label { font-size: 12px; font-weight: 400; fill: #475569; }
|
|
22
|
-
</style>
|
|
23
|
-
<rect width="960" height="700" fill="#ffffff"/>
|
|
24
|
-
<text x="480" y="60" text-anchor="middle" class="title">{{TITLE}}</text>
|
|
25
|
-
<!-- NODES -->
|
|
26
|
-
<!-- ARROWS -->
|
|
27
|
-
<!-- LEGEND -->
|
|
28
|
-
</svg>
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 700">
|
|
2
|
-
<defs>
|
|
3
|
-
<marker id="arrowBlue" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
|
|
4
|
-
<polygon points="0 0, 10 3.5, 0 7" fill="#2563eb"/>
|
|
5
|
-
</marker>
|
|
6
|
-
</defs>
|
|
7
|
-
<style>
|
|
8
|
-
text { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; }
|
|
9
|
-
.title { font-size: 24px; font-weight: 700; fill: #1e293b; }
|
|
10
|
-
.entity-name { font-size: 15px; font-weight: 700; fill: #1e293b; }
|
|
11
|
-
.attribute { font-size: 12px; font-weight: 400; fill: #475569; }
|
|
12
|
-
.primary-key { font-size: 12px; font-weight: 600; fill: #1e293b; text-decoration: underline; }
|
|
13
|
-
.relationship { font-size: 12px; font-weight: 500; fill: #64748b; }
|
|
14
|
-
.cardinality { font-size: 11px; font-weight: 400; fill: #64748b; }
|
|
15
|
-
</style>
|
|
16
|
-
<rect width="960" height="700" fill="#ffffff"/>
|
|
17
|
-
<text x="480" y="60" text-anchor="middle" class="title">{{TITLE}}</text>
|
|
18
|
-
<!-- ENTITIES -->
|
|
19
|
-
<!-- RELATIONSHIPS -->
|
|
20
|
-
<!-- CARDINALITY -->
|
|
21
|
-
</svg>
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 700">
|
|
2
|
-
<defs>
|
|
3
|
-
<marker id="arrowBlue" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
|
|
4
|
-
<polygon points="0 0, 10 3.5, 0 7" fill="#2563eb"/>
|
|
5
|
-
</marker>
|
|
6
|
-
</defs>
|
|
7
|
-
<style>
|
|
8
|
-
text { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; }
|
|
9
|
-
.title { font-size: 24px; font-weight: 700; fill: #1e293b; }
|
|
10
|
-
.node-label { font-size: 14px; font-weight: 500; fill: #1e293b; }
|
|
11
|
-
.decision-label { font-size: 13px; font-weight: 500; fill: #1e293b; }
|
|
12
|
-
.arrow-label { font-size: 11px; font-weight: 400; fill: #475569; }
|
|
13
|
-
</style>
|
|
14
|
-
<rect width="960" height="700" fill="#ffffff"/>
|
|
15
|
-
<text x="480" y="60" text-anchor="middle" class="title">{{TITLE}}</text>
|
|
16
|
-
<!-- START -->
|
|
17
|
-
<!-- PROCESSES -->
|
|
18
|
-
<!-- DECISIONS -->
|
|
19
|
-
<!-- ARROWS -->
|
|
20
|
-
<!-- END -->
|
|
21
|
-
</svg>
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 800">
|
|
2
|
-
<defs>
|
|
3
|
-
<marker id="arrowBlue" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
|
|
4
|
-
<polygon points="0 0, 10 3.5, 0 7" fill="#2563eb"/>
|
|
5
|
-
</marker>
|
|
6
|
-
</defs>
|
|
7
|
-
<style>
|
|
8
|
-
text { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; }
|
|
9
|
-
.title { font-size: 24px; font-weight: 700; fill: #1e293b; }
|
|
10
|
-
.participant { font-size: 14px; font-weight: 600; fill: #1e293b; }
|
|
11
|
-
.message { font-size: 12px; font-weight: 400; fill: #475569; }
|
|
12
|
-
.lifeline { stroke: #cbd5e1; stroke-width: 1.5; stroke-dasharray: 5,3; }
|
|
13
|
-
</style>
|
|
14
|
-
<rect width="960" height="800" fill="#ffffff"/>
|
|
15
|
-
<text x="480" y="60" text-anchor="middle" class="title">{{TITLE}}</text>
|
|
16
|
-
<!-- PARTICIPANTS -->
|
|
17
|
-
<!-- LIFELINES -->
|
|
18
|
-
<!-- MESSAGES -->
|
|
19
|
-
<!-- ACTIVATIONS -->
|
|
20
|
-
</svg>
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 700">
|
|
2
|
-
<defs>
|
|
3
|
-
<marker id="arrowBlue" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
|
|
4
|
-
<polygon points="0 0, 10 3.5, 0 7" fill="#2563eb"/>
|
|
5
|
-
</marker>
|
|
6
|
-
</defs>
|
|
7
|
-
<style>
|
|
8
|
-
text { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; }
|
|
9
|
-
.title { font-size: 24px; font-weight: 700; fill: #1e293b; }
|
|
10
|
-
.state-name { font-size: 14px; font-weight: 600; fill: #1e293b; }
|
|
11
|
-
.state-activity { font-size: 11px; font-weight: 400; fill: #64748b; }
|
|
12
|
-
. { font-size: 11px; font-weight: 400; fill: #475569; }
|
|
13
|
-
</style>
|
|
14
|
-
<rect width="960" height="700" fill="#ffffff"/>
|
|
15
|
-
<text x="480" y="60" text-anchor="middle" class="title">{{TITLE}}</text>
|
|
16
|
-
<!-- INITIAL_STATE -->
|
|
17
|
-
<!-- STATES -->
|
|
18
|
-
<!-- TRANSITIONS -->
|
|
19
|
-
<!-- FINAL_STATE -->
|
|
20
|
-
</svg>
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 400">
|
|
2
|
-
<defs>
|
|
3
|
-
<marker id="arrowBlue" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
|
|
4
|
-
<polygon points="0 0, 10 3.5, 0 7" fill="#2563eb"/>
|
|
5
|
-
</marker>
|
|
6
|
-
</defs>
|
|
7
|
-
<style>
|
|
8
|
-
text { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; }
|
|
9
|
-
.title { font-size: 24px; font-weight: 700; fill: #1e293b; }
|
|
10
|
-
.period-label { font-size: 12px; font-weight: 500; fill: #475569; }
|
|
11
|
-
.task-label { font-size: 13px; font-weight: 500; fill: #1e293b; }
|
|
12
|
-
.milestone-label { font-size: 12px; font-weight: 600; fill: #1e293b; }
|
|
13
|
-
</style>
|
|
14
|
-
<rect width="1200" height="400" fill="#ffffff"/>
|
|
15
|
-
<text x="600" y="50" text-anchor="middle" class="title">{{TITLE}}</text>
|
|
16
|
-
<!-- TIME_AXIS -->
|
|
17
|
-
<!-- TASKS -->
|
|
18
|
-
<!-- MILESTONES -->
|
|
19
|
-
</svg>
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 700">
|
|
2
|
-
<defs>
|
|
3
|
-
<marker id="arrowBlue" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
|
|
4
|
-
<polygon points="0 0, 10 3.5, 0 7" fill="#2563eb"/>
|
|
5
|
-
</marker>
|
|
6
|
-
</defs>
|
|
7
|
-
<style>
|
|
8
|
-
text { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; }
|
|
9
|
-
.title { font-size: 24px; font-weight: 700; fill: #1e293b; }
|
|
10
|
-
.actor-label { font-size: 13px; font-weight: 600; fill: #1e293b; }
|
|
11
|
-
.usecaseel { font-size: 13px; font-weight: 500; fill: #1e293b; }
|
|
12
|
-
.system-label { font-size: 16px; font-weight: 600; fill: #475569; }
|
|
13
|
-
.relationship { font-size: 11px; font-weight: 400; fill: #64748b; font-style: italic; }
|
|
14
|
-
</style>
|
|
15
|
-
<rect width="960" height="700" fill="#ffffff"/>
|
|
16
|
-
<text x="480" y="60" text-anchor="middle" class="title">{{TITLE}}</text>
|
|
17
|
-
<!-- SYSTEM_BOUNDARY -->
|
|
18
|
-
<!-- ACTORS -->
|
|
19
|
-
<!-- USECASES -->
|
|
20
|
-
<!-- RELATIONSHIPS -->
|
|
21
|
-
</svg>
|