创作者工具 · 新资源

Kajabi Sage 设计系统.

构建一个面向创作者的分享面板,清晰呈现课程信息,提供明确的复制操作,并如实反馈剪贴板状态。探索 Sage 的 Rails 组件结构、已发布的字体排印规范,以及较新的外部加载 Pine 令牌层。

OpenDesign 指南7 个章节42 个参考条目原始应用指南
01

Kajabi Sage 设计系统界面预览

选择一门虚构课程,查看链接或消息,并复制与屏幕上完全一致的内容;也可手动复制。

创作者课程分享面板打开完整示例
独立呈现的原生 HTML 设计,参考了 Sage Copy Text 结构、已发布的字体规范,以及 Pine 当前的默认/浅色值。不包含 Sage 运行时或专有字体包。· 实现参考
02

Kajabi Sage 设计系统设计参考

Sage 公开的组件和字体文档,以及当前文档实际加载的默认/浅色 Pine 样式表。已发布的 Sage 字体表和较新的 Pine 别名属于不同参考资料;请勿将它们默认为相同内容。

当前 Pine 颜色角色

来源
名称 / 规则值 / 配置用途
--pine-color-primaryvar(--pine-color-grey-900)Sage 文档加载的当前默认/浅色 Pine 样式表快照。
--pine-color-primary-hovervar(--pine-color-grey-950)Sage 文档加载的当前默认/浅色 Pine 样式表快照。
--pine-color-textvar(--pine-color-grey-900)Sage 文档加载的当前默认/浅色 Pine 样式表快照。
--pine-color-text-primaryvar(--pine-color-white)Sage 文档加载的当前默认/浅色 Pine 样式表快照。
--pine-color-background-appvar(--pine-color-grey-100)Sage 文档加载的当前默认/浅色 Pine 样式表快照。
--pine-color-background-containervar(--pine-color-white)Sage 文档加载的当前默认/浅色 Pine 样式表快照。
--pine-color-bordervar(--pine-color-grey-300)Sage 文档加载的当前默认/浅色 Pine 样式表快照。

当前 Pine 基础色

来源
名称 / 规则值 / 配置用途
--pine-color-grey-100#f8f8f8 Sage 文档加载的当前默认/浅色 Pine 样式表快照。
--pine-color-grey-300#d2d1d1 Sage 文档加载的当前默认/浅色 Pine 样式表快照。
--pine-color-grey-900#343332 Sage 文档加载的当前默认/浅色 Pine 样式表快照。
--pine-color-grey-950#1a1a19 Sage 文档加载的当前默认/浅色 Pine 样式表快照。
--pine-color-white#ffffff Sage 文档加载的当前默认/浅色 Pine 样式表快照。

当前 Pine 尺寸和圆角

来源
名称 / 规则值 / 配置用途
--pine-dimension-xsvar(--pine-dimension-100)Sage 文档加载的当前默认/浅色 Pine 样式表快照。
--pine-dimension-smvar(--pine-dimension-200)Sage 文档加载的当前默认/浅色 Pine 样式表快照。
--pine-dimension-mdvar(--pine-dimension-300)Sage 文档加载的当前默认/浅色 Pine 样式表快照。
--pine-dimension-lgvar(--pine-dimension-400)Sage 文档加载的当前默认/浅色 Pine 样式表快照。
--pine-dimension-1008pxSage 文档加载的当前默认/浅色 Pine 样式表快照。
--pine-dimension-20016pxSage 文档加载的当前默认/浅色 Pine 样式表快照。
--pine-dimension-30024pxSage 文档加载的当前默认/浅色 Pine 样式表快照。
--pine-dimension-40032pxSage 文档加载的当前默认/浅色 Pine 样式表快照。
--pine-border-radius-mdvar(--pine-dimension-125)Sage 文档加载的当前默认/浅色 Pine 样式表快照。
--pine-dimension-12510pxSage 文档加载的当前默认/浅色 Pine 样式表快照。
--pine-border-radius-full9999pxSage 文档加载的当前默认/浅色 Pine 样式表快照。

当前 Pine 字体条目

来源
名称 / 规则值 / 配置用途
--pine-font-family-bodyvar(--pine-font-family-inter)Sage 文档加载的当前默认/浅色 Pine 样式表快照。
--pine-font-family-inter"Inter", system-ui, "Segoe UI", "Roboto", "Ubuntu", sans-serifSage 文档加载的当前默认/浅色 Pine 样式表快照。
--pine-font-size-body-mdvar(--pine-font-size-100)Sage 文档加载的当前默认/浅色 Pine 样式表快照。
--pine-font-size-10014pxSage 文档加载的当前默认/浅色 Pine 样式表快照。
--pine-font-size-body-lgvar(--pine-font-size-116)Sage 文档加载的当前默认/浅色 Pine 样式表快照。
--pine-font-size-11616pxSage 文档加载的当前默认/浅色 Pine 样式表快照。

已发布的 Sage 字体类

来源
名称 / 规则值 / 配置用途
t-sage-heading-140px / 48px; 700; -0.6px tracking已发布的文档字体规范。
t-sage-heading-232px / 40px; 700; -0.5px已发布的标题规范。
t-sage-heading-328px / 32px; 700; -0.15px已发布的标题规范。
t-sage-heading-424px / 32px; 600; -0.15px已发布的标题规范。
t-sage-body16px / 24px; 400已发布的正文规范。
t-sage-body-small14px / 20px; 400已发布的配套字体规范。
t-sage-body-xsmall12px / 16px; 400已发布的最小字号正文规范。
Body weight suffixes-med 500 / -semi 600 / -bold 700附加到正文类系列。

复制组件属性

来源
名称 / 规则值 / 配置用途
SageCopyText.valueRequired string要显示和复制的文本。
semiboldBoolean, default false整个区块强调显示。
SageCopyButton.fill_containerBoolean, default false复制按钮占满容器宽度。
SageCopyButton.borderlessBoolean example低强调度的复制操作。
SageCopyTextCard.truncate_contentstrue enables truncation仅在完整文本仍然可用时限制长内容的显示长度。
03

Kajabi Sage 设计系统完整指南

实用指南,介绍如何为真实界面选择、应用和评审此系统。

DESIGN-kajabi-sage.md

完整指导、实现起点和源代码链接。

下载指南

Kajabi Sage 设计系统:面向创作者工作流的分享面板

课程信息与链接并列时仍清晰可辨

Sage 服务于 Kajabi 的创作者和知识商业界面。课程分享面板是一个实用的小型组合,因为它将产品信息、较长的技术内容,以及其成功与页面状态可能互不相关的操作结合在一起。此示例提供两门虚构课程,配有原创封面图、学员链接和可用于电子邮件的消息。

摘自本 OpenDesign 指南

切换课程会同时更新两项内容。切换输出格式会更改要复制的文本,同时保持所选课程信息可见。页面不会发布或发送任何内容;唯一可选的副作用是用户点击剪贴板按钮时触发的操作。

阅读配套规范

Kajabi Sage 设计系统与 Pine 之间有明确的依赖边界

CSS 颜色函数不一定总是十六进制值查询

当前 Sage Assets README 指出,Pine 令牌由使用它的应用加载,不会打包进 sage-assets。文档区分了 sage-color() 和 sage-color-hex():前者返回语义 CSS 变量,后者读取旧版值,以便执行 Sass 颜色运算。现在会返回 var(...) 的颜色函数,不能安全地用于编译时十六进制颜色计算。

在线文档加载的是 @kajabi-ui/styles/dist/pine/pine.css。在该样式表默认的浅色根主题中,主色角色映射到 grey-900;而旧版 README 中的十六进制示例则是蓝色。指南将这两条信息分开说明:前者是当前使用的语义角色,后者用于演示旧版十六进制值的查询方式。新实现不得想当然地用其中一个替代另一个。

阅读配套规范

Kajabi Sage 设计系统在应用界面中保持克制,在内容中展现表现力

让操作颜色与其含义相对应

Sage 的颜色指南建议用颜色表示交互、选中状态和反馈,而不是为界面随意增添个性。示例中的应用框架保持中性,表现力丰富的颜色则来自课程插图。这样一来,复制操作很容易找到,也不会让每个面板都被涂上不同的状态色。

只有成功写入剪贴板后,才能显示成功状态。若剪贴板访问受阻,应提供便于手动复制的状态,而不是显示绿色成功消息。选中的课程和输出格式使用各自的控件状态,与上一次复制结果相互独立。

阅读配套规范

Kajabi Sage 设计系统 已发布的 Sage 规范与当前令牌别名

类型角色与 HTML 语义彼此独立

已发布的 Sage 表格提供 t-sage-heading 和 t-sage-body 类,并明确列出字号、行高和字重组合。可参考该表格复现文档中规定的样式。较新的 Pine 样式表也提供了自己的正文字体别名,其中包括 14 像素、中等字重的正文字体角色,因此当前集成应先确认组件实际使用的是哪一层。

为元素应用视觉上的标题类,不会改变该元素的语义层级。课程名称仍是标题,URL 仍是表单内容,复制操作仍是按钮。预览采用已发布的 Sage 32/40 标题样式和 16/24 正文样式,并使用系统字体作为后备;不会假称字体文件已打包在内。

阅读配套规范

Kajabi Sage 设计系统文案、复制按钮和复制文本卡片

根据内容形态选择结构

文档分别介绍了行内复制文本、卡片式区块和复制按钮。需要将标签与多行内容放在一起时,卡片式区块很实用。按钮可以填满容器,也可以采用无边框样式;半粗体强调则应用于组件层级。

示例使用只读文本区域显示当前内容。这是有意采用的原生实现:无法访问剪贴板时,用户仍可选择文本;同时,多行邮件内容也更易阅读。其值就是传给浏览器的完整内容,不含不可见的额外标签或过时的课程标识符。

  • 行内复制文本适合放在其他文案旁边的简短单值。
  • 复制卡片将相关内容归为一组,并留出足够宽度供用户查看。
  • 值较长或包含多行内容时,使用独立按钮明确呈现操作。

阅读配套规范

Kajabi Sage 设计系统应避免长链接撑破面板

双栏布局在小屏幕上改为纵向排列

桌面版示例将课程选择栏放在当前课程和分享控件旁边。在小屏幕上,课程选择栏会变成横向排列的两张卡片,分享面板则排在其后。文本框中的内容会在容器内换行,按钮仍会显示在下方。

官方的 Copy Text 指南建议为组件设置局部最大宽度,并允许截断卡片内容。本示例选择换行并支持手动选择,而不隐藏 URL 中的重要部分。内边距采用已核实的 Pine 8/16/24/32 尺寸阶梯;双栏比例和断点则由应用自行决定。

阅读配套规范

Kajabi Sage 设计系统完整公开的示例与可靠的原生实现方式

仅在用户触发操作后复制

独立示例会加载公开的 Pine 令牌,并自行提供 HTML 和剪贴板处理程序,无需 Sage 软件包账户即可运行。原生 Rails 示例则明确说明,它是为已有 Sage 应用组合而成;不会声称单独粘贴一个辅助程序就能安装整个系统。

Sage Assets 将 GitHub Packages 列为发布注册表。采用此方式的团队必须使用经批准的注册表访问权限,并在依赖语义颜色变量之前加载外部 Pine 层。文档还指出字体域名存在限制,因此使用系统字体作为后备,比默默假设品牌字体已成功加载更可靠。

  1. 通过 localhost 或 HTTPS 打开独立示例,并选择课程和内容格式。
  2. 触发复制操作;只有在剪贴板 Promise 成功完成后才报告成功,否则请用户选中文本并手动复制。
  3. 更改课程或格式时,清除旧的复制状态,避免状态提示对应的内容已经过时。

阅读配套规范

Kajabi Sage 设计系统组件示例

完整的独立交互示例

将完整文档保存为 index.html 并在浏览器中打开。独立的 HTML 实现参考了 Sage Copy Text 的结构、已发布的字体规格,以及 Pine 当前默认和浅色主题的取值。无需 Sage 运行时或专有字体包。

html
<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Course sharing — Sage interpretation</title><style>*{box-sizing:border-box}body{margin:0;background:#f8f8f8;color:#343332;font:16px/1.5 system-ui,sans-serif}main{max-width:1120px;margin:auto;padding:32px}.top{display:flex;justify-content:space-between;font-size:12px;letter-spacing:.08em;border-bottom:1px solid #d2d1d1;padding-bottom:16px;gap:16px}h1{font-size:32px;line-height:40px;letter-spacing:-.5px;margin:24px 0 8px}h2{font-size:24px;line-height:32px;margin:0 0 8px}.intro{margin:0 0 24px;color:#6c6a69}.grid{display:grid;grid-template-columns:240px 1fr;gap:24px}.courses{display:grid;gap:16px;align-content:start}.course{background:white;border:1px solid #d2d1d1;border-radius:10px;padding:12px;text-align:left;color:inherit;font:inherit;cursor:pointer}.course[aria-pressed=true]{border:2px solid #343332;padding:11px}.course small{display:block;font-size:12px;color:#6c6a69}.art{position:relative;overflow:hidden;border-radius:6px;display:grid;place-content:center;letter-spacing:.08em;font-size:11px;text-align:center}.art b{z-index:1;position:relative;line-height:1.2}.art.studio{background:#f2b9a5;color:#682923}.art.studio:before{content:'';position:absolute;border-radius:50%;width:150px;height:150px;background:#c26e4f;right:-40px;top:25px}.art.studio:after{content:'';position:absolute;width:55px;height:120px;background:#f9e7bc;transform:rotate(25deg);left:20px;top:-20px}.art.journal{background:#d1ddaa;color:#203a30}.art.journal:before{content:'';position:absolute;width:100px;height:160px;border:22px solid #68865b;border-radius:60% 0;transform:rotate(20deg);right:5px;top:-5px}.art.journal:after{content:'';position:absolute;width:90px;height:70px;border:18px solid #b29f59;border-radius:50%;left:-30px;bottom:-20px}.course .art{height:115px;margin-bottom:12px}.panel{background:white;padding:24px;border:1px solid #d2d1d1;border-radius:10px}.hero{display:grid;grid-template-columns:140px 1fr;gap:24px;align-items:center;margin-bottom:24px}.hero .art{height:140px}.hero p{font-size:14px;color:#6c6a69;margin:0}.format{display:flex;gap:16px;border-bottom:1px solid #d2d1d1;margin-bottom:24px}.format button{background:none;border:0;border-bottom:3px solid transparent;padding:10px 0;font:inherit;color:#6c6a69;cursor:pointer}.format button[aria-pressed=true]{border-bottom-color:#343332;color:#343332}label{display:block;font-size:14px;font-weight:600;margin-bottom:8px}textarea{width:100%;resize:vertical;min-height:135px;border:1px solid #d2d1d1;border-radius:10px;padding:16px;font:14px/1.5 system-ui;background:#fcfcfc;color:#343332}.copy{font:600 14px/20px system-ui;border:0;border-radius:9999px;background:#343332;color:white;padding:12px 24px;cursor:pointer;margin-top:16px}.copy:hover{background:#1a1a19}button:focus-visible,textarea:focus-visible{outline:3px solid #6c6a69;outline-offset:3px}.status{min-height:42px;font-size:13px;color:#4d4d4c}.foot{font-size:12px;color:#6c6a69;margin-top:24px}@media(max-width:650px){main{padding:20px}.grid{grid-template-columns:1fr}.courses{grid-template-columns:1fr 1fr;gap:12px}.course .art{height:85px}.hero{grid-template-columns:90px 1fr;gap:16px}.hero .art{height:110px}.panel{padding:20px}.top{flex-direction:column;gap:4px}h1{font-size:28px;line-height:36px}h2{font-size:20px;line-height:28px}}</style><main><header class="top"><b>CREATOR WORKSPACE</b><span>Local sharing specimen</span></header><h1>Give your course a clear invitation.</h1><p class="intro">Choose a sample course and prepare the exact text to share.</p><div class="grid"><nav class="courses" aria-label="Choose a course"><button class="course" data-course="studio" aria-pressed="true"><div class="art studio" aria-hidden="true"><b>STUDIO<br>NOTES</b></div><b>Studio Notes</b><small>6 lessons · Original sample</small></button><button class="course" data-course="journal" aria-pressed="false"><div class="art journal" aria-hidden="true"><b>FIELD<br>JOURNAL</b></div><b>Field Journal</b><small>4 lessons · Original sample</small></button></nav><section class="panel"><div class="hero"><div id="cover" class="art studio" aria-hidden="true"><b>STUDIO<br>NOTES</b></div><div><h2 id="title">Studio Notes</h2><p id="description">A fictional course about building a daily creative practice.</p></div></div><div class="format" aria-label="Copy format"><button data-format="link" aria-pressed="true">Course link</button><button data-format="message" aria-pressed="false">Invitation text</button></div><label for="payload">Text to copy</label><textarea id="payload" readonly></textarea><button id="copy" class="copy" type="button">Copy visible text</button><p class="status" id="status" role="status"></p></section></div><p class="foot">Independent Sage interpretation using verified Pine light-theme colors and dimensions. Original course covers; system-font fallback. No course is published and no message is sent.</p></main><script>const courses={studio:{name:'Studio Notes',slug:'studio-notes',desc:'A fictional course about building a daily creative practice.',art:'STUDIO<br>NOTES'},journal:{name:'Field Journal',slug:'field-journal',desc:'A fictional course about observing, collecting and recording ideas.',art:'FIELD<br>JOURNAL'}};let selected='studio',format='link';const payload=document.querySelector('#payload'),status=document.querySelector('#status');function render(){const c=courses[selected],url='https://example.com/courses/'+c.slug;document.querySelector('#title').textContent=c.name;document.querySelector('#description').textContent=c.desc;document.querySelector('#cover').className='art '+selected;document.querySelector('#cover').innerHTML='<b>'+c.art+'</b>';payload.value=format==='link'?url:'You are invited to explore '+c.name+'.\n\n'+c.desc+'\n\nView the sample: '+url;document.querySelectorAll('[data-course]').forEach(b=>b.setAttribute('aria-pressed',b.dataset.course===selected));document.querySelectorAll('[data-format]').forEach(b=>b.setAttribute('aria-pressed',b.dataset.format===format));status.textContent=''}document.querySelectorAll('[data-course]').forEach(b=>b.onclick=()=>{selected=b.dataset.course;render()});document.querySelectorAll('[data-format]').forEach(b=>b.onclick=()=>{format=b.dataset.format;render()});document.querySelector('#copy').onclick=async()=>{try{await navigator.clipboard.writeText(payload.value);status.textContent='Visible text copied.'}catch{payload.focus();payload.select();status.textContent='Copy was unavailable. The text is selected; copy it manually.'}};render();</script></html>

代码参考

  • 复制操作通过浏览器剪贴板 API 执行,并提供手动复制的备用方式。示例课程为原创;原生 Rails CopyText 组件另有文档说明。

完整的复制交互与失败处理

如果浏览器权限或嵌入环境不允许写入剪贴板,用户仍可选中复制文本。

html
<!doctype html>
<html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>Share a sample course link</title>
<!-- Public Pine token stylesheet used by the Sage documentation. Pin its reviewed package version in production. -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@kajabi-ui/styles@latest/dist/pine/pine.css">
<style>
body{font-family:var(--pine-font-family-body);color:var(--pine-color-text);background:var(--pine-color-background-app);padding:var(--pine-dimension-md)}
main{max-width:42rem;margin:auto;background:var(--pine-color-background-container);padding:var(--pine-dimension-md);border:var(--pine-border-width) solid var(--pine-color-border);border-radius:var(--pine-border-radius-md)}
textarea{box-sizing:border-box;width:100%;padding:var(--pine-dimension-sm);font:inherit;resize:vertical}
button{font:inherit;cursor:pointer;margin-top:var(--pine-dimension-sm);padding:var(--pine-dimension-xs) var(--pine-dimension-sm)}
button:focus-visible,textarea:focus-visible{outline:2px solid currentColor;outline-offset:3px}
</style><main><h1>Share a sample course link</h1><p>This is a fictional course URL.</p>
<label for="link">Text to copy</label><textarea id="link" readonly rows="2">https://example.com/courses/studio-notes</textarea>
<button type="button" id="copy">Copy course link</button><p id="message" role="status"></p></main>
<script>
const field=document.querySelector('#link'),message=document.querySelector('#message');
document.querySelector('#copy').onclick=async()=>{
 try{await navigator.clipboard.writeText(field.value);message.textContent='Course link copied.'}
 catch{field.focus();field.select();message.textContent='Copy was unavailable. The link is selected; copy it manually.'}
};
</script></html>

代码参考

  • 只有剪贴板 Promise 成功完成后,才显示“已复制”。
  • 显示的内容与复制的内容是同一个字符串。
  • 这是一个使用已发布 Pine 令牌的独立实现,并非虚构的 Sage 剪贴板 API。

Sage Rails 原生复制结构

在已完成配置的 Sage Rails 应用中使用文档所述的 Rails 辅助方法。

erb
<h2 class="t-sage-heading-4">Course link</h2>
<%= sage_component SageCopyTextCard, {} do %>
  <p><b>Course:</b> Studio Notes</p>
  <p>https://example.com/courses/studio-notes</p>
<% end %>
<%= sage_component SageCopyButton, { value: "https://example.com/courses/studio-notes", semibold: true, fill_container: true } %>

代码参考

  • 这些辅助工具需要与现有 Sage Rails、资源和系统JavaScript集成。
  • 整个组件使用半粗体,而不是添加影响范围较广的粗体覆盖样式。
04

Kajabi Sage 设计系统 Agent 设置

实现起点

完整、独立的公开令牌实现;保存为 HTML 文件,并通过 localhost 或 HTTPS 提供服务,以支持剪贴板功能。此实现不会加载 Sage Rails/React 组件。Sage 原生资源通过 GitHub Packages 注册表分发,而当前资源 README 要求单独加载 Pine 令牌。

html
<!doctype html>
<html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>Share a sample course link</title>
<!-- Public Pine token stylesheet used by the Sage documentation. Pin its reviewed package version in production. -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@kajabi-ui/styles@latest/dist/pine/pine.css">
<style>
body{font-family:var(--pine-font-family-body);color:var(--pine-color-text);background:var(--pine-color-background-app);padding:var(--pine-dimension-md)}
main{max-width:42rem;margin:auto;background:var(--pine-color-background-container);padding:var(--pine-dimension-md);border:var(--pine-border-width) solid var(--pine-color-border);border-radius:var(--pine-border-radius-md)}
textarea{box-sizing:border-box;width:100%;padding:var(--pine-dimension-sm);font:inherit;resize:vertical}
button{font:inherit;cursor:pointer;margin-top:var(--pine-dimension-sm);padding:var(--pine-dimension-xs) var(--pine-dimension-sm)}
button:focus-visible,textarea:focus-visible{outline:2px solid currentColor;outline-offset:3px}
</style><main><h1>Share a sample course link</h1><p>This is a fictional course URL.</p>
<label for="link">Text to copy</label><textarea id="link" readonly rows="2">https://example.com/courses/studio-notes</textarea>
<button type="button" id="copy">Copy course link</button><p id="message" role="status"></p></main>
<script>
const field=document.querySelector('#link'),message=document.querySelector('#message');
document.querySelector('#copy').onclick=async()=>{
 try{await navigator.clipboard.writeText(field.value);message.textContent='Course link copied.'}
 catch{field.focus();field.select();message.textContent='Copy was unavailable. The link is selected; copy it manually.'}
};
</script></html>

适用于你项目的提示词

Agent 提示词
创建一个 Kajabi Sage 课程分享面板,明确选择课程并复制分享内容。保留已发布的 Sage 字体规范与外部加载的 Pine 令牌层之间的区别。准确显示待复制内容,仅在复制成功后提示剪贴板操作成功;如果操作受阻,则提供手动选择文本的方式。不要接入真实课程、客户或内容发布系统。
05

Kajabi Sage 设计系统来源与范围

独立的 OpenDesign 指南。课程和封面插图均为原创。预览使用原生 HTML 和有文档记录的视觉参考;Rails 示例则需要现有且经过授权的 Sage 集成。不会发布或发送任何内容。