feat: Add Nanaxe server with Docker, GitHub Actions CI/CD, and auto-deployment
- Add complete server infrastructure with Gitea, API, PostgreSQL - Implement Obsidian-compatible markdown mindmap converter - Add Flutter service for server synchronization - Configure GitHub Actions for automated build and deploy - Add production docker-compose with health checks - Include VPS setup and deployment scripts - Add comprehensive deployment documentation
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
import 'package:reactive_mind_map/reactive_mind_map.dart' as rm;
|
||||
import '../models/mind_map_model.dart';
|
||||
|
||||
/// Адаптер для конвертации MindMapNode в формат reactive_mind_map
|
||||
class MindMapAdapter {
|
||||
/// Конвертирует список MindMapNode в rm.MindMapData для reactive_mind_map
|
||||
static rm.MindMapData nodesToMindMapData(List<MindMapNode> nodes) {
|
||||
if (nodes.isEmpty) {
|
||||
return rm.MindMapData(
|
||||
id: 'empty',
|
||||
title: 'Пустая карта',
|
||||
children: [],
|
||||
);
|
||||
}
|
||||
|
||||
// Находим корневой узел (level 0)
|
||||
final rootNodes = nodes.where((n) => n.level == 0).toList();
|
||||
|
||||
if (rootNodes.isEmpty) {
|
||||
// Если нет корневого узла, создаём его
|
||||
return rm.MindMapData(
|
||||
id: 'auto_root',
|
||||
title: 'Автоматический корень',
|
||||
children: _buildChildren(nodes, null, nodes),
|
||||
);
|
||||
}
|
||||
|
||||
final root = rootNodes.first;
|
||||
return rm.MindMapData(
|
||||
id: root.id,
|
||||
title: root.title,
|
||||
children: _buildChildren(nodes, root.id, nodes),
|
||||
);
|
||||
}
|
||||
|
||||
/// Рекурсивно строит дочерние узлы
|
||||
static List<rm.MindMapData> _buildChildren(
|
||||
List<MindMapNode> allNodes,
|
||||
String? parentId,
|
||||
List<MindMapNode> nodes,
|
||||
) {
|
||||
final children = allNodes.where((n) => n.parentId == parentId).toList();
|
||||
|
||||
return children.map((node) {
|
||||
return rm.MindMapData(
|
||||
id: node.id,
|
||||
title: node.title,
|
||||
children: _buildChildren(allNodes, node.id, nodes),
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
/// Конвертирует rm.MindMapData обратно в список MindMapNode
|
||||
static List<MindMapNode> mindMapDataToNodes(
|
||||
rm.MindMapData data,
|
||||
String projectId, {
|
||||
String? parentId,
|
||||
int level = 0,
|
||||
}) {
|
||||
final nodes = <MindMapNode>[];
|
||||
final now = DateTime.now();
|
||||
|
||||
nodes.add(MindMapNode(
|
||||
id: data.id,
|
||||
projectId: projectId,
|
||||
parentId: parentId,
|
||||
level: level,
|
||||
title: data.title,
|
||||
color: '#2196F3', // Default color, можно улучшить хранить цвет в metadata
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
));
|
||||
|
||||
// Рекурсивно добавляем детей
|
||||
for (final child in data.children!) {
|
||||
nodes.addAll(mindMapDataToNodes(
|
||||
child,
|
||||
projectId,
|
||||
parentId: data.id,
|
||||
level: level + 1,
|
||||
));
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
/// HEX → int (для reactive_mind_map)
|
||||
static int _hexToColorInt(String hex) {
|
||||
hex = hex.replaceAll('#', '');
|
||||
if (hex.length == 6) {
|
||||
return int.parse('FF$hex', radix: 16);
|
||||
}
|
||||
return 0xFF2196F3; // Default blue
|
||||
}
|
||||
|
||||
/// int → HEX (для MindMapNode)
|
||||
static String _colorIntToHex(int color) {
|
||||
return '#${(color & 0xFFFFFF).toRadixString(16).padLeft(6, '0').toUpperCase()}';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user