@appaflytech/zeyrek-ai-mcp 0.0.21 → 0.0.23
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/dist/config.js +2 -0
- package/dist/knowledge/componentCatalog.js +6 -4
- package/dist/knowledge/componentEvents.js +12 -5
- package/dist/knowledge/mobileComponentCatalog.js +628 -0
- package/dist/knowledge/mobileComponentEvents.js +110 -0
- package/dist/knowledge/normalize.js +52 -11
- package/dist/knowledge/platform/lint.js +205 -0
- package/dist/knowledge/platform/mobile.js +78 -0
- package/dist/knowledge/platform/mobileRules.js +126 -0
- package/dist/knowledge/platform/mobileTabs.js +108 -0
- package/dist/knowledge/platform/profile.js +20 -0
- package/dist/knowledge/platform/resolve.js +122 -0
- package/dist/knowledge/platform/web.js +38 -0
- package/dist/knowledge/rules.js +56 -12
- package/dist/knowledge/styleResolve.js +1 -1
- package/dist/knowledge/styleResolveNative.js +410 -0
- package/dist/knowledge/themeResolve.js +3 -3
- package/dist/platform/capture/actions.js +333 -0
- package/dist/platform/capture/browser.js +1 -0
- package/dist/platform/{screenshot.js → capture/capture.js} +23 -509
- package/dist/platform/capture/index.js +10 -0
- package/dist/platform/capture/readiness.js +103 -0
- package/dist/platform/capture/summary.js +77 -0
- package/dist/platform/capture/target.js +5 -0
- package/dist/platform/capture/targets/studio-mobile.js +15 -0
- package/dist/platform/capture/targets/studio-web.js +5 -0
- package/dist/platform/domSummary.js +1 -1
- package/dist/resources/examples/mobile-app-shell-drawer.json +209 -0
- package/dist/resources/examples/mobile-app-shell-stack.json +123 -0
- package/dist/resources/examples/mobile-app-shell-tab.json +174 -0
- package/dist/resources/examples/mobile-list-detail-form.json +656 -0
- package/dist/resources/guides/component.md +6 -1
- package/dist/resources/guides/functions.md +1 -1
- package/dist/resources/guides/layout.md +11 -7
- package/dist/resources/guides/mobile.md +283 -0
- package/dist/resources/guides/page.md +69 -16
- package/dist/resources/guides/translation.md +1 -1
- package/dist/server.js +2 -0
- package/dist/tools/applications.js +60 -3
- package/dist/tools/components.js +50 -10
- package/dist/tools/designSchemaPatch.js +13 -4
- package/dist/tools/externalComponents.js +25 -4
- package/dist/tools/flows.js +9 -2
- package/dist/tools/layouts.js +41 -9
- package/dist/tools/mobile.js +203 -0
- package/dist/tools/pages.js +115 -35
- package/dist/tools/platformInfo.js +2 -1
- package/dist/tools/profileWrite.js +45 -0
- package/dist/tools/screenWrite.js +2 -2
- package/dist/tools/screens.js +9 -3
- package/package.json +1 -1
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kare ne zaman hazır? (G-30 → B-6, 2026-09-07)
|
|
3
|
+
*
|
|
4
|
+
* `delayMs` TAHMİNDİ; 09-05'te runtime koşan akış sayacını yayınlamaya başladı (`@ng-apps/flow`
|
|
5
|
+
* → flow-runtime-errors.ts) ve bekleme "running sıfır, completed > 0" olunca bitiyordu. Bu şart
|
|
6
|
+
* mount akışı OLMAYAN sayfada (giriş ekranı) hiç sağlanmaz; akış tetiklemeyen `set` eylemi de
|
|
7
|
+
* `completed`'ı artırmaz. 09-06·2 koşusunda üç eylemli giriş denemesi bu yüzden 47 sn sürdü;
|
|
8
|
+
* sentetik ölçümde sayfa 0.3 sn'de hazırken aynı çağrı 48 sn'ydi — süre sayfanın değil, bu
|
|
9
|
+
* döngünün. Hazırlık artık TEK anlık görüntüden okunur: akış sayacı + Studio'nun yükleme
|
|
10
|
+
* iskeleti (`ViewDetail.svelte` → `.view-detail > .bx--skeleton__placeholder`) + runtime
|
|
11
|
+
* düğümleri (`[data-element-id]`) + hata/bulunamadı hâli + adres. Karar `decideReadiness`'ta.
|
|
12
|
+
*
|
|
13
|
+
* Yüklenmemiş kare ASLA dönmez: bütçe dolduğunda sayfa hâlâ hazır değilse çağrı hatayla düşer
|
|
14
|
+
* (`captureUnready: true` teşhis kipi dışında). Bozuk sayfayı görmek istiyorsan hata mesajı
|
|
15
|
+
* neyin görüldüğünü zaten söyler.
|
|
16
|
+
*/
|
|
17
|
+
export const readinessScript = `(function () { /* readinessSnapshot */
|
|
18
|
+
var activity = window.__ngAppsFlowActivity;
|
|
19
|
+
return {
|
|
20
|
+
activity: activity && typeof activity.running === 'number' && typeof activity.completed === 'number' ? { running: activity.running, completed: activity.completed } : null,
|
|
21
|
+
runtimeNodes: document.querySelectorAll('[data-element-id]').length,
|
|
22
|
+
skeleton: !!document.querySelector('.view-detail > .bx--skeleton__placeholder'),
|
|
23
|
+
viewDetail: !!document.querySelector('.view-detail'),
|
|
24
|
+
errorState: !!document.querySelector('.view-detail__error, .view-detail .error-page'),
|
|
25
|
+
readyState: String(document.readyState),
|
|
26
|
+
href: String(location.href)
|
|
27
|
+
};
|
|
28
|
+
})()`;
|
|
29
|
+
/** Okunan değer gerçekten sayaç mı; değilse sayfa sayaç yayınlamıyordur (eski runtime). */
|
|
30
|
+
export function isFlowActivity(activity) {
|
|
31
|
+
if (!activity || typeof activity !== 'object')
|
|
32
|
+
return false;
|
|
33
|
+
const { running, completed } = activity;
|
|
34
|
+
return typeof running === 'number' && typeof completed === 'number';
|
|
35
|
+
}
|
|
36
|
+
/** Tarayıcıdan dönen değer anlık görüntü mü; yönlendirme sırasında evaluate düşer ve undefined kalır. */
|
|
37
|
+
export function parseReadiness(raw) {
|
|
38
|
+
if (!raw || typeof raw !== 'object')
|
|
39
|
+
return undefined;
|
|
40
|
+
const value = raw;
|
|
41
|
+
if (typeof value.runtimeNodes !== 'number' || typeof value.href !== 'string')
|
|
42
|
+
return undefined;
|
|
43
|
+
return {
|
|
44
|
+
activity: isFlowActivity(value.activity) ? { running: value.activity.running, completed: value.activity.completed } : null,
|
|
45
|
+
runtimeNodes: value.runtimeNodes,
|
|
46
|
+
skeleton: value.skeleton === true,
|
|
47
|
+
viewDetail: value.viewDetail === true,
|
|
48
|
+
errorState: value.errorState === true,
|
|
49
|
+
readyState: String(value.readyState ?? ''),
|
|
50
|
+
href: value.href
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/** `/dev` ve `/view` aynı sayfadır (Studio `hooks.ts` reroute); yönlendirme kararı yalnız yoldan verilir. */
|
|
54
|
+
export function runtimePath(url) {
|
|
55
|
+
try {
|
|
56
|
+
return new URL(url).pathname.replace(/^\/dev\//, '/view/').replace(/\/+$/, '');
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return url;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/** "Hiç akış koşmadı" kararı için DOM'un kaç yoklama değişmemesi gerekir (~600 ms = eski settleMs). */
|
|
63
|
+
const quietPolls = 5;
|
|
64
|
+
/** Sayaç yayınlanmayan runtime'da tek kanıt DOM durulmasıdır; daha uzun beklenir (~1 sn). */
|
|
65
|
+
const legacyQuietPolls = 8;
|
|
66
|
+
/** Runtime dışına yönlendirme: hedef sayfanın kendi JS'i çizmeyi bitirsin (~1.5 sn). */
|
|
67
|
+
const redirectQuietPolls = 12;
|
|
68
|
+
/**
|
|
69
|
+
* Tek anlık görüntüden "kare alınabilir" kararı; iki uçta da yanlış beklememek için tek yerde.
|
|
70
|
+
* `quiet` görüntünün kaç yoklamadır değişmediğidir, `completedBefore` bu beklemenin başındaki
|
|
71
|
+
* bitmiş akış sayısı (sayfa değiştiyse çağıran sıfırlar). İskelet görünüyorsa hiçbir karar yok.
|
|
72
|
+
*/
|
|
73
|
+
export function decideReadiness(snapshot, quiet, completedBefore, baselineUrl) {
|
|
74
|
+
if (snapshot.skeleton)
|
|
75
|
+
return undefined;
|
|
76
|
+
const { activity } = snapshot;
|
|
77
|
+
const idle = activity !== null && activity.running === 0;
|
|
78
|
+
if (idle && activity.completed > completedBefore && snapshot.runtimeNodes > 0)
|
|
79
|
+
return 'ready';
|
|
80
|
+
if (idle && snapshot.runtimeNodes > 0 && quiet >= quietPolls)
|
|
81
|
+
return 'ready-no-flows';
|
|
82
|
+
if (activity === null && snapshot.runtimeNodes > 0 && quiet >= legacyQuietPolls)
|
|
83
|
+
return 'ready-no-counter';
|
|
84
|
+
if (idle && snapshot.errorState && quiet >= quietPolls)
|
|
85
|
+
return 'error';
|
|
86
|
+
if (!snapshot.viewDetail && snapshot.readyState === 'complete' && baselineUrl !== undefined && runtimePath(snapshot.href) !== runtimePath(baselineUrl) && quiet >= redirectQuietPolls)
|
|
87
|
+
return 'redirected';
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
/** Hata mesajı için: bütçe dolduğunda sayfada NE görüldü. */
|
|
91
|
+
export function describeUnready(readiness, apiNote) {
|
|
92
|
+
const snapshot = readiness.snapshot;
|
|
93
|
+
const suffix = apiNote === undefined ? '' : ` · ${apiNote}`;
|
|
94
|
+
if (!snapshot)
|
|
95
|
+
return `tarayıcı sayfayı hiç değerlendiremedi (sürekli yönlendirme ya da bağlam düştü)${suffix}`;
|
|
96
|
+
if (snapshot.skeleton)
|
|
97
|
+
return `sayfa hâlâ yükleme iskeletinde${suffix}`;
|
|
98
|
+
if (snapshot.activity && snapshot.activity.running > 0)
|
|
99
|
+
return `${snapshot.activity.running} akış hâlâ koşuyor (${snapshot.activity.completed} bitti)${suffix}`;
|
|
100
|
+
if (snapshot.runtimeNodes === 0)
|
|
101
|
+
return `runtime hiç render olmadı — data-element-id taşıyan düğüm yok${snapshot.viewDetail ? '' : ', .view-detail kabı da yok'}${suffix}`;
|
|
102
|
+
return `sayfa durulmadı (${snapshot.runtimeNodes} düğüm, sayaç ${snapshot.activity ? `${snapshot.activity.running} koşan / ${snapshot.activity.completed} biten` : 'yok'})${suffix}`;
|
|
103
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NE GÖRÜNÜYOR — resimsiz (S-5). Aynı sayfa yüklemesinden çıkan üçüncü çıktı: her KÖK runtime
|
|
3
|
+
* düğümünün görünürlüğü, metni, satır sayısı, açık sekmesi, değeri ve hata metinleri.
|
|
4
|
+
*
|
|
5
|
+
* Kök düğüm = kimliğinde `__` OLMAYAN düğüm; iç roller (`tbl__row-3`) satır sayısına dönüşür,
|
|
6
|
+
* listeye girmez. Tavan 300 düğüm, metin 80 karakter (K3) — özet bir kareyi değiştirmeli, onun
|
|
7
|
+
* kadar pahalı olmamalı. Tip `data-component-type`'tan gelir (frontend f-02); runtime basmıyorsa
|
|
8
|
+
* alan YAZILMAZ ve `typed: false` döner — `layoutReportUnavailable` ile aynı dürüstlük kuralı.
|
|
9
|
+
*/
|
|
10
|
+
export function domSummaryScript(viewportHeight) {
|
|
11
|
+
return `(function () { /* domSummary */
|
|
12
|
+
var MAX = 300;
|
|
13
|
+
var CUT = 80;
|
|
14
|
+
// Görünür alanın GERÇEK boyu: fullPage ve clip yolları viewport'u içerik boyuna büyütür ve
|
|
15
|
+
// o anda window.innerHeight = içerik yüksekliği olur — her düğüm "ekran içinde" görünürdü ve
|
|
16
|
+
// "kart katlanmanın altında mı" sorusu HER ZAMAN 'visible' cevabı alırdı (B-10).
|
|
17
|
+
var VH = ${Math.max(Math.round(viewportHeight), 1)};
|
|
18
|
+
var clean = function (value) { return String(value || '').replace(/\\s+/g, ' ').trim(); };
|
|
19
|
+
// Mobil sekme çubuğu '__tabs' bir KÖK satırdır (öğeleri '__tabs__item-<slug>' iç roldür, K14);
|
|
20
|
+
// web runtime bu kimliği hiç basmaz.
|
|
21
|
+
var ROOT_SELECTOR = '[data-element-id]:not([data-element-id*="__"]), [data-element-id="__tabs"]';
|
|
22
|
+
var isRoot = function (element) { var id = String(element.getAttribute('data-element-id') || ''); return id.indexOf('__') < 0 || id === '__tabs'; };
|
|
23
|
+
var all = Array.prototype.slice.call(document.querySelectorAll('[data-element-id]'));
|
|
24
|
+
var roots = all.filter(isRoot);
|
|
25
|
+
var typed = false;
|
|
26
|
+
var nodes = roots.slice(0, MAX).map(function (node) {
|
|
27
|
+
var id = node.getAttribute('data-element-id');
|
|
28
|
+
var type = node.getAttribute('data-component-type');
|
|
29
|
+
if (type) typed = true;
|
|
30
|
+
// Bir olgu, ONU TAŞIYAN düğüme yazılır: en yakın kök ata bu düğüm değilse o olgu
|
|
31
|
+
// çocuğundur ve orada zaten listelenecektir (B-8). Aksi hâlde aynı değer üç satırda çıkar.
|
|
32
|
+
var owned = function (element) { return !!element && element.closest(ROOT_SELECTOR) === node; };
|
|
33
|
+
var rect = node.getBoundingClientRect();
|
|
34
|
+
var visible = typeof node.checkVisibility === 'function'
|
|
35
|
+
? !!node.checkVisibility({ checkVisibilityCSS: true, checkOpacity: true })
|
|
36
|
+
: (rect.width > 0 && rect.height > 0);
|
|
37
|
+
var inViewport = rect.bottom > 0 && rect.right > 0 && rect.top < VH && rect.left < (window.innerWidth || 0);
|
|
38
|
+
// Kap düğümün innerText'i ÇOCUKLARININ metnidir; metin yalnız YAPRAK köklerde yazılır.
|
|
39
|
+
var nested = Array.prototype.slice.call(node.querySelectorAll('[data-element-id]'))
|
|
40
|
+
.some(isRoot);
|
|
41
|
+
var text = nested ? '' : clean(node.innerText);
|
|
42
|
+
if (text.length > CUT) text = text.slice(0, CUT) + '…';
|
|
43
|
+
var rows = document.querySelectorAll('[data-element-id^="' + id + '__row-"]').length;
|
|
44
|
+
var tab = node.querySelector('[role="tab"][aria-selected="true"]');
|
|
45
|
+
var field = node.querySelector('input, select, textarea');
|
|
46
|
+
var chosen = node.querySelector('.selected-item');
|
|
47
|
+
var holder = field || chosen;
|
|
48
|
+
var value = !owned(holder) ? '' : (field ? (field.type === 'password' ? '***' : clean(field.value)) : clean(chosen.textContent));
|
|
49
|
+
var media = node.querySelector('img, svg, canvas, video, iframe');
|
|
50
|
+
// İç içe <li> hem grubu hem alt mesajları sayıyordu: tek grup + 2 alt hata 3 görünüyordu (B-7).
|
|
51
|
+
var errorItems = Array.prototype.slice.call(node.querySelectorAll('.form-validation-errors li:not(:has(li))'))
|
|
52
|
+
.filter(owned).map(function (item) { return clean(item.textContent); });
|
|
53
|
+
// aria-invalid hem köke hem input'a yazılabiliyor (Password.svelte); yalnız ALANLAR sayılır.
|
|
54
|
+
var invalid = Array.prototype.slice.call(node.querySelectorAll('input[aria-invalid="true"], select[aria-invalid="true"], textarea[aria-invalid="true"]')).filter(owned).length;
|
|
55
|
+
var summary = { elementId: id, visible: !!visible, inViewport: !!inViewport };
|
|
56
|
+
if (type) summary.type = type;
|
|
57
|
+
if (text) summary.text = text;
|
|
58
|
+
if (rows > 0) summary.rows = rows;
|
|
59
|
+
if (owned(tab)) summary.activeTab = clean(tab.textContent);
|
|
60
|
+
if (value) summary.value = value;
|
|
61
|
+
if (visible && !text && !media && !nested) summary.empty = true;
|
|
62
|
+
if (errorItems.length > 0) summary.errors = errorItems;
|
|
63
|
+
else if (invalid > 0) summary.errors = ['aria-invalid: ' + invalid];
|
|
64
|
+
return summary;
|
|
65
|
+
});
|
|
66
|
+
var messages = [];
|
|
67
|
+
Array.prototype.slice.call(document.querySelectorAll('.ng-toast')).forEach(function (toast) {
|
|
68
|
+
var name = String(toast.className || '');
|
|
69
|
+
var kind = name.indexOf('ng-toast--error') >= 0 ? 'toast/error' : (name.indexOf('ng-toast--success') >= 0 ? 'toast/success' : 'toast');
|
|
70
|
+
messages.push({ kind: kind, text: clean(toast.innerText).slice(0, 160) });
|
|
71
|
+
});
|
|
72
|
+
Array.prototype.slice.call(document.querySelectorAll('.view-detail__error, .error-page')).forEach(function (node) {
|
|
73
|
+
messages.push({ kind: 'error', text: clean(node.innerText).slice(0, 160) });
|
|
74
|
+
});
|
|
75
|
+
return { nodes: nodes, messages: messages, truncated: roots.length > MAX, typed: typed };
|
|
76
|
+
})()`;
|
|
77
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mobil uygulama: `@ng-apps/ui-native` `NativeRuntime`, Studio'da react-native-web ile çizilir
|
|
3
|
+
* (plans/mobil-uygulama-expo F5). Ağaçta `<form>` yoktur — `submit` runtime'ın yayımladığı köprüyle
|
|
4
|
+
* form düğümünün `submit` olayını makineye iletir (`web-runtime-host.tsx` `__ngAppsSubmitForm`).
|
|
5
|
+
* Sekme çubuğu `__tabs`, öğeleri `__tabs__item-<sayfa slug'ı>` kimliğini taşır (K14). Açılır
|
|
6
|
+
* listenin tetikleyicisi `role="combobox"`, seçenekleri `role="option"` + `data-value` taşır ve liste
|
|
7
|
+
* `Modal` katmanında açılır (`ng-apps-ui-native` `dropdown`).
|
|
8
|
+
*/
|
|
9
|
+
export const studioMobileTarget = Object.freeze({
|
|
10
|
+
name: 'studio-mobile',
|
|
11
|
+
submitBridge: '__ngAppsSubmitForm',
|
|
12
|
+
optionSelector: '[role="option"][data-value], [role="treeitem"][data-value]',
|
|
13
|
+
optionsOutsideNode: true,
|
|
14
|
+
platformNote: 'Mobil uygulama: kare Studio\'daki react-native-web çizimidir (/dev|/view) — cihazdaki native çizimle yapısal olarak (düğüm, sıra, ölçü modu, renk) aynı, piksel olarak değil.'
|
|
15
|
+
});
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* (card) · GİZLİ" 200 karakterdir.
|
|
8
8
|
*
|
|
9
9
|
* Katman saftır: tarayıcıdan gelen anlık görüntüyü doğrular ve biçimler. Toplama işi
|
|
10
|
-
* `
|
|
10
|
+
* `capture/summary.ts` `domSummaryScript`'te, sunum `pages.ts`'te.
|
|
11
11
|
*/
|
|
12
12
|
function text(value) {
|
|
13
13
|
return typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_meta": {
|
|
3
|
+
"synthetic": true,
|
|
4
|
+
"note": "Mobil uygulama kabuğu — ÇEKMECE: app-bar (leading 'menu' + menuTarget) + slot + drawer widget'ı. Çekmece ayar değil bileşendir; içindeki düğmeler sıradan redirect akışlarıyla sayfa açar. mobile_app_create drawer:true ile bu kabuğu kurar.",
|
|
5
|
+
"pairsWith": "mobile-app-shell-stack, mobile-app-shell-tab",
|
|
6
|
+
"sourceRef": "platform_guide('mobile') §Gezinme; plans/mobil-uygulama-expo/05-mobil-ayarlar-ve-gezinme.md §2.5, §8"
|
|
7
|
+
},
|
|
8
|
+
"_rules": {
|
|
9
|
+
"flexOnly": "Mobil çizer yalnız flex'tir: blocks boş, sıra dizi indeksi, ölçü appearance ile (MOB-001). Kökte layout prop'u YOK — mobil container şeması onu düşürür.",
|
|
10
|
+
"singleSlot": "TEK slot; sayfa şeması slot'a yerleşir (LAY-002 / LAY-006 web'dekiyle aynı).",
|
|
11
|
+
"appBarTitle": "app-bar.title boşsa sayfa adı yazılır; leading 'auto' yığında geri düğmesi, kökte (menuTarget varsa) menü düğmesi çizer.",
|
|
12
|
+
"catalog": "app-bar, slot ve drawer mobil kataloğun Dalga 1 bileşenleridir. component_list mobil uygulamada bunları döndürmüyorsa katalog henüz yazılmamıştır ve layout_create 422 unknown-type alır (MOB-003).",
|
|
13
|
+
"verify": "Kabuğu layout'a bağlı bir sayfada page_screenshot ile doğrula (mobilde varsayılan device: 'phone').",
|
|
14
|
+
"menuTarget": "app-bar.menuTarget çekmecenin elementId'sidir (nav_drawer); iç rol app_bar__menu düğmesidir — page_screenshot actions:[{ action:'click', target:'app_bar__menu' }] çekmeceyi açar.",
|
|
15
|
+
"drawerFlows": "Menü düğmelerine akış ayrı adımda bağlanır: flow_create (host: 'layout', adım redirect { path: '<sayfa slug'ı>' }) → layout_schema_patch set_event { target: 'menu_gorevler', event: 'click' }.",
|
|
16
|
+
"drawerNode": "Çekmece mobil kataloğun `drawer` bileşenidir (kind 'component', çocuk alır): layout'a doğrudan yazılır, prop'ları katalogdakilerdir (`position`, `size`, `title`, `isDismissDisabled`); kapalı doğar, `app-bar` menüsü `isOpen: true` yazarak açar. Katalogda olmayan prop (ör. `width`, `overlay`) ya da seçenek dışı değer (düğmede `variant: 'ghost'` — geçerli olanlar `solid`/`text`/`outline`) layout_create'i 422 ile düşürür."
|
|
17
|
+
},
|
|
18
|
+
"mobileAppCreate": {
|
|
19
|
+
"slug": "saha-menu",
|
|
20
|
+
"name": "Saha",
|
|
21
|
+
"drawer": true,
|
|
22
|
+
"pages": [
|
|
23
|
+
{
|
|
24
|
+
"pageSlug": "gorevler",
|
|
25
|
+
"pageName": "Görevler"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"pageSlug": "profil",
|
|
29
|
+
"pageName": "Profil"
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
"layoutCreate": {
|
|
34
|
+
"name": "Mobil kabuk",
|
|
35
|
+
"views": [
|
|
36
|
+
{
|
|
37
|
+
"elementId": "shell_root",
|
|
38
|
+
"name": "shell_root",
|
|
39
|
+
"type": "container",
|
|
40
|
+
"kind": "component",
|
|
41
|
+
"props": {
|
|
42
|
+
"title": {
|
|
43
|
+
"type": "static",
|
|
44
|
+
"ref": null,
|
|
45
|
+
"data": ""
|
|
46
|
+
},
|
|
47
|
+
"direction": {
|
|
48
|
+
"type": "static",
|
|
49
|
+
"ref": null,
|
|
50
|
+
"data": "column"
|
|
51
|
+
},
|
|
52
|
+
"gap": {
|
|
53
|
+
"type": "static",
|
|
54
|
+
"ref": null,
|
|
55
|
+
"data": "none"
|
|
56
|
+
},
|
|
57
|
+
"size": {
|
|
58
|
+
"type": "static",
|
|
59
|
+
"ref": null,
|
|
60
|
+
"data": "grow"
|
|
61
|
+
},
|
|
62
|
+
"wrap": {
|
|
63
|
+
"type": "static",
|
|
64
|
+
"ref": null,
|
|
65
|
+
"data": false
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"states": {
|
|
69
|
+
"isDroppable": true,
|
|
70
|
+
"isWrapper": true
|
|
71
|
+
},
|
|
72
|
+
"appearance": {
|
|
73
|
+
"heightType": "fill",
|
|
74
|
+
"widthType": "fill"
|
|
75
|
+
},
|
|
76
|
+
"blocks": [],
|
|
77
|
+
"events": [],
|
|
78
|
+
"validations": [],
|
|
79
|
+
"stateBindings": [],
|
|
80
|
+
"children": [
|
|
81
|
+
{
|
|
82
|
+
"elementId": "app_bar",
|
|
83
|
+
"name": "app_bar",
|
|
84
|
+
"type": "app-bar",
|
|
85
|
+
"kind": "component",
|
|
86
|
+
"props": {
|
|
87
|
+
"title": {
|
|
88
|
+
"type": "static",
|
|
89
|
+
"ref": null,
|
|
90
|
+
"data": ""
|
|
91
|
+
},
|
|
92
|
+
"leading": {
|
|
93
|
+
"type": "static",
|
|
94
|
+
"ref": null,
|
|
95
|
+
"data": "menu"
|
|
96
|
+
},
|
|
97
|
+
"menuTarget": {
|
|
98
|
+
"type": "static",
|
|
99
|
+
"ref": null,
|
|
100
|
+
"data": "nav_drawer"
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
"appearance": {
|
|
104
|
+
"widthType": "fill"
|
|
105
|
+
},
|
|
106
|
+
"blocks": [],
|
|
107
|
+
"events": [],
|
|
108
|
+
"validations": [],
|
|
109
|
+
"stateBindings": [],
|
|
110
|
+
"children": []
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"elementId": "page_slot",
|
|
114
|
+
"name": "page_slot",
|
|
115
|
+
"type": "slot",
|
|
116
|
+
"kind": "component",
|
|
117
|
+
"props": {},
|
|
118
|
+
"appearance": {
|
|
119
|
+
"widthType": "fill",
|
|
120
|
+
"heightType": "fill"
|
|
121
|
+
},
|
|
122
|
+
"blocks": [],
|
|
123
|
+
"events": [],
|
|
124
|
+
"validations": [],
|
|
125
|
+
"stateBindings": [],
|
|
126
|
+
"children": []
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
"elementId": "nav_drawer",
|
|
130
|
+
"name": "nav_drawer",
|
|
131
|
+
"type": "drawer",
|
|
132
|
+
"kind": "component",
|
|
133
|
+
"props": {
|
|
134
|
+
"position": {
|
|
135
|
+
"type": "static",
|
|
136
|
+
"ref": null,
|
|
137
|
+
"data": "left"
|
|
138
|
+
},
|
|
139
|
+
"size": {
|
|
140
|
+
"type": "static",
|
|
141
|
+
"ref": null,
|
|
142
|
+
"data": "default"
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
"appearance": {},
|
|
146
|
+
"blocks": [],
|
|
147
|
+
"events": [],
|
|
148
|
+
"validations": [],
|
|
149
|
+
"stateBindings": [],
|
|
150
|
+
"children": [
|
|
151
|
+
{
|
|
152
|
+
"elementId": "menu_gorevler",
|
|
153
|
+
"name": "menu_gorevler",
|
|
154
|
+
"type": "button",
|
|
155
|
+
"kind": "component",
|
|
156
|
+
"props": {
|
|
157
|
+
"text": {
|
|
158
|
+
"type": "static",
|
|
159
|
+
"ref": null,
|
|
160
|
+
"data": "Görevler"
|
|
161
|
+
},
|
|
162
|
+
"variant": {
|
|
163
|
+
"type": "static",
|
|
164
|
+
"ref": null,
|
|
165
|
+
"data": "text"
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
"appearance": {
|
|
169
|
+
"widthType": "fill"
|
|
170
|
+
},
|
|
171
|
+
"blocks": [],
|
|
172
|
+
"events": [],
|
|
173
|
+
"validations": [],
|
|
174
|
+
"stateBindings": [],
|
|
175
|
+
"children": []
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
"elementId": "menu_profil",
|
|
179
|
+
"name": "menu_profil",
|
|
180
|
+
"type": "button",
|
|
181
|
+
"kind": "component",
|
|
182
|
+
"props": {
|
|
183
|
+
"text": {
|
|
184
|
+
"type": "static",
|
|
185
|
+
"ref": null,
|
|
186
|
+
"data": "Profil"
|
|
187
|
+
},
|
|
188
|
+
"variant": {
|
|
189
|
+
"type": "static",
|
|
190
|
+
"ref": null,
|
|
191
|
+
"data": "text"
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
"appearance": {
|
|
195
|
+
"widthType": "fill"
|
|
196
|
+
},
|
|
197
|
+
"blocks": [],
|
|
198
|
+
"events": [],
|
|
199
|
+
"validations": [],
|
|
200
|
+
"stateBindings": [],
|
|
201
|
+
"children": []
|
|
202
|
+
}
|
|
203
|
+
]
|
|
204
|
+
}
|
|
205
|
+
]
|
|
206
|
+
}
|
|
207
|
+
]
|
|
208
|
+
}
|
|
209
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_meta": {
|
|
3
|
+
"synthetic": true,
|
|
4
|
+
"note": "Mobil uygulama kabuğu — YIĞIN (varsayılan gezinme): app-bar + tek slot. Sekme ayarı yok; redirect sayfayı yığına iter, app-bar geri düğmesi ve cihaz geri tuşu döner. layout_create'in views alanına olduğu gibi verilebilir; mobile_app_create tabs ve drawer verilmeyince bu kabuğu kurar.",
|
|
5
|
+
"pairsWith": "mobile-app-shell-tab (sekmeli), mobile-app-shell-drawer (çekmeceli), mobile-list-detail-form (üç sayfa)",
|
|
6
|
+
"sourceRef": "platform_guide('mobile') §Gezinme; plans/mobil-uygulama-expo/05-mobil-ayarlar-ve-gezinme.md §2.5-2.6"
|
|
7
|
+
},
|
|
8
|
+
"_rules": {
|
|
9
|
+
"flexOnly": "Mobil çizer yalnız flex'tir: blocks boş, sıra dizi indeksi, ölçü appearance ile (MOB-001). Kökte layout prop'u YOK — mobil container şeması onu düşürür.",
|
|
10
|
+
"singleSlot": "TEK slot; sayfa şeması slot'a yerleşir (LAY-002 / LAY-006 web'dekiyle aynı).",
|
|
11
|
+
"appBarTitle": "app-bar.title boşsa sayfa adı yazılır; leading 'auto' yığında geri düğmesi, kökte (menuTarget varsa) menü düğmesi çizer.",
|
|
12
|
+
"catalog": "app-bar, slot ve drawer mobil kataloğun Dalga 1 bileşenleridir. component_list mobil uygulamada bunları döndürmüyorsa katalog henüz yazılmamıştır ve layout_create 422 unknown-type alır (MOB-003).",
|
|
13
|
+
"verify": "Kabuğu layout'a bağlı bir sayfada page_screenshot ile doğrula (mobilde varsayılan device: 'phone')."
|
|
14
|
+
},
|
|
15
|
+
"mobileAppCreate": {
|
|
16
|
+
"slug": "saha",
|
|
17
|
+
"name": "Saha",
|
|
18
|
+
"pages": [
|
|
19
|
+
{
|
|
20
|
+
"pageSlug": "gorevler",
|
|
21
|
+
"pageName": "Görevler"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"pageSlug": "detay",
|
|
25
|
+
"pageName": "Görev detayı"
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"layoutCreate": {
|
|
30
|
+
"name": "Mobil kabuk",
|
|
31
|
+
"views": [
|
|
32
|
+
{
|
|
33
|
+
"elementId": "shell_root",
|
|
34
|
+
"name": "shell_root",
|
|
35
|
+
"type": "container",
|
|
36
|
+
"kind": "component",
|
|
37
|
+
"props": {
|
|
38
|
+
"title": {
|
|
39
|
+
"type": "static",
|
|
40
|
+
"ref": null,
|
|
41
|
+
"data": ""
|
|
42
|
+
},
|
|
43
|
+
"direction": {
|
|
44
|
+
"type": "static",
|
|
45
|
+
"ref": null,
|
|
46
|
+
"data": "column"
|
|
47
|
+
},
|
|
48
|
+
"gap": {
|
|
49
|
+
"type": "static",
|
|
50
|
+
"ref": null,
|
|
51
|
+
"data": "none"
|
|
52
|
+
},
|
|
53
|
+
"size": {
|
|
54
|
+
"type": "static",
|
|
55
|
+
"ref": null,
|
|
56
|
+
"data": "grow"
|
|
57
|
+
},
|
|
58
|
+
"wrap": {
|
|
59
|
+
"type": "static",
|
|
60
|
+
"ref": null,
|
|
61
|
+
"data": false
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"states": {
|
|
65
|
+
"isDroppable": true,
|
|
66
|
+
"isWrapper": true
|
|
67
|
+
},
|
|
68
|
+
"appearance": {
|
|
69
|
+
"heightType": "fill",
|
|
70
|
+
"widthType": "fill"
|
|
71
|
+
},
|
|
72
|
+
"blocks": [],
|
|
73
|
+
"events": [],
|
|
74
|
+
"validations": [],
|
|
75
|
+
"stateBindings": [],
|
|
76
|
+
"children": [
|
|
77
|
+
{
|
|
78
|
+
"elementId": "app_bar",
|
|
79
|
+
"name": "app_bar",
|
|
80
|
+
"type": "app-bar",
|
|
81
|
+
"kind": "component",
|
|
82
|
+
"props": {
|
|
83
|
+
"title": {
|
|
84
|
+
"type": "static",
|
|
85
|
+
"ref": null,
|
|
86
|
+
"data": ""
|
|
87
|
+
},
|
|
88
|
+
"leading": {
|
|
89
|
+
"type": "static",
|
|
90
|
+
"ref": null,
|
|
91
|
+
"data": "auto"
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
"appearance": {
|
|
95
|
+
"widthType": "fill"
|
|
96
|
+
},
|
|
97
|
+
"blocks": [],
|
|
98
|
+
"events": [],
|
|
99
|
+
"validations": [],
|
|
100
|
+
"stateBindings": [],
|
|
101
|
+
"children": []
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"elementId": "page_slot",
|
|
105
|
+
"name": "page_slot",
|
|
106
|
+
"type": "slot",
|
|
107
|
+
"kind": "component",
|
|
108
|
+
"props": {},
|
|
109
|
+
"appearance": {
|
|
110
|
+
"widthType": "fill",
|
|
111
|
+
"heightType": "fill"
|
|
112
|
+
},
|
|
113
|
+
"blocks": [],
|
|
114
|
+
"events": [],
|
|
115
|
+
"validations": [],
|
|
116
|
+
"stateBindings": [],
|
|
117
|
+
"children": []
|
|
118
|
+
}
|
|
119
|
+
]
|
|
120
|
+
}
|
|
121
|
+
]
|
|
122
|
+
}
|
|
123
|
+
}
|