मैं ने नीपी पैकेज प्रकाशित किया!
परिचय
मैं .. एक net आदमी अंत में मेरे पैरों को मारने के लिए साहस तोड़ दिया nm पैकेज की दुनिया में! इसलिए मैं बहुत खुश हूँ ।
मेकर के लिए कुछ वास्तव में उपयोगी संवादों को बनाने के बाद (अंग्रेजी, पूर्ण प्रकाश बक्से में निर्यात, पीएनजी/SVG, और स्वचालित थीम स्विच करने के लिए निर्यात करें) मैंने निर्णय किया कि यह उन्हें ठीक से पैकेज करने और समाज के साथ साझा करने के लिए समय था। इस पोस्ट में मैं कैसे मैं बनाया। @mostlylucid/mermaid-enhancements एक उत्पादन के रूप में तैयार एनएमएमपी पैकेज.
नोट: अब भी रिलीज पर काम करते रहिए ।
यह पैकेज क्यों?
मैं अब कुछ समय के लिए अपने ब्लॉग पर इन मंचों का उपयोग कर रहा हूँ, और वे जटिल मेरपिक आरेखों के साथ काम करने के लिए आवश्यक हो गया है। विशेषताएँ शामिल हैं:
- इंटरएक्टिव इंटरेक्शन व ज़ूम - बड़े आरेखित करें
- फुलस्क्रीन हल्काबाक्स -ग्रेसिव देखने का अनुभव
- पीएनजी/एसजी में निर्यात करें - उच्च विशेषता डायग्राम डाउनलोड
- प्रसंग स्विचिंग स्वचालित करें - समुद्रीय प्रकाश/ अंध मोड समर्थन
- डिज़ाइन - मोबाइल और डेस्कटॉप पर काम करता है
क्योंकि मैं एक ही कोड की नकल कर रहा था, यह एक उचित एनएमपी पैकेज बनाने के लिए अर्थ रखता था जिसे कोई इस्तेमाल कर सकता था ।
परियोजना स्ट्रक्चर
मैंने टाइप स्क्रिप्ट समर्थन के साथ एक पेशेवर पैकेज ढांचा सेट किया:
mostlylucid-mermaid/
├── src/
│ ├── index.ts # Main entry point
│ ├── enhancements.ts # Pan/zoom/export functionality
│ ├── theme-switcher.ts # Theme switching logic
│ ├── types.ts # TypeScript type definitions
│ └── styles.css # Complete styling
├── examples/
│ └── demo.html # Full-featured demo
├── dist/ # Built output (generated)
├── package.json
├── tsconfig.json
├── README.md
├── QUICKSTART.md
├── PUBLISHING.md
└── LICENSE
पैकेज प्रकार सुरक्षा और बेहतर डेवलपर अनुभव के लिए स्क्रिप्ट प्रयोग करता है, लेकिन अधिकतम संगतता के लिए जावास्क्रिप्ट को सरल करता है.
यु. पू.
यहाँ है कि घटक एक साथ फिट कैसे है:
यह क्या ही अजीब लग रहा है!
तो आप यह बहुत अच्छी तरह से पक्का है और कुछ उपयोगी कार्य है सिर्फ स्थिर आरेखों के अलावा. यह हमेशा मुझे परेशान करता है कि वे पृष्ठ में थे कैसे वे कर रहे थे तो यह एक आसान तरीका लग रहा था आकार कम करने के लिए जब तक लाभ रखने के लिए।
graph TD
A[User Initializes] --> B[init Function]
B --> C[initMermaid]
B --> D[enhanceMermaidDiagrams]
C --> E[Theme Detection]
C --> F[Event Listeners]
C --> G[Mermaid Rendering]
E --> E1[Global State]
E --> E2[LocalStorage]
E --> E3[DOM Class]
E --> E4[OS Preference]
F --> F1[Custom Events]
F --> F2[Media Query]
G --> H[Apply Enhancements]
D --> H
H --> I[Wrap Diagrams]
H --> J[Init Pan/Zoom]
H --> K[Add Controls]
I --> L[Interactive Diagram]
J --> L
K --> L
L --> M[User Interactions]
M --> M1[Zoom In/Out]
M --> M2[Pan]
M --> M3[Fullscreen]
M --> M4[Export PNG/SVG]
style A stroke:#059669,stroke-width:3px,color:#10b981
style L stroke:#2563eb,stroke-width:3px,color:#3b82f6
style M stroke:#7c3aed,stroke-width:3px,color:#8b5cf6
कोर कार्यान्वयन
परिभाषा टाइप करें
प्रथम, मैंने विस्तृत क़िस्म- स्क्रिप्ट क़िस्म पारिभाषित किया:
// src/types.ts
export interface PanZoomInstance {
zoom(scale: number): void;
zoomIn(): void;
zoomOut(): void;
reset(): void;
fit(): void;
center(): void;
resize(): void;
destroy(): void;
isPanEnabled(): boolean;
enablePan(enabled: boolean): void;
}
export type ExportFormat = 'png' | 'svg';
export type Theme = 'dark' | 'default';
export type ControlAction = 'fullscreen' | 'zoomIn' | 'zoomOut' |
'reset' | 'pan' | 'exportPng' | 'exportSvg';
export interface EnhancementConfig {
icons?: IconConfig;
controls?: {
fullscreen?: boolean;
zoom?: boolean;
pan?: boolean;
export?: boolean;
};
}
मुख्य प्रविष्टि बिन्दु
मुख्य प्रविष्टि पाइंट सरल है:
// src/index.ts
export {
enhanceMermaidDiagrams,
cleanupMermaidEnhancements
} from './enhancements.js';
export {
initMermaid
} from './theme-switcher.js';
export async function init() {
await initMermaid();
}
export default {
init,
initMermaid,
enhanceMermaidDiagrams,
};
पैन/बड़ा कार्यान्वयन
विडगेट तर्क को नियंत्रण व प्रारंभ करने के लिए प्रत्येक आरेखित करता है.
// src/enhancements.ts
import svgPanZoom from 'svg-pan-zoom';
import { toPng, toSvg } from 'html-to-image';
const panZoomInstances = new Map();
function initPanZoom(svgElement: SVGElement, diagramId: string) {
// Clean up existing instance if present
if (panZoomInstances.has(diagramId)) {
try {
panZoomInstances.get(diagramId).destroy();
} catch (e) {
console.warn('Failed to destroy existing pan-zoom instance:', e);
}
panZoomInstances.delete(diagramId);
}
try {
const panZoomInstance = svgPanZoom(svgElement, {
zoomEnabled: true,
controlIconsEnabled: false,
fit: true,
center: true,
minZoom: 0.1,
maxZoom: 10,
zoomScaleSensitivity: 0.3,
dblClickZoomEnabled: true,
mouseWheelZoomEnabled: true,
preventMouseEventsDefault: true,
contain: false
});
panZoomInstances.set(diagramId, panZoomInstance);
return panZoomInstance;
} catch (error) {
console.error('Failed to initialize pan-zoom:', error);
return null;
}
}
नियंत्रण बटनों को गतिशील रूप से बनाया गया:
function createControlButtons(container: HTMLElement, diagramId: string) {
if (container.querySelector('.mermaid-controls')) {
return;
}
const controlsDiv = document.createElement('div');
controlsDiv.className = 'mermaid-controls';
const buttons = [
{ icon: 'bx-fullscreen', title: 'Fullscreen', action: 'fullscreen' },
{ icon: 'bx-zoom-in', title: 'Zoom In', action: 'zoomIn' },
{ icon: 'bx-zoom-out', title: 'Zoom Out', action: 'zoomOut' },
{ icon: 'bx-reset', title: 'Reset View', action: 'reset' },
{ icon: 'bx-move', title: 'Pan', action: 'pan' },
{ icon: 'bx-image', title: 'Export as PNG', action: 'exportPng' },
{ icon: 'bx-code-alt', title: 'Export as SVG', action: 'exportSvg' }
];
buttons.forEach(btn => {
const button = document.createElement('button');
button.className = `mermaid-control-btn bx ${btn.icon}`;
button.setAttribute('title', btn.title);
button.setAttribute('aria-label', btn.title);
button.setAttribute('data-action', btn.action);
button.setAttribute('data-diagram-id', diagramId);
controlsDiv.appendChild(button);
});
container.appendChild(controlsDiv);
}
फंक्शन सिंक निर्यात करें
निर्यात कार्यान्वयन एसवीजी क्लोन करता है, दृश्य- बक्से की रक्षा करता है, और एचटीएमएल- आई का प्रयोग करता है:
async function exportDiagram(
container: HTMLElement,
format: ExportFormat,
diagramId: string
) {
try {
const svgElement = container.querySelector('svg');
if (!svgElement) {
console.warn('No diagram found to export');
return;
}
// Clone to avoid modifying the original
const clonedSvg = svgElement.cloneNode(true) as SVGElement;
// Get or calculate viewBox
let viewBox = clonedSvg.getAttribute('viewBox');
if (!viewBox) {
const bbox = svgElement.getBBox();
viewBox = `${bbox.x} ${bbox.y} ${bbox.width} ${bbox.height}`;
clonedSvg.setAttribute('viewBox', viewBox);
}
// Set explicit dimensions for proper export
const [, , vbWidth, vbHeight] = viewBox.split(' ').map(Number);
clonedSvg.setAttribute('width', vbWidth.toString());
clonedSvg.setAttribute('height', vbHeight.toString());
// Remove pan-zoom transforms
clonedSvg.removeAttribute('style');
clonedSvg.style.backgroundColor = 'transparent';
clonedSvg.style.maxWidth = 'none';
// Create temporary container
const tempDiv = document.createElement('div');
tempDiv.style.position = 'absolute';
tempDiv.style.left = '-9999px';
tempDiv.appendChild(clonedSvg);
document.body.appendChild(tempDiv);
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const filename = `mermaid-diagram-${timestamp}`;
if (format === 'png') {
const dataUrl = await toPng(clonedSvg, {
backgroundColor: 'white',
pixelRatio: 2 // Higher quality
});
downloadFile(dataUrl, `${filename}.png`);
} else {
const dataUrl = await toSvg(clonedSvg, {
backgroundColor: 'transparent'
});
downloadFile(dataUrl, `${filename}.svg`);
}
document.body.removeChild(tempDiv);
console.log(`Diagram exported as ${format.toUpperCase()}`);
} catch (error) {
console.error('Failed to export diagram:', error);
}
}
प्रसंग स्विचिंग
प्रसंग स्विचर अनेक जांच विधियों को संभालता है:
// src/theme-switcher.ts
export async function initMermaid() {
// Normalize code fences
normalizeMermaidCodeFences();
const mermaidElements = document.querySelectorAll(elementSelector);
if (mermaidElements.length === 0) return;
await saveOriginalData();
// Set up theme change handlers
const handleDarkThemeSet = async () => {
await resetProcessed();
await loadMermaid('dark');
};
const handleLightThemeSet = async () => {
await resetProcessed();
await loadMermaid('default');
};
// Listen for custom theme events
document.body.addEventListener('dark-theme-set', handleDarkThemeSet);
document.body.addEventListener('light-theme-set', handleLightThemeSet);
// OS theme change listener
if (typeof window.matchMedia === 'function') {
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
mediaQuery.addEventListener('change', async (e) => {
await resetProcessed();
await loadMermaid(e.matches ? 'dark' : 'default');
});
}
// Detect current theme with fallbacks
let isDarkMode = false;
if (typeof window.__themeState !== 'undefined') {
isDarkMode = window.__themeState === 'dark';
} else if (localStorage.theme) {
isDarkMode = localStorage.theme === 'dark';
} else if (document.documentElement.classList.contains('dark')) {
isDarkMode = true;
} else if (window.matchMedia?.('(prefers-color-scheme: dark)').matches) {
isDarkMode = true;
}
await loadMermaid(isDarkMode ? 'dark' : 'default');
}
पैकेज कॉन्फ़िगरेशन
पैकेज.jin
पैकेज. jann अलग उपयोग मामलों के लिए अनेक प्रविष्टि बिन्दु पारिभाषित करता है:
{
"name": "@mostlylucid/mermaid-enhancements",
"version": "1.0.0",
"description": "Enhance Mermaid.js diagrams with interactive pan/zoom, fullscreen lightbox, export to PNG/SVG, and automatic theme switching",
"main": "dist/index.js",
"module": "src/index.ts",
"types": "src/types.ts",
"exports": {
".": {
"types": "./src/types.ts",
"import": "./src/index.ts",
"require": "./dist/index.js"
},
"./min": {
"types": "./dist/index.d.ts",
"import": "./dist/index.min.js",
"require": "./dist/index.min.js"
},
"./styles.css": "./src/styles.css"
},
"unpkg": "dist/index.min.js",
"jsdelivr": "dist/index.min.js",
"scripts": {
"build": "tsc",
"minify": "node scripts/minify.js",
"build:all": "npm run build && npm run minify",
"prepublishOnly": "npm run build:all",
"dev": "cd examples && npx http-server -p 3000 -o"
},
"peerDependencies": {
"mermaid": "^10.0.0 || ^11.0.0"
},
"dependencies": {
"html-to-image": "^1.11.11",
"svg-pan-zoom": "^3.6.1"
}
}
स्क्रिप्ट कॉन्फ़िगरेशन टाइप करें
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"moduleResolution": "node"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "examples"]
}
उपयोग उदाहरण
मूल उपयोग
पैकेज का उपयोग करने के लिए सबसे आसान तरीका:
import mermaid from 'mermaid';
import { init } from '@mostlylucid/mermaid-enhancements';
import '@mostlylucid/mermaid-enhancements/styles.css';
await init();
प्रसंग स्विच के साथ
साइटों के लिए प्रकाश/ गहरे मोड के साथ:
import { init } from '@mostlylucid/mermaid-enhancements';
// Initialize
await init();
// When theme changes
function toggleTheme() {
const isDark = document.body.classList.toggle('dark');
document.documentElement.classList.toggle('dark', isDark);
// Notify the enhancements
const event = new Event(isDark ? 'dark-theme-set' : 'light-theme-set');
document.body.dispatchEvent(event);
}
फिर से सक्रिय करें
import { useEffect } from 'react';
import { init, cleanupMermaidEnhancements } from '@mostlylucid/mermaid-enhancements';
import '@mostlylucid/mermaid-enhancements/styles.css';
function MermaidDiagram({ chart }: { chart: string }) {
useEffect(() => {
init();
return () => cleanupMermaidEnhancements();
}, [chart]);
return (
<div className="mermaid">
{chart}
</div>
);
}
वीएक्स संयोजन
<template>
<div class="mermaid">{{ chart }}</div>
</template>
<script setup>
import { onMounted, onUnmounted } from 'vue';
import { init, cleanupMermaidEnhancements } from '@mostlylucid/mermaid-enhancements';
import '@mostlylucid/mermaid-enhancements/styles.css';
const props = defineProps(['chart']);
onMounted(async () => {
await init();
});
onUnmounted(() => {
cleanupMermaidEnhancements();
});
</script>
डेमो पृष्ठ
मैंने एक व्यापक डेमो पृष्ठ बनाया जो सभी विशेषताओं को दिखाता है:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mermaid Enhancements Demo</title>
<!-- Boxicons for control button icons -->
<link href="https://unpkg.com/[email protected]/css/boxicons.min.css" rel="stylesheet">
<!-- Mermaid Enhancements CSS -->
<link rel="stylesheet" href="../src/styles.css">
</head>
<body>
<!-- Your diagrams -->
<div class="mermaid">
graph TD
A[Start] --> B{Is it working?}
B -->|Yes| C[Great!]
B -->|No| D[Check setup]
C --> E[Zoom & Pan]
D --> F[Read docs]
E --> G[Export to PNG/SVG]
</div>
<!-- Load Mermaid -->
<script type="module">
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
window.mermaid = mermaid;
</script>
<!-- Initialize enhancements -->
<script type="module">
import { init } from '../dist/index.js';
await init();
</script>
</body>
</html>
प्रकाशक प्रक्रिया
यहाँ प्रकाशन कार्य फूल है:
sequenceDiagram
participant Dev as Developer
participant Git as Git Repo
participant NPM as npm Registry
participant CDN as unpkg/jsdelivr
participant User as End User
Dev->>Dev: Write code
Dev->>Dev: npm run build:all
Dev->>Dev: Test locally
Dev->>Git: git commit & push
Dev->>Git: Create version tag
Dev->>NPM: npm login
Dev->>NPM: npm publish --access public
NPM-->>CDN: Sync package
User->>NPM: npm install
User->>CDN: Import from CDN
NPM-->>User: Deliver package
CDN-->>User: Serve files
चरण- दर- स्टेप
- पैकेज बिल्ड करें:
npm run build:all # Compiles TypeScript and minifies
- स्थानीय रूप से जाँचें:
npm run dev # Opens demo at localhost:3000
- संस्करण बम्पेट:
npm version patch # or minor, or major
- प्रकाशन:
npm login
npm publish --access public
यह पैकेज अब इसके द्वारा उपलब्ध है:
- हाँ :
npm install @mostlylucid/mermaid-enhancements - अनसब्सक्राइब नहीं
https://unpkg.com/@mostlylucid/mermaid-enhancements - एसएसएल- सीडीएन:
https://cdn.jsdelivr.net/npm/@mostlylucid/mermaid-enhancements
न्यूनतमीकरण कौशल
मैंने खाली करने के लिए स्क्रिप्ट को जोड़ा है-स्तर आकार को कम करने के लिए:
// scripts/minify.js
const { minify } = require('terser');
const fs = require('fs');
const path = require('path');
async function minifyFile(inputPath, outputPath) {
const code = fs.readFileSync(inputPath, 'utf8');
const result = await minify(code, {
compress: {
dead_code: true,
drop_console: false,
drop_debugger: true,
keep_classnames: true,
keep_fnames: true,
},
mangle: {
keep_classnames: true,
keep_fnames: true,
},
format: {
comments: false,
},
});
fs.writeFileSync(outputPath, result.code);
const originalSize = fs.statSync(inputPath).size;
const minifiedSize = fs.statSync(outputPath).size;
const reduction = ((1 - minifiedSize / originalSize) * 100).toFixed(1);
console.log(`✓ ${path.basename(outputPath)}: ${originalSize} → ${minifiedSize} bytes (${reduction}% smaller)`);
}
// Minify main bundle
minifyFile(
path.join(__dirname, '../dist/index.js'),
path.join(__dirname, '../dist/index.min.js')
);
परिणाम:
- नियमित: 23.46 केबी
- न्यूनतम: 9.78 कि.8% कटौती!)
दस्तावेज़ीकरण
मैंने विस्तृत दस्तावेजों को बनाया है:
- पढ़ें. - पूरा एपीआई संदर्भ, उदाहरण, परेशानीएं
- QUICKICKT - 5-Ret मार्गदर्शन शुरू हो रही है
- PUBELPING. - एनएम प्रकाशन निर्देश
- विस्फोटक.med - संस्करण इतिहास
स्टाइलिंग
सीएसएस पूरी तरह से प्रतिक्रिया दे रहा है तथा काला मोड का समर्थन करता है:
/* Diagram wrapper */
.mermaid-wrapper {
position: relative;
border-radius: 0.5rem;
overflow: hidden;
width: 100%;
margin: 1rem 0;
}
/* Control buttons */
.mermaid-controls {
position: absolute;
top: 0.5rem;
right: 0.5rem;
display: flex;
gap: 0.25rem;
z-index: 10;
background: rgba(255, 255, 255, 0.9);
border-radius: 0.5rem;
padding: 0.25rem;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.dark .mermaid-controls {
background: rgba(31, 41, 55, 0.95);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
/* Individual buttons */
.mermaid-control-btn {
padding: 0.5rem;
border-radius: 0.25rem;
cursor: pointer;
transition: all 0.2s;
background: transparent;
border: none;
color: #4b5563;
font-size: 1.25rem;
}
.mermaid-control-btn:hover {
background: rgba(37, 99, 235, 0.1);
color: #2563eb;
transform: scale(1.1);
}
सबक
1. प्रकार स्क्रिप्ट के मूल्य के लिए यह योग्य है.
एक छोटी लाइब्रेरी के लिए भी, स्क्रिप्ट ने विकास के दौरान कई बग स्क्रिप्ट पकड़ा और उपभोक्ताओं के लिए उत्कृष्ट आईडीई समर्थन प्रदान किया.
2. बहु प्रविष्टि बिन्दु तत्व
दोनों को समर्थित करता है import और require, प्लस एक न्यूनतम संस्करण, पैकेज अधिक उपयोगी बनाता है:
"exports": {
".": {
"types": "./src/types.ts",
"import": "./src/index.ts",
"require": "./dist/index.js"
},
"./min": {
"import": "./dist/index.min.js"
}
}
3 डेमो ज़रूरी है
डेमो पृष्ठ ने मुझे बग पकड़ने और जीवित दस्तावेज़ों के रूप में सेवा करने में मदद की. उपयोक्ता वास्तव में देख सकते हैं कि यह कैसे काम करता है.
4 साफ किया जाना ज़रूरी है
मेमोरी प्रबंधन के लिए हमेशा साफ फंक्शन प्रदान करें:
export function cleanupMermaidEnhancements() {
panZoomInstances.forEach((instance, id) => {
try {
instance.destroy();
} catch (e) {
console.warn(`Failed to destroy pan-zoom instance ${id}:`, e);
}
});
panZoomInstances.clear();
}
प्रसंग पता लगाना Faces की जरूरत है
अलग साइट प्रसंगों को अलग अलग से संभालता है, इसलिए मैंने बहुत सी जांच विधियों को लागू किया:
- वैश्विक स्थिति (c)
window.__themeState) - स्थानीय- स्कैन (S)
localStorage.theme) - डोम वर्ग (e)
document.documentElement.classList) - ओएस प्राथमिकताएँ (e)
prefers-color-scheme)
परफ़ॉर्मेंस पर ध्यान दें
यह पैकेज प्रदर्शन के लिए न्यूनतम किया गया है:
- घटना डेलिगेशन - सभी नियंत्रण बटनों के लिए एक कार्यक्रम श्रोता
- ला zizance. kgm - केवल जब आवश्यक हो, फ्लैश/जोम केवल प्रारंभ होता है
- उदाहरण साफ - सही मेमोरी प्रबंधन
- न्यूनतम री- स्केल्स - थीम बदलने पर सिर्फ आरेख
- अतिप्रयोगक संचालन - उपयोग
requestAnimationFrameआरामदेह एनीमेशन के लिए
ब्राउज़र समर्थन
जाँच तथा पर काम करने पर:
- क्रोमेपेज (लाइन)
- फ़ायरफ़ॉक्स (अंलेट)
- सफर्री (बीच में)
- मोबाइल ब्राउज़र (यूओएस वेब साइट्री, क्रोमा मोबाइल)
भविष्य संवर्द्धन
भविष्य के अनुवादों के लिए विचार:
- कॉन्फ़िगर करने योग्य कंट्रोल बटन प्रतीक ( फ़ॉन्ट विशाल, भौतिक प्रतीकों के लिए समर्थन)
- [ कुंजीपट शॉर्टकट (जैसे कि. g, ज़ूम के लिए कंट्रोल+plus)
- [ मोबाइल पर प्रदर्शित बाहरी चिह्नों को छूता है (बगंब से जूम करने के लिए)
- आरेख स्रोत कोड बटन नक़ल करें
- [ डायग्राम यूआरएल विशेषता साझा करें
- [ [ रेखाचित्र]
- बहु निर्यात फॉर्मेट (पीडीएफ़, जेपीईजी)
कंटेनमेंट
यह पैकेज अब है:
- टाइप स्क्रिप्ट के साथ प्रकार
- अच्छा विवरणित
- उपयोग के लिए आसान
- उत्पादीय- प्रसंग
- फ्रेमवर्क- सेचुइन्सिक
- पूरी तरह परखा गया
आप अपने प्रोजेक्ट में मेकर का उपयोग कर रहे हैं, यह एक प्रयास करो!
संसाधन
- Git रेपोसिटरी: अधिकतर अल्पपारदर्शिता/ सबसे ज्यादा जर्दी
- एनएमएम पैकेज: @ action: button ( जल्द ही आ रहा है)
- डेमो: डेमो लाइव ( जल्द ही आ रहा है)