madebyraygun/craft-component-library

为Craft CMS量身定制的组件库系统

1.0.0 2024-09-16 22:54 UTC

This package is auto-updated.

Last update: 2024-09-17 19:29:31 UTC


README

一个完整的组件库系统,用于构建、预览和维护前端Web组件,完全集成Craft CMS

内置基于浏览器的库查看器允许您遍历或搜索组件文件夹以预览每个组件,并显示有关组件模板、上下文数据和组件文档的有用信息。

插件对CSS和JavaScript框架无关,可以支持任何文件夹结构,包括嵌套和层次结构化的组件结构,以支持原子设计原则

演示存储库包含用于与Vite一起使用的代码示例,并包括使用伴随上下文加载插件的全矩阵块实现。

要求

此插件需要Craft CMS 4.10.0或更高版本,以及PHP 8.2或更高版本。

此插件可以与任何前端构建系统(webpack、mix等)一起使用,但底层使用Plugin Vite。在组件库演示存储库中可以找到使用Vite在前端上运行的完整功能演示。

配置

可选地,在Craft config目录中创建一个component-library.php文件。

示例配置

return [
    'browser' => [
      'enabled' => true,
      'requiresLogin' => false,
      'path' => 'component-library',
      'welcome' => '@docs/index',
      'preview' => '@preview',
    ]
    'root' => dirname(__DIR__) . '/library',
    'docs' => dirname(__DIR__) . '/library/docs',
    'aliases' => [
        '@elements' => '02-elements',
        '@modules' => '03-modules',
    ]
];
  • browser.enabled - <默认: true> 启用或禁用组件库浏览器。这仅禁用了组件的前端独立查看器,模板加载仍然功能正常。
  • browser.requiresLogin <默认: false> 要求用户登录才能访问组件库浏览器。必须启用浏览器才能使此设置生效。
  • browser.path <默认: component-library> 从网站根目录访问组件库浏览器的URL路径。
  • browser.welcome <默认: ''> 要在欢迎页面显示的markdown组件的handle。
  • browser.preview <默认: @preview> 在所有没有特定预览模板的设置中的组件上使用作为预览的默认模板。有关更多信息,请参阅预览
  • root <默认: 'library'> 组件库的根目录,默认为在craft应用程序文件夹中的名为library的文件夹。
  • docs <默认: '@root/docs'> 存储markdown文件的目录。
  • aliases <默认: []> 组件库内部目录的自定义简写别名。有关更多信息,请参阅别名和处理

组件

组件只是组件库目录中的文件夹,其中包含一个twig模板文件和其他相关文件。组件库浏览器将自动检测并使这些组件在任何Craft模板中都可用。

组件文件夹必须包含一个 twig 模板文件,通常还包括一个配置文件(*.config.json*.config.php),其中包含配置信息和用于填充模板的上下文数据。组件文件夹通常还包括用于样式的 .css.scss 文件,用于交互的 .js.ts 文件,以及可能包含用于说明使用的 readme.md 文件。

组件可以包含或扩展其他组件及其数据,从而在库浏览器中构建更复杂的组件甚至完整的布局。一个简单的例子可能是一个单独的 card 组件,它包含一个 heading 组件和一个 image 组件。然后,这个卡片组件可以由一个 cards 组包含,该组随后被包含在一个 blog 页面布局中。

注意:此插件不依赖于前端,并且不负责编译组件的 CSS 或 JavaScript。任何前端框架和构建系统都可以得到支持。我们已在演示仓库中包含了 Vite 实现的示例。

每个组件的句柄由组件在库中的路径定义。

示例

如果您在以下目录中有一个 button 组件

.
└── library/
    └── button/
        └── button.twig

您可以通过以下方式将其包含在您的 Craft 模板中

  {% include '@button/button' %}

如果组件目录和文件名相同(区分大小写),则可以使用句柄的简写形式

  {# looks for ~/button/button.twig  #}
  {% include '@button' %}

别名和句柄

当处理嵌套目录或长句柄时,定义别名以更短的句柄可能很有用。

示例:使用此结构

.
└── library/
    └── elements/
        └── button/
            └── button.twig

您可以使用以下方式代替完整路径

  {% include '@elements/button/button' %}

您可以在 component-library.php 中定义别名

'aliases' => [
    '@button' => 'elements/button',
]

现在,您可以通过这种方式包含组件

  {# looks for ~/elements/button/button.twig  #}
  {% include '@button/button' %}

实际上,此组件的简写句柄仅仅是

  {# looks for ~/elements/button/button.twig  #}
  {% include '@button' %}

别名还可以用于强制顶层文件夹的排序顺序,例如在实现原子设计文件夹层次结构时。例如,我们的文件夹名称可能如下所示:01-atoms02-molecules03-organisms

使用此文件夹结构

.
└── library/
    └── 01-atoms/
        └── button/
            └── button.twig

通过在我们的配置中添加别名

'aliases' => [
    '@atoms' => '01-atoms',
    '@molecules' => '02-molecules',
    '@organisms' => '03-organisms'
]

现在,您可以按如下方式调用按钮组件

  {% include '@atoms/button' %}

组件配置和上下文

每个组件都将有自己的配置文件来定义其设置和上下文。

上下文 的目的是使组件可以在无需从 CMS 获取真实数据的情况下单独开发和预览。当在库中开发组件时,将提供用于预览组件在不同状态下使用的模拟数据对象。

要为组件创建配置文件,您需要在该文件夹中创建一个与组件同名的 config.phpconfig.json 文件。

一个简单的例子可能如下所示

.
└── library/
    └── button/
        └── button.twig
        └── button.config.php

在配置文件中,您可以定义以下属性

return [
  'title' => 'Button', // Custom title for the component
  'hidden' => false, // Hides the component
  'preview' => '@preview', // The template to render the component
  'context' => [
    'text' => 'Lorem Ipsum Dolor',
    'class' => 'is-primary',
  ],
]

在定义了配置文件之后,您可以在组件模板中使用 context 对象,如下所示

  <button class="{{class|default('is-primary')}}">
    {{text|default('click me')}}
  </button>

组件变体

组件通常有多种实现,称为变体。例如,单个按钮组件可能有 primarysecondary 变体。变体还可以用于测试焦点或禁用状态。可以通过上下文、额外的模板文件或 两者 来定义变体。让我们尝试几个例子。

基于文件的变体

通过添加具有相同名称和双横杠后缀的新 twig 文件来创建基于文件的变体。给定以下目录结构

.
└── library/
    └── button/
        └── button.twig
        └── button--primary.twig

您可以通过以下方式包含按钮组件及其主要变体

  {% include '@button/button' %}
  {% include '@button/button--primary' %}

  {# or using the shorter handle #}
  {% include '@button' %}
  {% include '@button--primary' %}

您也可以为您的组件库定义不同的路径结构

.
└── library/
    └── toolbar/
        └── button.twig
        └── dropdown.twig
        └── dropdown--small.twig

然后使用以下方式包含它们

  {% include '@toolbar/button' %}
  {% include '@toolbar/dropdown' %}
  {% include '@toolbar/dropdown--small' %}

基于上下文的变体

基于上下文的变体通过在上下文定义中添加额外的 variants 数组来定义。在此,您可以看到我们在 heading.config.json 中添加了多个标题级别

{
  "name": "Heading",
  "hidden": false,
  "context": {
    "level": "h1",
    "class": "heading-1",
    "content": "Lorem Ipsum Dolor Sit Amet"
  },
  "variants": [
    {
      "name": "H2",
      "context": {
        "level": "h2",
        "class": "heading-2"
      }
    },
    {
      "name": "H3",
      "context": {
        "level": "h3",
        "class": "heading-3"
      }
    }
  ]
}

当未定义时,变体将从组件继承上下文。这意味着在上面的例子中,content属性将在变体上下文中可用。

引用其他组件

组件模板文件可以相互引用

.
└── library/
    └── button/
        └── button.twig
        └── button.config.php
    └── cta/
        └── cta.twig
        └── cta.config.php

cta.twig:

<div class="cta">
  <p>{{ctaText}}</p>
  {% include '@button' with button %}
</div>

此外,您还可以通过使用组件别名来引用其他组件的上下文,如下所示

cta.config.php:

return [
  'context' => [
    'ctaText' => 'Lorem ipsum dolor sit amet',
    'button' => '@button', //pulls in the entire @button context
  ]
]

return [
  'context' => [
    'ctaText' => 'Lorem ipsum dolor sit amet',
    'button' => [
      'text' => 'Custom text',
      'class' => '@button.class' //pulls in just class value from the button component 
    ]
  ]
]

当使用php配置文件时,您可以自由地使用任何PHP代码以更复杂的方式定义上下文对象。我们发现包含一个像Faker这样的数据模拟库很有用。以下是一个具有多个变体的标题组件的示例,所有内容都由Faker生成

<?php 

use Faker\Factory as Faker;
$faker = Faker::create();

$tagClassMap = [
	'h1' => 'heading-1',
	'h2' => 'heading-2',
	'h3' => 'heading-3',
	'h4' => 'heading-4',
];

$variants = [];

foreach ($tagClassMap as $level => $class) {
	$variants[] = [
		'name' => $level,
		'context' => [
			'level' => $level,
			'class' => $class,
			'text' => $faker->sentence()
		]
	];
}

$first = array_shift($variants);

return [
	'name' => $first['name'],
	'context' => $first['context'],
	'variants' => $variants
];

预览

库浏览器将使用在组件配置文件中定义的preview模板渲染组件预览。如果没有定义预览模板,则将使用默认预览模板。预览模板是库中声明的普通twig文件。您通常会定义一个预览模板来使用单个文件夹中的组件,如下所示

.
└── library/
    └── button/
        └── button.twig
        └── button.config.php
    └── preview/
        └── preview.twig
        └── preview--dark.twig

button.config.php中,您会定义要使用的预览模板,如下所示

return [
  'preview' => '@preview',
  'context' => ...
]

并且预览通常是组件的基础布局HTML包装器,如下所示

<!DOCTYPE html>
<html>
  <head>
    <title>Component Preview</title>
    {# if using built-in Vite dev server #}
    {{ craft.library.script("src/app.js") }} 
  </head>
  <body>
    <main>
      {% block main %}
        {{ yield|raw }}
      {% endblock %}
    </main>
  </body>
</html>

您还可能想使用您网站的实时布局来预览您的组件。您可以通过自定义preview.twig的内容来实现这一点,如下所示

{% extends "_layouts/_site" %}
{% block main %}
  {{ yield|raw }}
{% endblock %}

其中{{yield|raw}}将被渲染的组件的HTML输出所替换,而_layouts/_sitecraft/templates目录下的路径。

由于预览仅用于间接由每个组件使用,因此无需从浏览器中访问它们。您可以通过在配置文件中将hidden属性设置为如下来隐藏它们

return [
  'hidden' => true,
  'context' => ...
]

组件库文档

您可以在根项目级别以及单个组件级别记录组件库。

项目文档

项目文档可以作为markdown文件文件夹添加到组件库文件夹的/docs目录中。库浏览器将自动检测并使这些文件可用。所有*.md文件都使用gfm风味通过Craft Markdown Filter进行解析。有关完整的语法和格式,请参阅docs

此外,您可以将任何markdown文件用作库浏览器的欢迎页面,通过设置browser.welcome配置(请参阅配置)。

组件文档

每个组件都可以通过创建与组件同名的markdown文件来拥有自己的文档。例如,如果您有一个button组件,您可以在button.twig文件旁边创建一个button.md文件。该markdown文件将被解析并在组件预览的工具栏标签中显示。

示例

.
└── library/
    └── button/
        └── button.twig
        └── button.md

Vite集成

组件库包括完整的Vite支持。插件内部使用nystudio107/craft-vite来提供与Vite构建系统的无缝集成。这允许您在组件中使用最新的ES6+功能、SCSS、PostCSS等。请参阅我们在组件库演示仓库中的示例Vite实现

在Craft中使用您的组件

您可以直接通过传递必要的数据将您的组件加载到Craft twig模板中,如下所示

{% include '@modules/card/article with {url: '#', title: 'Card title'} %}

当处理更复杂的组件组或需要额外格式化数据时,这可能会变得令人厌烦。我们更喜欢使用Craft的模板钩子来格式化数据并将其注入到条目上下文中。这可以通过创建一个自定义模块来实现

craft/modules/pagecontext/components/HomepageEntryContext.php

  
namespace modules\pagecontext\components;

use Craft;

class HomepageEntryContext
{

  public static function Hook() 
  {

    Craft::$app->view->hook('homepage-entry-context', function(array &$context) {
    $context['homepage_entry_context'] = [
      'banner' => self::GetBanner($context['entry']),
      'pageContent' => self::GetPageContent($context['entry'])
    ];
  });
}
...

craft/templates/homepage/entry.twig

{% hook 'homepage-entry-context' %}
{% extends "_layouts/_site" %}
{% block main %}
  {% include '@modules/homepageBanner' with homepage_entry_context.banner %}
  {% include '@modules/pageContent' with homepage_entry_context.pageContent %}
{% endblock %}

更多示例包括在组件库演示仓库中。我们还包括了一些使用块加载器插件来格式化和填充更复杂的矩阵块数据的示例。