🎯 MapView v2.0 - Global Deployment Ready

 MAJOR FEATURES:
• Auto-zoom intelligence với smart bounds fitting
• Enhanced 3D GPS markers với pulsing effects
• Professional route display với 6-layer rendering
• Status-based parking icons với availability indicators
• Production-ready build optimizations

🗺️ AUTO-ZOOM FEATURES:
• Smart bounds fitting cho GPS + selected parking
• Adaptive padding (50px) cho visual balance
• Max zoom control (level 16) để tránh quá gần
• Dynamic centering khi không có selection

🎨 ENHANCED VISUALS:
• 3D GPS marker với multi-layer pulse effects
• Advanced parking icons với status colors
• Selection highlighting với animation
• Dimming system cho non-selected items

🛣️ ROUTE SYSTEM:
• OpenRouteService API integration
• Multi-layer route rendering (glow, shadow, main, animated)
• Real-time distance & duration calculation
• Visual route info trong popup

📱 PRODUCTION READY:
• SSR safe với dynamic imports
• Build errors resolved
• Global deployment via Vercel
• Optimized performance

🌍 DEPLOYMENT:
• Vercel: https://whatever-ctk2auuxr-phong12hexdockworks-projects.vercel.app
• Bundle size: 22.8 kB optimized
• Global CDN distribution
• HTTPS enabled

💾 VERSION CONTROL:
• MapView-v2.0.tsx backup created
• MAPVIEW_VERSIONS.md documentation
• Full version history tracking
This commit is contained in:
2025-07-20 19:52:16 +07:00
parent 3203463a6a
commit c65cc97a33
64624 changed files with 7199453 additions and 6462 deletions

View File

@@ -0,0 +1,15 @@
import { Tree } from '@angular-devkit/schematics';
export declare enum NodeDependencyType {
Default = "dependencies",
Dev = "devDependencies",
Peer = "peerDependencies",
Optional = "optionalDependencies"
}
export interface NodeDependency {
type: NodeDependencyType;
name: string;
version: string;
overwrite?: boolean;
}
export declare function addPackageJsonDependency(tree: Tree, dependency: NodeDependency, pkgJsonPath?: string): void;
export declare function getPackageJsonDependency(tree: Tree, name: string, pkgJsonPath?: string): NodeDependency | null;

View File

@@ -0,0 +1,42 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NodeDependencyType = void 0;
exports.addPackageJsonDependency = addPackageJsonDependency;
exports.getPackageJsonDependency = getPackageJsonDependency;
const json_file_util_1 = require("./json-file.util");
const PKG_JSON_PATH = '/package.json';
var NodeDependencyType;
(function (NodeDependencyType) {
NodeDependencyType["Default"] = "dependencies";
NodeDependencyType["Dev"] = "devDependencies";
NodeDependencyType["Peer"] = "peerDependencies";
NodeDependencyType["Optional"] = "optionalDependencies";
})(NodeDependencyType || (exports.NodeDependencyType = NodeDependencyType = {}));
const ALL_DEPENDENCY_TYPE = [
NodeDependencyType.Default,
NodeDependencyType.Dev,
NodeDependencyType.Optional,
NodeDependencyType.Peer,
];
function addPackageJsonDependency(tree, dependency, pkgJsonPath = PKG_JSON_PATH) {
const json = new json_file_util_1.JSONFile(tree, pkgJsonPath);
const { overwrite, type, name, version } = dependency;
const path = [type, name];
if (overwrite || !json.get(path)) {
json.modify(path, version);
}
}
function getPackageJsonDependency(tree, name, pkgJsonPath = PKG_JSON_PATH) {
const json = new json_file_util_1.JSONFile(tree, pkgJsonPath);
for (const depType of ALL_DEPENDENCY_TYPE) {
const version = json.get([depType, name]);
if (typeof version === 'string') {
return {
type: depType,
name: name,
version,
};
}
}
return null;
}

View File

@@ -0,0 +1 @@
export declare function normalizeToKebabOrSnakeCase(str: string): string;

View File

@@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.normalizeToKebabOrSnakeCase = normalizeToKebabOrSnakeCase;
function normalizeToKebabOrSnakeCase(str) {
const STRING_DASHERIZE_REGEXP = /\s/g;
const STRING_DECAMELIZE_REGEXP = /([a-z\d])([A-Z])/g;
return str
?.trim()
?.replace(STRING_DECAMELIZE_REGEXP, '$1-$2')
?.toLowerCase()
?.replace(STRING_DASHERIZE_REGEXP, '-');
}

View File

@@ -0,0 +1,9 @@
export * from './metadata.manager';
export * from './module-import.declarator';
export * from './module-metadata.declarator';
export * from './module.declarator';
export * from './module.finder';
export * from './name.parser';
export * from './path.solver';
export * from './source-root.helpers';
export * from './formatting';

View File

@@ -0,0 +1,25 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
__exportStar(require("./metadata.manager"), exports);
__exportStar(require("./module-import.declarator"), exports);
__exportStar(require("./module-metadata.declarator"), exports);
__exportStar(require("./module.declarator"), exports);
__exportStar(require("./module.finder"), exports);
__exportStar(require("./name.parser"), exports);
__exportStar(require("./path.solver"), exports);
__exportStar(require("./source-root.helpers"), exports);
__exportStar(require("./formatting"), exports);

View File

@@ -0,0 +1,15 @@
import { JsonValue } from '@angular-devkit/core';
import { Tree } from '@angular-devkit/schematics';
export type InsertionIndex = (properties: string[]) => number;
export type JSONPath = (string | number)[];
export declare class JSONFile {
private readonly host;
private readonly path;
content: string;
constructor(host: Tree, path: string);
private _jsonAst;
private get JsonAst();
get(jsonPath: JSONPath): unknown;
modify(jsonPath: JSONPath, value: JsonValue | undefined, insertInOrder?: InsertionIndex | false): void;
remove(jsonPath: JSONPath): void;
}

View File

@@ -0,0 +1,68 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.JSONFile = void 0;
const jsonc_parser_1 = require("jsonc-parser");
class JSONFile {
constructor(host, path) {
this.host = host;
this.path = path;
const buffer = this.host.read(this.path);
if (buffer) {
this.content = buffer.toString();
}
else {
throw new Error(`Could not read '${path}'.`);
}
}
get JsonAst() {
if (this._jsonAst) {
return this._jsonAst;
}
const errors = [];
this._jsonAst = (0, jsonc_parser_1.parseTree)(this.content, errors, {
allowTrailingComma: true,
});
if (errors.length) {
const { error, offset } = errors[0];
throw new Error(`Failed to parse "${this.path}" as JSON AST Object. ${(0, jsonc_parser_1.printParseErrorCode)(error)} at location: ${offset}.`);
}
return this._jsonAst;
}
get(jsonPath) {
const jsonAstNode = this.JsonAst;
if (!jsonAstNode) {
return undefined;
}
if (jsonPath.length === 0) {
return (0, jsonc_parser_1.getNodeValue)(jsonAstNode);
}
const node = (0, jsonc_parser_1.findNodeAtLocation)(jsonAstNode, jsonPath);
return node === undefined ? undefined : (0, jsonc_parser_1.getNodeValue)(node);
}
modify(jsonPath, value, insertInOrder) {
let getInsertionIndex;
if (insertInOrder === undefined) {
const property = jsonPath.slice(-1)[0];
getInsertionIndex = (properties) => [...properties, property].sort().findIndex((p) => p === property);
}
else if (insertInOrder !== false) {
getInsertionIndex = insertInOrder;
}
const edits = (0, jsonc_parser_1.modify)(this.content, jsonPath, value, {
getInsertionIndex,
formattingOptions: {
insertSpaces: true,
tabSize: 2,
},
});
this.content = (0, jsonc_parser_1.applyEdits)(this.content, edits);
this.host.overwrite(this.path, this.content);
this._jsonAst = undefined;
}
remove(jsonPath) {
if (this.get(jsonPath) !== undefined) {
this.modify(jsonPath, undefined);
}
}
}
exports.JSONFile = JSONFile;

View File

@@ -0,0 +1,13 @@
import { DeclarationOptions } from './module.declarator';
export declare class MetadataManager {
private content;
constructor(content: string);
insert(metadata: string, symbol: string, staticOptions?: DeclarationOptions['staticOptions']): string | undefined;
private findFirstDecoratorMetadata;
private getSourceNodes;
private insertMetadataToEmptyModuleDecorator;
private insertNewMetadataToDecorator;
private insertSymbolToMetadata;
private mergeSymbolAndExpr;
private addBlankLines;
}

View File

@@ -0,0 +1,174 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MetadataManager = void 0;
const typescript_1 = require("typescript");
class MetadataManager {
constructor(content) {
this.content = content;
}
insert(metadata, symbol, staticOptions) {
const source = (0, typescript_1.createSourceFile)('filename.ts', this.content, typescript_1.ScriptTarget.ES2017);
const moduleDecoratorNode = this.findFirstDecoratorMetadata(source, 'Module');
if (!moduleDecoratorNode) {
return;
}
const matchingProperties = moduleDecoratorNode.properties
.filter((prop) => prop.kind === typescript_1.SyntaxKind.PropertyAssignment)
.filter((prop) => {
const name = prop.name;
switch (name.kind) {
case typescript_1.SyntaxKind.Identifier:
return name.getText(source) === metadata;
case typescript_1.SyntaxKind.StringLiteral:
return name.text === metadata;
default:
return false;
}
});
symbol = this.mergeSymbolAndExpr(symbol, staticOptions);
const addBlankLinesIfDynamic = () => {
symbol = staticOptions ? this.addBlankLines(symbol) : symbol;
};
if (matchingProperties.length === 0) {
const expr = moduleDecoratorNode;
if (expr.properties.length === 0) {
addBlankLinesIfDynamic();
return this.insertMetadataToEmptyModuleDecorator(expr, metadata, symbol);
}
else {
addBlankLinesIfDynamic();
return this.insertNewMetadataToDecorator(expr, source, metadata, symbol);
}
}
else {
return this.insertSymbolToMetadata(source, matchingProperties, symbol, staticOptions);
}
}
findFirstDecoratorMetadata(source, identifier) {
for (const node of this.getSourceNodes(source)) {
const isDecoratorFactoryNode = node.kind === typescript_1.SyntaxKind.Decorator &&
node.expression.kind === typescript_1.SyntaxKind.CallExpression;
if (!isDecoratorFactoryNode)
continue;
const expr = node.expression;
const isExpectedExpression = expr.arguments[0]?.kind === typescript_1.SyntaxKind.ObjectLiteralExpression;
if (!isExpectedExpression)
continue;
if (expr.expression.kind === typescript_1.SyntaxKind.Identifier) {
const escapedText = expr.expression.escapedText;
const isTargetIdentifier = escapedText
? escapedText.toLowerCase() === identifier.toLowerCase()
: true;
if (isTargetIdentifier) {
return expr.arguments[0];
}
}
}
}
getSourceNodes(sourceFile) {
const nodes = [sourceFile];
const result = [];
while (nodes.length > 0) {
const node = nodes.shift();
if (node) {
result.push(node);
if (node.getChildCount(sourceFile) >= 0) {
nodes.unshift(...node.getChildren(sourceFile));
}
}
}
return result;
}
insertMetadataToEmptyModuleDecorator(expr, metadata, symbol) {
const position = expr.getEnd() - 1;
const toInsert = ` ${metadata}: [${symbol}]`;
return this.content.split('').reduce((content, char, index) => {
if (index === position) {
return `${content}\n${toInsert}\n${char}`;
}
else {
return `${content}${char}`;
}
}, '');
}
insertNewMetadataToDecorator(expr, source, metadata, symbol) {
const node = expr.properties[expr.properties.length - 1];
const position = node.getEnd();
const text = node.getFullText(source);
const matches = text.match(/^\r?\n\s*/);
let toInsert;
if (matches) {
toInsert = `,${matches[0]}${metadata}: [${symbol}]`;
}
else {
toInsert = `, ${metadata}: [${symbol}]`;
}
return this.content.split('').reduce((content, char, index) => {
if (index === position) {
return `${content}${toInsert}${char}`;
}
else {
return `${content}${char}`;
}
}, '');
}
insertSymbolToMetadata(source, matchingProperties, symbol, staticOptions) {
const assignment = matchingProperties[0];
let node;
const arrLiteral = assignment.initializer;
if (!arrLiteral.elements) {
return this.content;
}
if (arrLiteral.elements.length === 0) {
node = arrLiteral;
}
else {
node = arrLiteral.elements;
}
if (Array.isArray(node)) {
const nodeArray = node;
const symbolsArray = nodeArray.map((childNode) => childNode.getText(source));
if (symbolsArray.includes(symbol)) {
return this.content;
}
node = node[node.length - 1];
}
let toInsert;
let position = node.getEnd();
if (node.kind === typescript_1.SyntaxKind.ArrayLiteralExpression) {
position--;
toInsert = staticOptions ? this.addBlankLines(symbol) : `${symbol}`;
}
else {
const text = node.getFullText(source);
const itemSeparator = (text.match(/^\r?\n(\r?)\s+/) ||
text.match(/^\r?\n/) ||
' ')[0];
toInsert = `,${itemSeparator}${symbol}`;
}
return this.content.split('').reduce((content, char, index) => {
if (index === position) {
return `${content}${toInsert}${char}`;
}
else {
return `${content}${char}`;
}
}, '');
}
mergeSymbolAndExpr(symbol, staticOptions) {
if (!staticOptions) {
return symbol;
}
const spacing = 6;
let options = JSON.stringify(staticOptions.value, null, spacing);
options = options.replace(/\"([^(\")"]+)\":/g, '$1:');
options = options.replace(/\"/g, `'`);
options = options.slice(0, options.length - 1) + ' }';
symbol += `.${staticOptions.name}(${options})`;
return symbol;
}
addBlankLines(expr) {
return `\n ${expr}\n `;
}
}
exports.MetadataManager = MetadataManager;

View File

@@ -0,0 +1,10 @@
import { DeclarationOptions } from './module.declarator';
import { PathSolver } from './path.solver';
export declare class ModuleImportDeclarator {
private solver;
constructor(solver?: PathSolver);
declare(content: string, options: DeclarationOptions): string;
private findImportsEndpoint;
private buildLineToInsert;
private computeRelativePath;
}

View File

@@ -0,0 +1,39 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ModuleImportDeclarator = void 0;
const core_1 = require("@angular-devkit/core");
const path_solver_1 = require("./path.solver");
class ModuleImportDeclarator {
constructor(solver = new path_solver_1.PathSolver()) {
this.solver = solver;
}
declare(content, options) {
const toInsert = this.buildLineToInsert(options);
const contentLines = content.split('\n');
const finalImportIndex = this.findImportsEndpoint(contentLines);
contentLines.splice(finalImportIndex + 1, 0, toInsert);
return contentLines.join('\n');
}
findImportsEndpoint(contentLines) {
const reversedContent = Array.from(contentLines).reverse();
const reverseImports = reversedContent.filter(line => line.match(/\} from ('|")/));
if (reverseImports.length <= 0) {
return 0;
}
return contentLines.indexOf(reverseImports[0]);
}
buildLineToInsert(options) {
return `import { ${options.symbol} } from '${this.computeRelativePath(options)}';`;
}
computeRelativePath(options) {
let importModulePath;
if (options.type !== undefined) {
importModulePath = (0, core_1.normalize)(`/${options.path}/${options.name}.${options.type}`);
}
else {
importModulePath = (0, core_1.normalize)(`/${options.path}/${options.name}`);
}
return this.solver.relative(options.module, importModulePath);
}
}
exports.ModuleImportDeclarator = ModuleImportDeclarator;

View File

@@ -0,0 +1,4 @@
import { DeclarationOptions } from './module.declarator';
export declare class ModuleMetadataDeclarator {
declare(content: string, options: DeclarationOptions): string;
}

View File

@@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ModuleMetadataDeclarator = void 0;
const metadata_manager_1 = require("./metadata.manager");
class ModuleMetadataDeclarator {
declare(content, options) {
const manager = new metadata_manager_1.MetadataManager(content);
const inserted = manager.insert(options.metadata, options.symbol, options.staticOptions);
return inserted ?? content;
}
}
exports.ModuleMetadataDeclarator = ModuleMetadataDeclarator;

View File

@@ -0,0 +1,23 @@
import { Path } from '@angular-devkit/core';
import { ModuleImportDeclarator } from './module-import.declarator';
import { ModuleMetadataDeclarator } from './module-metadata.declarator';
export interface DeclarationOptions {
metadata: string;
type?: string;
name: string;
className?: string;
path: Path;
module: Path;
symbol?: string;
staticOptions?: {
name: string;
value: Record<string, any>;
};
}
export declare class ModuleDeclarator {
private imports;
private metadata;
constructor(imports?: ModuleImportDeclarator, metadata?: ModuleMetadataDeclarator);
declare(content: string, options: DeclarationOptions): string;
private computeSymbol;
}

View File

@@ -0,0 +1,32 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ModuleDeclarator = void 0;
const strings_1 = require("@angular-devkit/core/src/utils/strings");
const module_import_declarator_1 = require("./module-import.declarator");
const module_metadata_declarator_1 = require("./module-metadata.declarator");
class ModuleDeclarator {
constructor(imports = new module_import_declarator_1.ModuleImportDeclarator(), metadata = new module_metadata_declarator_1.ModuleMetadataDeclarator()) {
this.imports = imports;
this.metadata = metadata;
}
declare(content, options) {
options = this.computeSymbol(options);
content = this.imports.declare(content, options);
content = this.metadata.declare(content, options);
return content;
}
computeSymbol(options) {
const target = Object.assign({}, options);
if (options.className) {
target.symbol = options.className;
}
else if (options.type !== undefined) {
target.symbol = (0, strings_1.classify)(options.name).concat((0, strings_1.capitalize)(options.type));
}
else {
target.symbol = (0, strings_1.classify)(options.name);
}
return target;
}
}
exports.ModuleDeclarator = ModuleDeclarator;

View File

@@ -0,0 +1,13 @@
import { Path } from '@angular-devkit/core';
import { Tree } from '@angular-devkit/schematics';
export interface FindOptions {
name?: string;
path: Path;
kind?: string;
}
export declare class ModuleFinder {
private tree;
constructor(tree: Tree);
find(options: FindOptions): Path | null;
private findIn;
}

View File

@@ -0,0 +1,24 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ModuleFinder = void 0;
const core_1 = require("@angular-devkit/core");
class ModuleFinder {
constructor(tree) {
this.tree = tree;
}
find(options) {
const generatedDirectoryPath = options.path;
const generatedDirectory = this.tree.getDir(generatedDirectoryPath);
return this.findIn(generatedDirectory);
}
findIn(directory) {
if (!directory) {
return null;
}
const moduleFilename = directory.subfiles.find(filename => /\.module\.(t|j)s$/.test(filename));
return moduleFilename !== undefined
? (0, core_1.join)(directory.path, moduleFilename.valueOf())
: this.findIn(directory.parent);
}
}
exports.ModuleFinder = ModuleFinder;

View File

@@ -0,0 +1,12 @@
import { Path } from '@angular-devkit/core';
export interface ParseOptions {
name: string;
path?: string;
}
export interface Location {
name: string;
path: Path;
}
export declare class NameParser {
parse(options: ParseOptions): Location;
}

View File

@@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NameParser = void 0;
const core_1 = require("@angular-devkit/core");
class NameParser {
parse(options) {
const nameWithoutPath = (0, core_1.basename)(options.name);
const namePath = (0, core_1.dirname)((options.path === undefined ? '' : options.path)
.concat('/')
.concat(options.name));
return {
name: nameWithoutPath,
path: (0, core_1.normalize)('/'.concat(namePath)),
};
}
}
exports.NameParser = NameParser;

View File

@@ -0,0 +1,4 @@
import { Path } from '@angular-devkit/core';
export declare class PathSolver {
relative(from: Path, to: Path): string;
}

View File

@@ -0,0 +1,14 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PathSolver = void 0;
const core_1 = require("@angular-devkit/core");
class PathSolver {
relative(from, to) {
const placeholder = '/placeholder';
const relativeDir = (0, core_1.relative)((0, core_1.dirname)((placeholder + from)), (0, core_1.dirname)((placeholder + to)));
return (relativeDir.startsWith('.')
? relativeDir
: './' + relativeDir).concat(relativeDir.length === 0 ? (0, core_1.basename)(to) : '/' + (0, core_1.basename)(to));
}
}
exports.PathSolver = PathSolver;

View File

@@ -0,0 +1,6 @@
import { Rule, Tree } from '@angular-devkit/schematics';
export declare function isInRootDirectory(host: Tree, extraFiles?: string[]): boolean;
export declare function mergeSourceRoot<T extends {
sourceRoot?: string;
path?: string;
} = any>(options: T): Rule;

View File

@@ -0,0 +1,24 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isInRootDirectory = isInRootDirectory;
exports.mergeSourceRoot = mergeSourceRoot;
const core_1 = require("@angular-devkit/core");
const defaults_1 = require("../lib/defaults");
function isInRootDirectory(host, extraFiles = []) {
const files = ['nest-cli.json', 'nest.json'].concat(extraFiles || []);
return files.map(file => host.exists(file)).some(isPresent => isPresent);
}
function mergeSourceRoot(options) {
return (host) => {
const isInRoot = isInRootDirectory(host, ['tsconfig.json', 'package.json']);
if (!isInRoot) {
return host;
}
const defaultSourceRoot = options.sourceRoot !== undefined ? options.sourceRoot : defaults_1.DEFAULT_PATH_NAME;
options.path =
options.path !== undefined
? (0, core_1.join)((0, core_1.normalize)(defaultSourceRoot), options.path)
: (0, core_1.normalize)(defaultSourceRoot);
return host;
};
}