@m1kapp/kit 0.0.37 → 0.0.40
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/bin/lib/project.mjs +130 -0
- package/bin/m1kkit.mjs +11 -2
- package/bin/new.mjs +162 -0
- package/bin/skills/m1kapp-clean.md +129 -49
- package/bin/skills/m1kapp-new.md +73 -0
- package/bin/skills.mjs +5 -1
- package/bin/stats.mjs +41 -939
- package/bin/track.mjs +55 -6
- package/bin/untrack.mjs +139 -0
- package/dist/index.d.mts +40 -9
- package/dist/index.d.ts +40 -9
- package/dist/index.js +4 -4
- package/dist/index.mjs +4 -4
- package/dist/meta.json +6 -6
- package/dist/pwa.js +2 -2
- package/dist/pwa.mjs +1 -1
- package/dist/styles.css +1 -1
- package/package.json +8 -3
- package/templates/vite-app/_gitignore +5 -0
- package/templates/vite-app/_package.json +25 -0
- package/templates/vite-app/index.html +17 -0
- package/templates/vite-app/src/App.tsx +136 -0
- package/templates/vite-app/src/index.css +22 -0
- package/templates/vite-app/src/main.tsx +10 -0
- package/templates/vite-app/src/vite-env.d.ts +10 -0
- package/templates/vite-app/tsconfig.json +21 -0
- package/templates/vite-app/vite.config.ts +7 -0
package/bin/track.mjs
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* m1kkit track <url> [--host=m1k.app]
|
|
3
|
+
* m1kkit track <url> [--host=m1k.app] [--write]
|
|
4
4
|
*
|
|
5
5
|
* 로그인 없이 m1k 방문자 트래커에 사이트를 등록하고 배지 slug를 발급받는다.
|
|
6
6
|
* 발급된 claim 토큰은 현재 폴더의 .m1k.json 에 저장 → 나중에 `m1kkit claim`으로 계정 귀속.
|
|
7
|
+
* `--write` 를 주면 발급된 slug를 앱 코드(`<Watermark trackSlug>`)와 `.env` 에 직접 꽂는다.
|
|
7
8
|
*/
|
|
8
9
|
import { writeFileSync, existsSync, readFileSync } from "fs";
|
|
9
|
-
import { resolve } from "path";
|
|
10
|
+
import { resolve, dirname, join } from "path";
|
|
11
|
+
import { fileURLToPath } from "url";
|
|
12
|
+
|
|
13
|
+
const { detectProject, wireSlug } = await import(
|
|
14
|
+
join(dirname(fileURLToPath(import.meta.url)), "lib", "project.mjs")
|
|
15
|
+
);
|
|
10
16
|
|
|
11
17
|
const args = process.argv.slice(2);
|
|
12
18
|
const flags = Object.fromEntries(
|
|
@@ -24,15 +30,20 @@ if (!url || flags.help) {
|
|
|
24
30
|
m1kkit track — m1k 방문자 트래커에 사이트 등록 (무로그인)
|
|
25
31
|
|
|
26
32
|
사용법:
|
|
27
|
-
npx m1kkit track <url> [--host=m1k.app]
|
|
33
|
+
npx m1kkit track <url> [--host=m1k.app] [--write]
|
|
28
34
|
|
|
29
35
|
예시:
|
|
30
36
|
npx m1kkit track https://myside.app
|
|
37
|
+
npx m1kkit track https://myside.app --write # 발급 + 코드에 바로 배선
|
|
31
38
|
|
|
32
39
|
동작:
|
|
33
40
|
1) 로그인 없이 사이트를 등록하고 배지 slug를 발급
|
|
34
41
|
2) 배지 스니펫을 출력 (README/푸터에 붙여넣기 → 바로 수집 시작)
|
|
35
42
|
3) claim 토큰을 ./.m1k.json 에 저장 → 나중에 'm1kkit claim'으로 내 계정에 귀속
|
|
43
|
+
|
|
44
|
+
옵션:
|
|
45
|
+
--write slug를 <Watermark trackSlug="..."> 에 직접 넣고 .env 에도 기록.
|
|
46
|
+
(이걸 안 쓰면 slug만 발급되고 앱에는 아무것도 안 붙는다)
|
|
36
47
|
`);
|
|
37
48
|
process.exit(url ? 0 : 1);
|
|
38
49
|
}
|
|
@@ -58,10 +69,25 @@ if (!res.ok) {
|
|
|
58
69
|
process.exit(1);
|
|
59
70
|
}
|
|
60
71
|
|
|
72
|
+
const cwd = process.cwd();
|
|
73
|
+
|
|
74
|
+
/** slug를 앱에 꽂고, 무엇을 건드렸는지 사람 읽을 수 있게 출력한다. */
|
|
75
|
+
function applyWire(slug) {
|
|
76
|
+
const r = wireSlug(cwd, slug);
|
|
77
|
+
if (r.patched && !r.alreadyWired) console.log(` ✓ ${r.patched} — <Watermark trackSlug="${slug}"> 추가`);
|
|
78
|
+
else if (r.alreadyWired) console.log(` · ${r.patched} — trackSlug가 이미 있어 건너뜀`);
|
|
79
|
+
else console.log(` ! <Watermark> 를 쓰는 파일을 못 찾음 — trackSlug="${slug}" 를 직접 넣어주세요`);
|
|
80
|
+
if (r.env) console.log(` ✓ .env — ${r.env.key}=${slug} (${r.env.action})`);
|
|
81
|
+
console.log(` → dev 서버를 돌리는 중이면 재시작해야 .env가 반영됩니다.`);
|
|
82
|
+
return r;
|
|
83
|
+
}
|
|
84
|
+
|
|
61
85
|
if (data.alreadyRegistered) {
|
|
62
86
|
console.log(`\n⚠ ${data.message}`);
|
|
63
87
|
console.log(` slug: ${data.slug}`);
|
|
64
88
|
console.log(` badge: ${data.badgeUrl}\n`);
|
|
89
|
+
if (flags.write) applyWire(data.slug);
|
|
90
|
+
else console.log(` 코드에 배선하려면: npx m1kkit track ${url} --write\n`);
|
|
65
91
|
process.exit(0);
|
|
66
92
|
}
|
|
67
93
|
|
|
@@ -82,12 +108,35 @@ console.log(`
|
|
|
82
108
|
|
|
83
109
|
배지 스니펫 (README/푸터에 붙여넣기):
|
|
84
110
|
${data.snippet}
|
|
111
|
+
`);
|
|
112
|
+
|
|
113
|
+
if (flags.write) {
|
|
114
|
+
console.log(` ⚡ kit 자동 집계 배선:`);
|
|
115
|
+
applyWire(data.slug);
|
|
116
|
+
} else {
|
|
117
|
+
// 프로젝트 종류에 따라 env 변수 이름이 다르다. 반대쪽 이름을 쓰면 에러 없이
|
|
118
|
+
// 조용히 무시되기만 해서 "붙인 줄 알았는데 0" 이 되므로, 감지해서 알려준다.
|
|
119
|
+
const { kind } = detectProject(cwd);
|
|
120
|
+
const hint =
|
|
121
|
+
kind === "next"
|
|
122
|
+
? `Next 감지 → .env 에 NEXT_PUBLIC_M1K_SLUG=${data.slug} (kit이 알아서 읽음)`
|
|
123
|
+
: kind === "vite"
|
|
124
|
+
? `Vite 감지 → .env 에 VITE_M1K_SLUG=${data.slug}
|
|
125
|
+
+ 앱 소스에 <Watermark trackSlug={import.meta.env.VITE_M1K_SLUG}>
|
|
126
|
+
(Vite는 import.meta.env 를 앱 소스에서만 치환한다 — kit 안에서는 못 읽음)`
|
|
127
|
+
: `Next면 .env 에 NEXT_PUBLIC_M1K_SLUG=${data.slug}
|
|
128
|
+
Vite면 .env 에 VITE_M1K_SLUG=${data.slug} + 앱 소스에서 trackSlug 로 전달`;
|
|
129
|
+
console.log(` ⚡ kit을 쓰면 스니펫 없이 자동 집계:
|
|
130
|
+
${hint}
|
|
85
131
|
|
|
86
|
-
|
|
87
|
-
.env 에 한 줄만 추가하면 Watermark/PoweredByKit 하단 크레딧이 방문을 자동으로 셉니다.
|
|
88
|
-
NEXT_PUBLIC_M1K_SLUG=${data.slug}
|
|
132
|
+
제일 확실한 방법(번들러 무관): <Watermark trackSlug="${data.slug}">
|
|
89
133
|
(끄려면: <Watermark track={false}> 또는 그 줄 삭제)
|
|
90
134
|
|
|
135
|
+
↳ 위를 대신 해주는 명령: npx m1kkit track ${url} --write
|
|
136
|
+
`);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
console.log(`
|
|
91
140
|
claim 토큰을 ./.m1k.json 에 저장했어요.
|
|
92
141
|
나중에 내 계정에 귀속하려면: npx m1kkit claim
|
|
93
142
|
|
package/bin/untrack.mjs
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* m1kkit untrack [slug] [--token=<claimToken>] [--bearer=<개인토큰>] [--host=m1k.app] [--yes]
|
|
4
|
+
*
|
|
5
|
+
* m1k 방문자 트래커에서 사이트 등록을 취소한다(삭제).
|
|
6
|
+
*
|
|
7
|
+
* `track`으로 잘못 등록했을 때 지울 방법이 없었다 — 대시보드 삭제는 브라우저
|
|
8
|
+
* 로그인이 필요하고, CLI로 익명 등록한 사이트는 아직 어느 계정에도 안 붙어
|
|
9
|
+
* 있어서 대시보드에 뜨지도 않는다. 그래서 claim 토큰으로 지운다.
|
|
10
|
+
*
|
|
11
|
+
* slug/토큰을 안 주면 현재 폴더의 ./.m1k.json 에서 읽는다.
|
|
12
|
+
*/
|
|
13
|
+
import { existsSync, readFileSync, writeFileSync, unlinkSync } from "fs";
|
|
14
|
+
import { resolve } from "path";
|
|
15
|
+
import { createInterface } from "readline";
|
|
16
|
+
|
|
17
|
+
const args = process.argv.slice(2);
|
|
18
|
+
const flags = Object.fromEntries(
|
|
19
|
+
args
|
|
20
|
+
.filter((a) => a.startsWith("--"))
|
|
21
|
+
.map((a) => {
|
|
22
|
+
const [k, v] = a.replace(/^--/, "").split("=");
|
|
23
|
+
return [k, v ?? true];
|
|
24
|
+
}),
|
|
25
|
+
);
|
|
26
|
+
const positional = args.filter((a) => !a.startsWith("--"));
|
|
27
|
+
|
|
28
|
+
const store = readStore();
|
|
29
|
+
const slug = positional[0] || store.slug;
|
|
30
|
+
const claimToken = flags.token || store.claimToken;
|
|
31
|
+
const bearer = flags.bearer || process.env.M1K_TOKEN;
|
|
32
|
+
const host = flags.host || store.host || process.env.M1K_HOST || "m1k.app";
|
|
33
|
+
|
|
34
|
+
if (!slug || flags.help) {
|
|
35
|
+
console.log(`
|
|
36
|
+
m1kkit untrack — 방문자 트래커에서 사이트 삭제
|
|
37
|
+
|
|
38
|
+
사용법:
|
|
39
|
+
npx m1kkit untrack [slug] [옵션]
|
|
40
|
+
|
|
41
|
+
slug를 안 주면 현재 폴더의 ./.m1k.json 에서 읽어요.
|
|
42
|
+
|
|
43
|
+
옵션:
|
|
44
|
+
--token=<claimToken> 미귀속 사이트용. 기본값은 ./.m1k.json 의 claimToken
|
|
45
|
+
--bearer=<개인토큰> 이미 내 계정에 귀속한 사이트용 (또는 M1K_TOKEN 환경변수)
|
|
46
|
+
--host=m1k.app
|
|
47
|
+
--yes 확인 없이 삭제
|
|
48
|
+
|
|
49
|
+
되돌릴 수 없어요 — 누적 방문 기록도 같이 지워집니다.
|
|
50
|
+
`);
|
|
51
|
+
process.exit(slug ? 0 : 1);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (!claimToken && !bearer) {
|
|
55
|
+
console.error(`✗ 인증 수단이 없어요.
|
|
56
|
+
미귀속 사이트면 --token=<claimToken> (./.m1k.json 에 있어요)
|
|
57
|
+
귀속한 사이트면 --bearer=<개인토큰>`);
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const scheme = /^(localhost|127\.|0\.0\.0\.0)/.test(host) ? "http" : "https";
|
|
62
|
+
const base = `${scheme}://${host}`;
|
|
63
|
+
|
|
64
|
+
if (!flags.yes && process.stdin.isTTY) {
|
|
65
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
66
|
+
const answer = await new Promise((res) =>
|
|
67
|
+
rl.question(`'${slug}' 를 삭제할까요? 누적 방문 기록도 같이 지워지고 되돌릴 수 없어요. (y/N): `, res),
|
|
68
|
+
);
|
|
69
|
+
rl.close();
|
|
70
|
+
if (!/^y(es)?$/i.test(answer.trim())) {
|
|
71
|
+
console.log("취소했어요.");
|
|
72
|
+
process.exit(0);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
let res, data;
|
|
77
|
+
try {
|
|
78
|
+
res = await fetch(`${base}/api/sites/cli`, {
|
|
79
|
+
method: "DELETE",
|
|
80
|
+
headers: {
|
|
81
|
+
"content-type": "application/json",
|
|
82
|
+
...(bearer ? { authorization: `Bearer ${bearer}` } : {}),
|
|
83
|
+
},
|
|
84
|
+
body: JSON.stringify({ slug, claimToken }),
|
|
85
|
+
});
|
|
86
|
+
data = await res.json().catch(() => ({}));
|
|
87
|
+
} catch (e) {
|
|
88
|
+
console.error(`✗ 삭제 요청 실패: ${e.message}`);
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (!res.ok) {
|
|
93
|
+
console.error(`✗ ${data?.error || data?.message || res.statusText}`);
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
console.log(`\n✓ 삭제했어요. ${data.url || slug}\n`);
|
|
98
|
+
clearStore(slug);
|
|
99
|
+
|
|
100
|
+
/** ./.m1k.json 읽기 (없거나 깨졌으면 빈 객체) */
|
|
101
|
+
function readStore() {
|
|
102
|
+
const file = resolve(process.cwd(), ".m1k.json");
|
|
103
|
+
if (!existsSync(file)) return {};
|
|
104
|
+
try {
|
|
105
|
+
return JSON.parse(readFileSync(file, "utf8"));
|
|
106
|
+
} catch {
|
|
107
|
+
return {};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* 지운 사이트를 가리키던 ./.m1k.json 을 정리한다 — 남겨두면 다음 `claim`이
|
|
113
|
+
* 죽은 토큰으로 브라우저를 연다. 다른 사이트를 가리키고 있으면 건드리지 않는다.
|
|
114
|
+
*/
|
|
115
|
+
function clearStore(deletedSlug) {
|
|
116
|
+
const file = resolve(process.cwd(), ".m1k.json");
|
|
117
|
+
if (!existsSync(file)) return;
|
|
118
|
+
let json;
|
|
119
|
+
try {
|
|
120
|
+
json = JSON.parse(readFileSync(file, "utf8"));
|
|
121
|
+
} catch {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (json.slug !== deletedSlug) return;
|
|
125
|
+
|
|
126
|
+
const rest = { ...json };
|
|
127
|
+
delete rest.slug;
|
|
128
|
+
delete rest.url;
|
|
129
|
+
delete rest.claimToken;
|
|
130
|
+
if (Object.keys(rest).length === 0) {
|
|
131
|
+
unlinkSync(file);
|
|
132
|
+
console.log(" ./.m1k.json 도 지웠어요.");
|
|
133
|
+
} else {
|
|
134
|
+
writeFileSync(file, JSON.stringify(rest, null, 2) + "\n");
|
|
135
|
+
console.log(" ./.m1k.json 에서 해당 항목을 지웠어요.");
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
console.log(` App.tsx 의 trackSlug / .env 의 *_M1K_SLUG 는 직접 지워주세요.\n`);
|
|
139
|
+
}
|
package/dist/index.d.mts
CHANGED
|
@@ -501,7 +501,10 @@ interface WatermarkProps {
|
|
|
501
501
|
hidePoweredBy?: boolean;
|
|
502
502
|
/**
|
|
503
503
|
* m1k.app visitor-tracker slug, forwarded to the embedded PoweredByKit badge.
|
|
504
|
-
* Falls back to `NEXT_PUBLIC_M1K_SLUG
|
|
504
|
+
* Falls back to `NEXT_PUBLIC_M1K_SLUG` on Next. Vite apps pass it explicitly:
|
|
505
|
+
* `trackSlug={import.meta.env.VITE_M1K_SLUG}` — Vite only substitutes
|
|
506
|
+
* `import.meta.env` in app source, never inside kit's own bundle.
|
|
507
|
+
* No slug → no tracking (off by default).
|
|
505
508
|
*/
|
|
506
509
|
trackSlug?: string;
|
|
507
510
|
/** Set false to disable the visitor beacon even when a slug is present */
|
|
@@ -513,9 +516,22 @@ interface WatermarkProps {
|
|
|
513
516
|
today?: number;
|
|
514
517
|
total?: number;
|
|
515
518
|
};
|
|
519
|
+
/**
|
|
520
|
+
* Scale up the shell + credit group on wide screens, so a 430px phone shell
|
|
521
|
+
* doesn't shrink to a sliver in a field of watermark (it covers ~26% of a
|
|
522
|
+
* 1440px screen but only ~10% of a 2560px one).
|
|
523
|
+
*
|
|
524
|
+
* Default: `true` — a continuous scale driven by viewport width and capped
|
|
525
|
+
* by available viewport height. Wide-but-short screens stay at a smaller
|
|
526
|
+
* factor so flex layout never squashes the shell's proportions. The factor
|
|
527
|
+
* tops out at ×1.5 (see `.kit-stage`). Pass a number to pin one fixed factor
|
|
528
|
+
* everywhere, or `false` for 1:1 always. The watermark background itself is
|
|
529
|
+
* never scaled; it always fills the viewport.
|
|
530
|
+
*/
|
|
531
|
+
zoom?: boolean | number;
|
|
516
532
|
}
|
|
517
533
|
/** Estimate rendered width of a string. CJK chars ≈ 1.0×, Latin ≈ 0.62× font size. */
|
|
518
|
-
declare function Watermark({ children, color, text, maxWidth, sponsor, speed, hidePoweredBy, trackSlug, track, claimed, counts, }: WatermarkProps): react_jsx_runtime.JSX.Element;
|
|
534
|
+
declare function Watermark({ children, color, text, maxWidth, sponsor, speed, hidePoweredBy, trackSlug, track, claimed, counts, zoom, }: WatermarkProps): react_jsx_runtime.JSX.Element;
|
|
519
535
|
|
|
520
536
|
declare const colors: {
|
|
521
537
|
readonly blue: "#3b82f6";
|
|
@@ -977,9 +993,11 @@ interface PoweredByKitProps {
|
|
|
977
993
|
/** "default" for inside AppShell, "overlay" for on top of Watermark background */
|
|
978
994
|
variant?: "default" | "overlay";
|
|
979
995
|
/**
|
|
980
|
-
* m1k.app visitor-tracker slug. When set
|
|
981
|
-
*
|
|
982
|
-
*
|
|
996
|
+
* m1k.app visitor-tracker slug. When set a tiny hidden beacon counts each
|
|
997
|
+
* page view; no slug → no tracking (off by default). Next reads
|
|
998
|
+
* `NEXT_PUBLIC_M1K_SLUG` automatically; Vite apps must pass
|
|
999
|
+
* `import.meta.env.VITE_M1K_SLUG` in explicitly (see `resolveEnvSlug`).
|
|
1000
|
+
* Register a slug with `npx m1kkit track <url> --write`.
|
|
983
1001
|
*/
|
|
984
1002
|
slug?: string;
|
|
985
1003
|
/** Tracker host. Default: "www.m1k.app" (apex m1k.app는 www로 307 리다이렉트 → cross-origin fetch가 CORS로 깨지므로 www 직결) */
|
|
@@ -1191,8 +1209,18 @@ interface ActionCardProps {
|
|
|
1191
1209
|
declare function ActionCard({ title, items, children, state, onConfirm, onCancel, accent, labels, className, }: ActionCardProps): react_jsx_runtime.JSX.Element;
|
|
1192
1210
|
|
|
1193
1211
|
interface ListRowProps {
|
|
1194
|
-
/**
|
|
1212
|
+
/** Active highlight tint (and the `bar` color when enabled). Defaults to `var(--kit-accent)`. */
|
|
1195
1213
|
accent?: string;
|
|
1214
|
+
/**
|
|
1215
|
+
* Draw the left color bar. **Default: false.**
|
|
1216
|
+
*
|
|
1217
|
+
* A thick coloured stripe on one edge of a card is a well-known generated-UI
|
|
1218
|
+
* tell, so it is opt-in rather than the default look — a plain row keeps the
|
|
1219
|
+
* hairline border on all four sides instead. Turn it on where the color
|
|
1220
|
+
* actually carries meaning: a schedule/Gantt timeline where the stripe encodes
|
|
1221
|
+
* the category or calendar of each block.
|
|
1222
|
+
*/
|
|
1223
|
+
bar?: boolean;
|
|
1196
1224
|
/** Leading column, e.g. a time like "14:00" */
|
|
1197
1225
|
lead?: ReactNode;
|
|
1198
1226
|
/** Secondary leading line under `lead`, e.g. an end time */
|
|
@@ -1214,15 +1242,18 @@ interface ListRowProps {
|
|
|
1214
1242
|
className?: string;
|
|
1215
1243
|
}
|
|
1216
1244
|
/**
|
|
1217
|
-
* Timeline / list row:
|
|
1245
|
+
* Timeline / list row: an optional leading column (time), a title with an
|
|
1218
1246
|
* optional subtitle, and trailing content. Height can scale via `heightScale` —
|
|
1219
1247
|
* handy for schedules, to-dos, Gantt-style timelines, and time blocks.
|
|
1220
1248
|
*
|
|
1249
|
+
* The left color bar is opt-in (`bar`) — see `ListRowProps.bar`.
|
|
1250
|
+
*
|
|
1221
1251
|
* @example
|
|
1222
|
-
* <ListRow
|
|
1252
|
+
* <ListRow title="첫 항목" sub="설명" onClick={open} />
|
|
1253
|
+
* <ListRow bar accent="#7fc06a" lead="14:00" title="회의" sub="👥 김상훈" heightScale={2} />
|
|
1223
1254
|
* <ListRow lead="09:00" title="스탠드업" trailing="● 지금" active />
|
|
1224
1255
|
*/
|
|
1225
|
-
declare function ListRow({ accent, lead, leadSub, title, sub, trailing, active, heightScale, onClick, className, }: ListRowProps): react_jsx_runtime.JSX.Element;
|
|
1256
|
+
declare function ListRow({ accent, bar, lead, leadSub, title, sub, trailing, active, heightScale, onClick, className, }: ListRowProps): react_jsx_runtime.JSX.Element;
|
|
1226
1257
|
|
|
1227
1258
|
interface LinkifiedTextProps {
|
|
1228
1259
|
children: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -501,7 +501,10 @@ interface WatermarkProps {
|
|
|
501
501
|
hidePoweredBy?: boolean;
|
|
502
502
|
/**
|
|
503
503
|
* m1k.app visitor-tracker slug, forwarded to the embedded PoweredByKit badge.
|
|
504
|
-
* Falls back to `NEXT_PUBLIC_M1K_SLUG
|
|
504
|
+
* Falls back to `NEXT_PUBLIC_M1K_SLUG` on Next. Vite apps pass it explicitly:
|
|
505
|
+
* `trackSlug={import.meta.env.VITE_M1K_SLUG}` — Vite only substitutes
|
|
506
|
+
* `import.meta.env` in app source, never inside kit's own bundle.
|
|
507
|
+
* No slug → no tracking (off by default).
|
|
505
508
|
*/
|
|
506
509
|
trackSlug?: string;
|
|
507
510
|
/** Set false to disable the visitor beacon even when a slug is present */
|
|
@@ -513,9 +516,22 @@ interface WatermarkProps {
|
|
|
513
516
|
today?: number;
|
|
514
517
|
total?: number;
|
|
515
518
|
};
|
|
519
|
+
/**
|
|
520
|
+
* Scale up the shell + credit group on wide screens, so a 430px phone shell
|
|
521
|
+
* doesn't shrink to a sliver in a field of watermark (it covers ~26% of a
|
|
522
|
+
* 1440px screen but only ~10% of a 2560px one).
|
|
523
|
+
*
|
|
524
|
+
* Default: `true` — a continuous scale driven by viewport width and capped
|
|
525
|
+
* by available viewport height. Wide-but-short screens stay at a smaller
|
|
526
|
+
* factor so flex layout never squashes the shell's proportions. The factor
|
|
527
|
+
* tops out at ×1.5 (see `.kit-stage`). Pass a number to pin one fixed factor
|
|
528
|
+
* everywhere, or `false` for 1:1 always. The watermark background itself is
|
|
529
|
+
* never scaled; it always fills the viewport.
|
|
530
|
+
*/
|
|
531
|
+
zoom?: boolean | number;
|
|
516
532
|
}
|
|
517
533
|
/** Estimate rendered width of a string. CJK chars ≈ 1.0×, Latin ≈ 0.62× font size. */
|
|
518
|
-
declare function Watermark({ children, color, text, maxWidth, sponsor, speed, hidePoweredBy, trackSlug, track, claimed, counts, }: WatermarkProps): react_jsx_runtime.JSX.Element;
|
|
534
|
+
declare function Watermark({ children, color, text, maxWidth, sponsor, speed, hidePoweredBy, trackSlug, track, claimed, counts, zoom, }: WatermarkProps): react_jsx_runtime.JSX.Element;
|
|
519
535
|
|
|
520
536
|
declare const colors: {
|
|
521
537
|
readonly blue: "#3b82f6";
|
|
@@ -977,9 +993,11 @@ interface PoweredByKitProps {
|
|
|
977
993
|
/** "default" for inside AppShell, "overlay" for on top of Watermark background */
|
|
978
994
|
variant?: "default" | "overlay";
|
|
979
995
|
/**
|
|
980
|
-
* m1k.app visitor-tracker slug. When set
|
|
981
|
-
*
|
|
982
|
-
*
|
|
996
|
+
* m1k.app visitor-tracker slug. When set a tiny hidden beacon counts each
|
|
997
|
+
* page view; no slug → no tracking (off by default). Next reads
|
|
998
|
+
* `NEXT_PUBLIC_M1K_SLUG` automatically; Vite apps must pass
|
|
999
|
+
* `import.meta.env.VITE_M1K_SLUG` in explicitly (see `resolveEnvSlug`).
|
|
1000
|
+
* Register a slug with `npx m1kkit track <url> --write`.
|
|
983
1001
|
*/
|
|
984
1002
|
slug?: string;
|
|
985
1003
|
/** Tracker host. Default: "www.m1k.app" (apex m1k.app는 www로 307 리다이렉트 → cross-origin fetch가 CORS로 깨지므로 www 직결) */
|
|
@@ -1191,8 +1209,18 @@ interface ActionCardProps {
|
|
|
1191
1209
|
declare function ActionCard({ title, items, children, state, onConfirm, onCancel, accent, labels, className, }: ActionCardProps): react_jsx_runtime.JSX.Element;
|
|
1192
1210
|
|
|
1193
1211
|
interface ListRowProps {
|
|
1194
|
-
/**
|
|
1212
|
+
/** Active highlight tint (and the `bar` color when enabled). Defaults to `var(--kit-accent)`. */
|
|
1195
1213
|
accent?: string;
|
|
1214
|
+
/**
|
|
1215
|
+
* Draw the left color bar. **Default: false.**
|
|
1216
|
+
*
|
|
1217
|
+
* A thick coloured stripe on one edge of a card is a well-known generated-UI
|
|
1218
|
+
* tell, so it is opt-in rather than the default look — a plain row keeps the
|
|
1219
|
+
* hairline border on all four sides instead. Turn it on where the color
|
|
1220
|
+
* actually carries meaning: a schedule/Gantt timeline where the stripe encodes
|
|
1221
|
+
* the category or calendar of each block.
|
|
1222
|
+
*/
|
|
1223
|
+
bar?: boolean;
|
|
1196
1224
|
/** Leading column, e.g. a time like "14:00" */
|
|
1197
1225
|
lead?: ReactNode;
|
|
1198
1226
|
/** Secondary leading line under `lead`, e.g. an end time */
|
|
@@ -1214,15 +1242,18 @@ interface ListRowProps {
|
|
|
1214
1242
|
className?: string;
|
|
1215
1243
|
}
|
|
1216
1244
|
/**
|
|
1217
|
-
* Timeline / list row:
|
|
1245
|
+
* Timeline / list row: an optional leading column (time), a title with an
|
|
1218
1246
|
* optional subtitle, and trailing content. Height can scale via `heightScale` —
|
|
1219
1247
|
* handy for schedules, to-dos, Gantt-style timelines, and time blocks.
|
|
1220
1248
|
*
|
|
1249
|
+
* The left color bar is opt-in (`bar`) — see `ListRowProps.bar`.
|
|
1250
|
+
*
|
|
1221
1251
|
* @example
|
|
1222
|
-
* <ListRow
|
|
1252
|
+
* <ListRow title="첫 항목" sub="설명" onClick={open} />
|
|
1253
|
+
* <ListRow bar accent="#7fc06a" lead="14:00" title="회의" sub="👥 김상훈" heightScale={2} />
|
|
1223
1254
|
* <ListRow lead="09:00" title="스탠드업" trailing="● 지금" active />
|
|
1224
1255
|
*/
|
|
1225
|
-
declare function ListRow({ accent, lead, leadSub, title, sub, trailing, active, heightScale, onClick, className, }: ListRowProps): react_jsx_runtime.JSX.Element;
|
|
1256
|
+
declare function ListRow({ accent, bar, lead, leadSub, title, sub, trailing, active, heightScale, onClick, className, }: ListRowProps): react_jsx_runtime.JSX.Element;
|
|
1226
1257
|
|
|
1227
1258
|
interface LinkifiedTextProps {
|
|
1228
1259
|
children: string;
|