@tomako/tools-runtime 0.1.10 → 0.1.11

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tomako/tools-runtime",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "description": "Shared interactive tools runtime for Tomako-FE workspace dialogs and Tomako-SEO tool pages",
5
5
  "type": "module",
6
6
  "exports": {
@@ -78,7 +78,7 @@ function SectionHeading({
78
78
  <Target aria-hidden className="size-4" />
79
79
  </span>
80
80
  ) : null}
81
- <h3 className={cn("font-semibold text-[#111111]", isWorkspace ? "text-base" : "text-lg")}>
81
+ <h3 className={cn("min-w-0 break-words font-semibold text-[#111111]", isWorkspace ? "text-base" : "text-lg")}>
82
82
  {title}
83
83
  </h3>
84
84
  </div>
@@ -166,7 +166,7 @@ function BulletList({
166
166
  ) : (
167
167
  <CheckCircle2 aria-hidden className="mt-0.5 size-4 shrink-0 text-[#7A9B69]" />
168
168
  )}
169
- <span>{item}</span>
169
+ <span className="min-w-0 break-words">{item}</span>
170
170
  </li>
171
171
  ))}
172
172
  </ul>
@@ -242,14 +242,14 @@ function CardListView({
242
242
  <article
243
243
  key={`${title}-${index}`}
244
244
  className={cn(
245
- "border border-[#D8D4CA] bg-white p-5",
245
+ "min-w-0 border border-[#D8D4CA] bg-white p-5",
246
246
  isWorkspace
247
247
  ? "rounded-lg"
248
248
  : "rounded-[1.25rem] shadow-[0_12px_28px_rgba(17,17,17,0.05)]",
249
249
  )}
250
250
  >
251
- <div className="flex items-start justify-between gap-3">
252
- <h4 className="text-base font-semibold leading-tight text-[#111111]">{title}</h4>
251
+ <div className="flex min-w-0 items-start justify-between gap-3">
252
+ <h4 className="min-w-0 break-words text-base font-semibold leading-tight text-[#111111]">{title}</h4>
253
253
  <div className="flex shrink-0 items-center gap-2">
254
254
  {meta != null && meta !== "" ? (
255
255
  <span
@@ -270,7 +270,7 @@ function CardListView({
270
270
  </div>
271
271
  </div>
272
272
  {typeof body === "string" && body.trim() ? (
273
- <p className="mt-2 text-sm leading-6 text-[#555555]">
273
+ <p className="mt-2 break-words text-sm leading-6 text-[#555555]">
274
274
  {block.card.body?.label ? (
275
275
  <span className="font-semibold text-[#111111]">
276
276
  {pickL10n(block.card.body.label, locale)}:{" "}
@@ -288,7 +288,7 @@ function CardListView({
288
288
  {!isWorkspace ? <ListChecks aria-hidden className="size-3.5" /> : null}
289
289
  {pickL10n(listSpec.label, locale)}
290
290
  </p>
291
- <ul className="mt-1.5 list-disc space-y-1 pl-5 text-sm leading-6 text-[#555555]">
291
+ <ul className="mt-1.5 list-disc space-y-1 break-words pl-5 text-sm leading-6 text-[#555555]">
292
292
  {items.map((item) => (
293
293
  <li key={item}>{item}</li>
294
294
  ))}
@@ -297,7 +297,7 @@ function CardListView({
297
297
  );
298
298
  })}
299
299
  {typeof footer === "string" && footer.trim() ? (
300
- <p className="mt-3 rounded-2xl border border-[#F2D2B8] bg-[#FFF7EE] px-3 py-2 text-sm leading-6 text-[#7A4B22]">
300
+ <p className="mt-3 break-words rounded-2xl border border-[#F2D2B8] bg-[#FFF7EE] px-3 py-2 text-sm leading-6 text-[#7A4B22]">
301
301
  {block.card.footer?.label ? (
302
302
  <span className="font-semibold">
303
303
  {pickL10n(block.card.footer.label, locale)}:{" "}
@@ -503,7 +503,7 @@ export function ResultView({
503
503
  variant={variant}
504
504
  />
505
505
  ) : (
506
- <p key={entry.label} className="text-sm leading-6 text-[#3D3D3D]">
506
+ <p key={entry.label} className="break-words text-sm leading-6 text-[#3D3D3D]">
507
507
  <span className="font-semibold text-[#111111]">{entry.label}: </span>
508
508
  {entry.text}
509
509
  </p>
@@ -75,8 +75,8 @@ function TomatoParticleLoader({ statusLabel }: { statusLabel: string }) {
75
75
 
76
76
  canvas.width = width * devicePixelRatio;
77
77
  canvas.height = height * devicePixelRatio;
78
- canvas.style.width = `${width}px`;
79
- canvas.style.height = `${height}px`;
78
+ canvas.style.width = "100%";
79
+ canvas.style.height = "100%";
80
80
  context.setTransform(devicePixelRatio, 0, 0, devicePixelRatio, 0, 0);
81
81
  context.imageSmoothingEnabled = false;
82
82
 
@@ -172,8 +172,12 @@ function TomatoParticleLoader({ statusLabel }: { statusLabel: string }) {
172
172
  }, []);
173
173
 
174
174
  return (
175
- <div aria-label={statusLabel} className="mx-auto flex h-[190px] w-[320px] items-center justify-center overflow-hidden" role="status">
176
- <canvas ref={canvasRef} aria-hidden className="block" />
175
+ <div
176
+ aria-label={statusLabel}
177
+ className="mx-auto flex aspect-[32/19] w-full max-w-[320px] items-center justify-center overflow-hidden"
178
+ role="status"
179
+ >
180
+ <canvas ref={canvasRef} aria-hidden className="block h-full w-full" />
177
181
  </div>
178
182
  );
179
183
  }
@@ -24,11 +24,11 @@ export async function GtmReadinessChecklistContainer({ locale, spec }: ToolPageP
24
24
  "toolsPages.gtmReadinessChecklist.guide",
25
25
  );
26
26
  return (
27
- <ToolPageShell locale={locale} spec={spec}>
27
+ <ToolPageShell locale={locale} spec={spec} showDefaultHeader={false}>
28
28
  <ToolWorkspaceSection
29
29
  heading={t("workspaceTitle")}
30
30
  hint={t("workspaceHint")}
31
- badge={t("workspaceBadge")}
31
+ headingLevel="h1"
32
32
  >
33
33
  <GtmReadinessChecklistWidget />
34
34
  </ToolWorkspaceSection>
@@ -38,6 +38,30 @@ export function GtmReadinessChecklistWidget() {
38
38
 
39
39
  return (
40
40
  <section className="overflow-hidden rounded-[1.5rem] border border-[#E8E4DB] bg-white shadow-[0_18px_50px_rgba(17,17,17,0.06)]">
41
+ <div
42
+ aria-live="polite"
43
+ className="sticky top-14 z-20 border-b border-[#CFD9EE] bg-[#DAE3F6]/95 px-4 py-3 backdrop-blur lg:hidden"
44
+ >
45
+ <div className="flex items-center justify-between gap-4">
46
+ <div className="min-w-0">
47
+ <p className="text-xs font-semibold uppercase tracking-[0.06em] text-[#555555]">
48
+ {t("score")}
49
+ </p>
50
+ <p className="mt-1 truncate text-sm font-semibold text-[#111111]">
51
+ {result.tierLabel}
52
+ </p>
53
+ </div>
54
+ <p className="shrink-0 text-3xl font-semibold leading-none text-[#111111]">
55
+ {result.score}<span className="ml-1 text-base text-[#555555]">%</span>
56
+ </p>
57
+ </div>
58
+ <div className="mt-2 h-1.5 overflow-hidden rounded-full bg-white/80">
59
+ <div
60
+ className="h-full rounded-full bg-[#111111] transition-[width]"
61
+ style={{ width: `${result.score}%` }}
62
+ />
63
+ </div>
64
+ </div>
41
65
  <div className="grid lg:grid-cols-[1.12fr_0.88fr]">
42
66
  <div className="bg-white p-5 md:p-7">
43
67
  <p className="mb-6 max-w-2xl text-sm leading-6 text-[#555555]">{t("howToUse")}</p>
@@ -24,17 +24,11 @@ export async function OgImageGeneratorContainer({ locale, spec }: ToolPageProps)
24
24
  );
25
25
 
26
26
  return (
27
- <ToolPageShell
28
- locale={locale}
29
- spec={spec}
30
- heroVariant="immersive"
31
- heroBackgroundImage="/tools/og-image-generator-hero.webp"
32
- heroBackgroundAlt={t("heroVisualAlt")}
33
- >
27
+ <ToolPageShell locale={locale} spec={spec} showDefaultHeader={false}>
34
28
  <ToolWorkspaceSection
35
29
  heading={t("workspaceHeading")}
36
30
  hint={t("workspaceHint")}
37
- badge={t("workspaceBadge")}
31
+ headingLevel="h1"
38
32
  >
39
33
  <OgImageGenerator />
40
34
  </ToolWorkspaceSection>
@@ -320,7 +320,7 @@ export function OgImageGenerator() {
320
320
  return (
321
321
  <>
322
322
  <ToolWorkspaceLayout
323
- className="rounded-lg border-[#E5E5E5] shadow-[0_24px_70px_rgba(17,17,17,0.08)]"
323
+ className="rounded-lg border-[#E5E5E5] shadow-[0_24px_70px_rgba(17,17,17,0.08)] lg:h-[min(80vh,900px)] lg:min-h-[720px]"
324
324
  form={
325
325
  <form onSubmit={(event) => void submit(event)} className="grid gap-5">
326
326
  <div>
@@ -49,9 +49,9 @@ export function CandidateCard({
49
49
  : "";
50
50
 
51
51
  return (
52
- <article className="rounded-[1.35rem] border border-[#D8D4CA] bg-white p-5 shadow-[0_14px_34px_rgba(17,17,17,0.07)]">
52
+ <article className="min-w-0 rounded-[1.35rem] border border-[#D8D4CA] bg-white p-5 shadow-[0_14px_34px_rgba(17,17,17,0.07)]">
53
53
  <div className="flex flex-col gap-4 md:flex-row md:items-start md:justify-between">
54
- <div>
54
+ <div className="min-w-0">
55
55
  <div className="flex flex-wrap items-center gap-2">
56
56
  <span className="rounded-full bg-[#111111] px-3 py-1.5 text-xs font-semibold text-white">
57
57
  {copy.stages[candidate.stage] ??
@@ -71,7 +71,7 @@ export function CandidateCard({
71
71
  </span>
72
72
  ) : null}
73
73
  </div>
74
- <h3 className="mt-4 text-3xl font-semibold leading-none text-[#111111]">
74
+ <h3 className="mt-4 break-words text-3xl font-semibold leading-none text-[#111111]">
75
75
  {candidate.name}
76
76
  </h3>
77
77
  </div>
@@ -131,7 +131,7 @@ export function CandidateCard({
131
131
  {candidate.domains.slice(0, 4).map((domain) => (
132
132
  <span
133
133
  key={domain.domain}
134
- className="rounded-full border border-[#D8D4CA] bg-[#F7F6F2] px-3 py-1.5 text-xs font-semibold text-[#555555]"
134
+ className="max-w-full break-all rounded-full border border-[#D8D4CA] bg-[#F7F6F2] px-3 py-1.5 text-xs font-semibold text-[#555555]"
135
135
  >
136
136
  {domain.domain}: {domain.status}
137
137
  </span>
@@ -25,31 +25,13 @@ export async function StartupIdeaResearchContainer({ locale, spec }: ToolPagePro
25
25
  const faqItems = t.raw("faqItems") as readonly ToolFaqItem[];
26
26
 
27
27
  return (
28
- <ToolPageShell
29
- locale={locale}
30
- spec={spec}
31
- heroVariant="showcase"
32
- heroVisual={
33
- <ToolImageVisual
34
- src="/tools/startup-idea-research-hero.webp"
35
- alt={t("visualAlt.hero")}
36
- priority
37
- wide
38
- />
39
- }
40
- >
28
+ <ToolPageShell locale={locale} spec={spec} showDefaultHeader={false}>
41
29
  <ToolWorkspaceSection
42
30
  heading={t("workspaceHeading")}
43
31
  hint={t("workspaceHint")}
44
- badge={t("workspaceBadge")}
32
+ headingLevel="h1"
45
33
  >
46
- <div className="grid gap-8 xl:grid-cols-[1fr_0.42fr] xl:items-start">
47
- <StartupIdeaResearch />
48
- <ToolImageVisual
49
- src="/tools/startup-idea-research-workflow.webp"
50
- alt={t("visualAlt.workspace")}
51
- />
52
- </div>
34
+ <StartupIdeaResearch />
53
35
  </ToolWorkspaceSection>
54
36
 
55
37
  <section className="border-t border-[#E8E4DB] py-12 md:py-16">
@@ -60,6 +42,14 @@ export async function StartupIdeaResearchContainer({ locale, spec }: ToolPagePro
60
42
  <div className="mt-7">
61
43
  <ToolPlainTextGrid items={values} columns="four" />
62
44
  </div>
45
+ <div className="mt-8">
46
+ <ToolImageVisual
47
+ src="/tools/startup-idea-research-workflow.webp"
48
+ alt={t("visualAlt.workspace")}
49
+ priority
50
+ wide
51
+ />
52
+ </div>
63
53
  </section>
64
54
 
65
55
  <section className="grid gap-8 border-t border-[#E8E4DB] py-12 md:grid-cols-[0.95fr_1.05fr] md:items-center md:py-16">
@@ -209,9 +209,9 @@ export function Report({
209
209
  }}
210
210
  />
211
211
  </Field>
212
- <article className="rounded-[1.25rem] border border-[#E2E6EC] bg-[#FAFBFC] p-5">
213
- <h4 className="text-xl font-semibold text-[#111111]">{postTitle}</h4>
214
- <p className="mt-3 whitespace-pre-line text-sm leading-6 text-[#3D3D3D]">{postBody}</p>
212
+ <article className="min-w-0 rounded-[1.25rem] border border-[#E2E6EC] bg-[#FAFBFC] p-5">
213
+ <h4 className="break-words text-xl font-semibold text-[#111111]">{postTitle}</h4>
214
+ <p className="mt-3 whitespace-pre-line break-words text-sm leading-6 text-[#3D3D3D]">{postBody}</p>
215
215
  <div className="mt-4 flex flex-wrap gap-3">
216
216
  <Button variant="outline" onClick={() => void copyRecruitmentText()}>
217
217
  <Copy className="size-4" aria-hidden />
@@ -283,7 +283,7 @@ export function Report({
283
283
  <h3 className="text-sm font-semibold uppercase tracking-[0.06em] text-[#55708A]">{t("sections.sources")}</h3>
284
284
  <div className="mt-4 grid gap-2">
285
285
  {data.sources.length ? data.sources.map((source) => (
286
- <a key={`${source.label}-${source.url ?? ""}`} href={source.url} target="_blank" rel="noreferrer nofollow" className="text-sm font-medium text-[#075DF5] hover:underline">
286
+ <a key={`${source.label}-${source.url ?? ""}`} href={source.url} target="_blank" rel="noreferrer nofollow" className="break-all text-sm font-medium text-[#075DF5] hover:underline">
287
287
  {source.label}
288
288
  </a>
289
289
  )) : <p className="text-sm text-[#777777]">{t("emptyList")}</p>}
@@ -313,7 +313,7 @@ export function InsightCard({
313
313
  </h3>
314
314
  <ul className="mt-4 grid gap-3">
315
315
  {items.length ? items.slice(0, 7).map((item) => (
316
- <li key={item} className="text-sm leading-6 text-[#3D3D3D]">
316
+ <li key={item} className="break-words text-sm leading-6 text-[#3D3D3D]">
317
317
  {item}
318
318
  </li>
319
319
  )) : <li className="text-sm text-[#777777]">{empty}</li>}