Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
564 changes: 564 additions & 0 deletions inc/Framework/ComponentLoader.php

Large diffs are not rendered by default.

42 changes: 41 additions & 1 deletion inc/helpers/custom-functions.php
Comment thread
aryanjasala marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,44 @@

declare( strict_types = 1 );

// Define custom functions here.
use rtCamp\Theme\Elementary\Framework\ComponentLoader;

if ( ! function_exists( 'elementary_theme_component' ) ) {

/**
* Render a component by name.
*
* Global convenience wrapper for ComponentLoader::render().
*
* @since 1.0.0
*
* @param string $name Component name (e.g. 'Button', 'Card').
* @param array $args Arguments to pass to the component.
* @param array $options Optional. Resolution options. See ComponentLoader::render().
*
* @return void
*/
function elementary_theme_component( string $name, array $args = [], array $options = [] ): void {
ComponentLoader::render( $name, $args, $options );
}
}

if ( ! function_exists( 'elementary_theme_get_component' ) ) {

/**
* Get the rendered HTML of a component as a string.
*
* Global convenience wrapper for ComponentLoader::get().
*
* @since 1.0.0
*
* @param string $name Component name (e.g. 'Button', 'Card').
* @param array $args Arguments to pass to the component.
* @param array $options Optional. Resolution options. See ComponentLoader::get().
*
* @return string Rendered component HTML.
*/
function elementary_theme_get_component( string $name, array $args = [], array $options = [] ): string {
return ComponentLoader::get( $name, $args, $options );
}
}
4 changes: 4 additions & 0 deletions phpcs.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@
</property>
</properties>
<exclude-pattern>tests/bootstrap.php</exclude-pattern>
<!-- Component partials are always require'd inside ComponentLoader::render(), so variables are method-scoped at runtime. -->
<exclude-pattern>src/components/*</exclude-pattern>
</rule>

<rule ref="WordPress-Docs">
Expand All @@ -112,6 +114,8 @@

<rule ref="WordPress.WP.GlobalVariablesOverride.Prohibited">
<exclude-pattern>tests/*</exclude-pattern>
<!-- Component partials are always require'd inside ComponentLoader::render(), so variables are method-scoped at runtime. -->
<exclude-pattern>src/components/*</exclude-pattern>
</rule>

<!--
Expand Down
9 changes: 9 additions & 0 deletions src/components/button/button.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* Button component script.
*/
document.addEventListener('DOMContentLoaded', () => {
const buttons = document.querySelectorAll('.elementary-button');
if (buttons.length > 0) {
console.log(`Elementary Button component loaded. Found ${buttons.length} buttons.`);
}
});
43 changes: 43 additions & 0 deletions src/components/button/button.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php
/**
* Button component.
*
* A render-only component that outputs a button or link element.
*
* @package rtCamp\Theme\Elementary
*
* @param array $args {
* Component arguments.
*
* @type string $label Button label text. Required.
* @type string $url URL for link buttons. Optional.
* @type string $class Additional CSS classes. Optional.
* @type string $tag HTML tag: 'a' or 'button'. Optional. Defaults to 'a' when $url is set, 'button' otherwise.
* }
*/

$label = $args['label'] ?? '';
$url = $args['url'] ?? '';
$class = $args['class'] ?? '';
$tag = $args['tag'] ?? ( ! empty( $url ) ? 'a' : 'button' );

if ( empty( $label ) ) {
return;
}

$css_class = trim( 'elementary-button ' . $class );

if ( 'a' === $tag && ! empty( $url ) ) {
printf(
'<a href="%s" class="%s">%s</a>',
esc_url( $url ),
esc_attr( $css_class ),
esc_html( $label )
);
} else {
printf(
'<button type="button" class="%s">%s</button>',
esc_attr( $css_class ),
esc_html( $label )
);
}
23 changes: 23 additions & 0 deletions src/components/button/button.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
.elementary-button {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0.75rem 1.5rem;
font-size: 1rem;
font-weight: 500;
line-height: 1.5;
color: #fff;
background-color: #0073aa;
border: 1px solid transparent;
border-radius: 4px;
text-decoration: none;
cursor: pointer;
transition: background-color 0.2s ease-in-out;

&:hover,
&:focus {
background-color: #005177;
text-decoration: none;
color: #fff;
}
}
9 changes: 9 additions & 0 deletions src/components/card/card.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* Card component script.
*/
document.addEventListener('DOMContentLoaded', () => {
const cards = document.querySelectorAll('.elementary-card');
if (cards.length > 0) {
console.log(`Elementary Card component loaded. Found ${cards.length} cards.`);
}
});
63 changes: 63 additions & 0 deletions src/components/card/card.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php
/**
* Card component.
*
* A render-only component that outputs a card with optional image, title,
* description, and action button. Demonstrates component composability
* by rendering the Button component internally.
*
* @package rtCamp\Theme\Elementary
*
* @param array $args {
* Component arguments.
*
* @type string $title Card title. Required.
* @type string $description Card description text. Optional.
* @type string $image_url Card image URL. Optional.
* @type string $url Card link URL. Optional.
* }
*/

use rtCamp\Theme\Elementary\Framework\ComponentLoader;

$title = $args['title'] ?? '';
$description = $args['description'] ?? '';
$image_url = $args['image_url'] ?? '';
$url = $args['url'] ?? '';

if ( empty( $title ) ) {
return;
}

?>
<div class="elementary-card">
<?php if ( ! empty( $image_url ) ) : ?>
<div class="elementary-card__image">
<img src="<?php echo esc_url( $image_url ); ?>" alt="<?php echo esc_attr( $title ); ?>" />
</div>
<?php endif; ?>

<div class="elementary-card__content">
<h3 class="elementary-card__title"><?php echo esc_html( $title ); ?></h3>

<?php if ( ! empty( $description ) ) : ?>
<p class="elementary-card__description"><?php echo esc_html( $description ); ?></p>
<?php endif; ?>

<?php if ( ! empty( $url ) ) : ?>
<div class="elementary-card__action">
<?php
ComponentLoader::render(
'Button',
[
'label' => $title,
'url' => $url,
'class' => 'elementary-card__button',
]
);
?>
</div>
<?php endif; ?>
</div>
</div>
<?php
53 changes: 53 additions & 0 deletions src/components/card/card.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
.elementary-card {
display: flex;
flex-direction: column;
background-color: #fff;
border: 1px solid #e2e8f0;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;

&:hover {
transform: translateY(-4px);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
}

&__image {
width: 100%;
height: 200px;
overflow: hidden;

img {
width: 100%;
height: 100%;
object-fit: cover;
}
}

&__content {
padding: 1.5rem;
display: flex;
flex-direction: column;
flex-grow: 1;
}

&__title {
font-size: 1.25rem;
font-weight: 600;
margin: 0 0 0.75rem;
color: #1a202c;
}

&__description {
font-size: 1rem;
color: #4a5568;
margin: 0 0 1.5rem;
line-height: 1.5;
flex-grow: 1;
}

&__action {
margin-top: auto;
}
}
Loading