Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reapply "Refactor testimonials section to use data collections" #84

Merged
merged 1 commit into from
Jun 8, 2024
Merged
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
126 changes: 1 addition & 125 deletions _pages/index.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -226,131 +226,7 @@
</div>
</div>
<!-- Start Testimonials -->
<section id="testimonials"
class="flex items-center justify-center w-full px-8 pt-10 md:pt-16 lg:pt-24 xl:pt-40 xl:px-0">
<div class="max-w-6xl mx-auto">
<div class="flex-col items-center ">
<div class="flex flex-col items-center justify-center w-full h-full max-w-2xl pr-8 mx-auto text-center">
<p class="my-5 text-base font-medium tracking-tight text-indigo-500 uppercase">
</p>
<h2 class="text-4xl font-extrabold leading-10 tracking-tight text-gray-900 sm:text-5xl sm:leading-none md:text-6xl lg:text-5xl xl:text-6xl">
Testimonials
</h2>
<p class="my-6 text-xl font-medium text-gray-500">
We are proud to hear that so many people use Hyde to build their websites.
Here are some of our favourite mentions.
</p>
</div>
<div class="flex flex-col items-center justify-center max-w-2xl py-8 mx-auto xl:flex-row xl:max-w-full">
<div class="w-full xl:w-1/2 xl:pr-8">
<blockquote class="my-4 flex flex-col-reverse items-center justify-between w-full col-span-1 p-6 text-center transition-all duration-200 bg-gray-100 rounded-lg md:flex-row md:text-left hover:bg-gray-50 hover:shadow ease">
<div class="flex flex-col sm:pr-8">
<div class="relative sm:pl-12">
<svg class="hidden sm:block absolute left-0 w-10 h-10 text-indigo-500 fill-current"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 125">
<path
d="M30.7 42c0 6.1 12.6 7 12.6 22 0 11-7.9 19.2-18.9 19.2C12.7 83.1 5 72.6 5 61.5c0-19.2 18-44.6 29.2-44.6 2.8 0 7.9 2 7.9 5.4S30.7 31.6 30.7 42zM82.4 42c0 6.1 12.6 7 12.6 22 0 11-7.9 19.2-18.9 19.2-11.8 0-19.5-10.5-19.5-21.6 0-19.2 18-44.6 29.2-44.6 2.8 0 7.9 2 7.9 5.4S82.4 31.6 82.4 42z" />
</svg>
<p class="mt-2 text-base text-gray-600 prose">
Caen (<a href="https://twitter.com/CodeWithCaen?ref_src=twsrc%5Etfw">@CodeWithCaen</a>) has made a website for his PHP-based static-site generator.
<br><br>What I&#39;m mostly impressed with is how clean and straightforward the documentation is. Writing good documentation is an art and Caen did an amazing job at it.
⭐️⭐️⭐️⭐️
</p>
</div>
<h3 class="pl-12 mt-3 text-base font-medium leading-5 text-gray-800 ">
<a href="https://twitter.com/SavvasStephnds" rel="author nofollow">@SavvasStephnds</a>
<span class="mt-1 text-sm leading-5 text-gray-500 ">- <a href="https://twitter.com/SavvasStephnds/status/1534928318503391233?ref_src=twsrc%5Etfw">Via Twitter</a></span>
</h3>
<p class="mt-1 text-sm leading-5 text-gray-500 "></p>
</div>
<img class="flex-shrink-0 object-cover w-24 h-24 mb-5 bg-gray-300 rounded-full md:mb-0"
onerror="this.onerror=null; this.src='https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png';"
src="https://pbs.twimg.com/profile_images/1567450524840075270/tceoqKT2_200x200.png"
alt="Profile image">
</blockquote>
<blockquote class="my-4 hidden lg:flex flex-col-reverse items-center justify-between w-full col-span-1 p-6 mt-12 text-center transition-all duration-200 bg-gray-100 rounded-lg md:flex-row md:text-left hover:bg-gray-50 hover:shadow ease">
<div class="flex flex-col sm:pr-10">
<div class="relative sm:pl-12">
<svg class="hidden sm:block absolute left-0 w-10 h-10 text-indigo-500 fill-current"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 125">
<path
d="M30.7 42c0 6.1 12.6 7 12.6 22 0 11-7.9 19.2-18.9 19.2C12.7 83.1 5 72.6 5 61.5c0-19.2 18-44.6 29.2-44.6 2.8 0 7.9 2 7.9 5.4S30.7 31.6 30.7 42zM82.4 42c0 6.1 12.6 7 12.6 22 0 11-7.9 19.2-18.9 19.2-11.8 0-19.5-10.5-19.5-21.6 0-19.2 18-44.6 29.2-44.6 2.8 0 7.9 2 7.9 5.4S82.4 31.6 82.4 42z" />
</svg>
<p class="mt-2 text-base text-gray-600 prose">Holy f. Your project is definitely one of my favorites of the whole <small>[startup]</small> tournament, I constantly keep an eye on the top 50 for it.
</p>
</div>
<h3 class="pl-12 mt-3 text-base font-medium leading-5 text-gray-800 ">
Felipe Lecot <span class="mt-1 text-sm leading-5 text-gray-500 ">- Director
- <a href="https://do2software.com" class="text-indigo-500" rel="author nofollow" title="External website">Do2 Software</a></span>
</h3>
<p class="mt-1 text-sm leading-5 text-gray-500 "></p>
</div>
<img class="flex-shrink-0 object-cover w-24 h-24 mb-5 bg-gray-300 rounded-full md:mb-0"
onerror="this.onerror=null; this.src='https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png';"
src="https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png"
alt="">
</blockquote>
</div>
<div class="w-full xl:w-1/2 xl:pl-8">
<blockquote class="my-4 flex flex-col-reverse items-center justify-between w-full col-span-1 p-6 text-center transition-all duration-200 bg-gray-100 rounded-lg md:flex-row md:text-left hover:bg-gray-50 hover:shadow ease">
<div class="flex flex-col sm:pr-10">
<div class="relative sm:pl-12">
<svg class="hidden sm:block absolute left-0 w-10 h-10 text-indigo-500 fill-current"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 125">
<path
d="M30.7 42c0 6.1 12.6 7 12.6 22 0 11-7.9 19.2-18.9 19.2C12.7 83.1 5 72.6 5 61.5c0-19.2 18-44.6 29.2-44.6 2.8 0 7.9 2 7.9 5.4S30.7 31.6 30.7 42zM82.4 42c0 6.1 12.6 7 12.6 22 0 11-7.9 19.2-18.9 19.2-11.8 0-19.5-10.5-19.5-21.6 0-19.2 18-44.6 29.2-44.6 2.8 0 7.9 2 7.9 5.4S82.4 31.6 82.4 42z" />
</svg>
<p class="mt-2 text-base text-gray-600 prose">
HydePHP is actually simple to setup. Now, I'm not a PHP developer and I can barely write a function in this language, but the project actually delivers on what it promises.
<br><br>
Docs: 10/10
Project: 10/10
</p>
</div>
<h3 class="pl-12 mt-3 text-base font-medium leading-5 text-gray-800 ">
<a href="https://twitter.com/peteralexbizjak" rel="author nofollow">@peteralexbizjak</a>
<span class="mt-1 text-sm leading-5 text-gray-500 ">- <a href="https://twitter.com/peteralexbizjak/status/1535177275649536001">Via Twitter</a></span>
</h3>
<p class="mt-1 text-sm leading-5 text-gray-500 "></p>
</div>
<img class="flex-shrink-0 object-cover w-24 h-24 mb-5 bg-gray-300 rounded-full md:mb-0"
onerror="this.onerror=null; this.src='https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png';"
src="https://pbs.twimg.com/profile_images/1608115407663005696/WflT9L0j_reasonably_small.jpg"
alt="Profile image">
</blockquote>
<blockquote class="my-4 flex flex-col-reverse items-center justify-between w-full col-span-1 p-6 mt-12 text-center transition-all duration-200 bg-gray-100 rounded-lg md:flex-row md:text-left hover:bg-gray-50 hover:shadow ease">
<div class="flex flex-col sm:pr-10">
<div class="relative sm:pl-12">
<svg class="hidden sm:block absolute left-0 w-10 h-10 text-indigo-500 fill-current"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 125">
<path
d="M30.7 42c0 6.1 12.6 7 12.6 22 0 11-7.9 19.2-18.9 19.2C12.7 83.1 5 72.6 5 61.5c0-19.2 18-44.6 29.2-44.6 2.8 0 7.9 2 7.9 5.4S30.7 31.6 30.7 42zM82.4 42c0 6.1 12.6 7 12.6 22 0 11-7.9 19.2-18.9 19.2-11.8 0-19.5-10.5-19.5-21.6 0-19.2 18-44.6 29.2-44.6 2.8 0 7.9 2 7.9 5.4S82.4 31.6 82.4 42z" />
</svg>
<p class="mt-2 text-base text-gray-600 prose">Want to have your mention here? Send a Tweet at
<a href="https://twitter.com/HydeFramework">@HydeFramework</a>, and/or use the hashtag
<a href="https://twitter.com/hashtag/HydePHP">#HydePHP</a>!
</p>
</div>
<h3 class="pl-12 mt-3 text-base font-medium leading-5 text-gray-800 ">
This could be you! <span class="mt-1 text-sm leading-5 text-gray-500 ">- CEO
SomeCompany</span>
</h3>
<p class="mt-1 text-sm leading-5 text-gray-500 "></p>
</div>
<img class="flex-shrink-0 object-cover w-24 h-24 mb-5 bg-gray-300 rounded-full md:mb-0"
onerror="this.onerror=null; this.src='https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png';"
src="https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png"
alt="">
</blockquote>
</div>
</div>
<footer class="text-center opacity-75">
<small>Testimonials may be edited for formatting, spelling, and brevity, but never content.</small>
<small>Want your own testimonial here? Want to remove yours? This <a class="text-indigo-700" href="https://github.com/hydephp/hydephp.com/blob/master/_pages/index.blade.php">page is open source</a>.</small>
</footer>
</div>
</div>
</section>
@include('testimonials')
<!-- End Testimonials-->
<!-- Blob SVG Border -->
<svg class="absolute bottom-0 w-full text-gray-100 fill-current" viewBox="0 0 1400 74" xmlns="http://www.w3.org/2000/svg"><path d="M0 24C87.243 11.422 173.12 5.133 257.633 5.133 468.305 5.133 578.027 74 700 74c136.015 0 290.882-96.208 481.234-68.867C1268.807 17.71 1341.73 24 1400 24v50H0V24z" /></svg>
Expand Down
18 changes: 18 additions & 0 deletions app/DataCollections/Types/Testimonials.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

declare(strict_types=1);

namespace App\DataCollections\Types;

use App\Extend\Concerns\DataCollectionType;

class Testimonials extends DataCollectionType
{
public string $name;
public ?string $title;
public ?string $company;
public ?string $company_url;
public ?string $twitter_link;
public ?string $twitter_username;
public string $markdown;
}
48 changes: 46 additions & 2 deletions app/Extend/Concerns/DataCollectionType.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

namespace App\Extend\Concerns;

use ReflectionClass;
use ReflectionProperty;
use InvalidArgumentException;

/**
* Contract for a custom data collection types.
*
Expand All @@ -11,16 +15,56 @@
*/
abstract class DataCollectionType
{
/**
* Automatically construct the data collection type from an array of collection data.
*
* @param array<string, mixed> $data Where mixed type is generally scalar or array.
*/
public function __construct(array $data = [])
{
foreach ($data as $key => $value) {
$schema = static::schema();

foreach ($schema as $key => $type) {
// Todo: Validate the key against the class properties
// - Validate all required properties are set
// - Validate properties are set to the correct type
// Todo: Set nullable properties to null if not set
// Todo: Add method hooks to run before/after construction

$this->{$key} = $value;
if (array_key_exists($key, $data)) {
$this->{$key} = $data[$key];
} else {
if (str_starts_with($type, '?')) {
$this->{$key} = null;
} else {
throw new InvalidArgumentException(sprintf("Missing required property '%s' for %s.", $key, static::class));
}
}
}
}

/**
* Get the class properties and their types using reflection.
*
* @return array<string, 'class-string'|'array'|'bool'|'callable'|'float'|'int'|'null'|'object'|'string'|'false'|'iterable'|'mixed'|'never'|'true'|'void'|'parent'|'self'|'static'> Associative array of property names over their types.
*/
protected static function schema(): array
{
$reflection = new ReflectionClass(static::class);
$properties = $reflection->getProperties(ReflectionProperty::IS_PUBLIC);

$schema = [];

foreach ($properties as $property) {
$type = $property->getType()->getName();

if ($property->getType()->allowsNull()) {
$type = '?'.$type; // Indicate nullable type
}

$schema[$property->getName()] = $type;
}

return $schema;
}
}
56 changes: 45 additions & 11 deletions app/Extend/DataCollections.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
namespace App\Extend;

use Hyde\Facades\Filesystem;
use Illuminate\Support\Collection;
use Hyde\Markdown\Models\FrontMatter;
use Illuminate\Support\Str;
use Hyde\Markdown\Models\MarkdownDocument;

/**
* @experimental Typed data collections class extension.
Expand All @@ -22,15 +24,51 @@ public static function yaml(string $name): static
return parent::yaml($name);
}

public static function markdown(string $name): static
{
if (static::hasType($name)) {
return static::getTypedMarkdown($name);
}

return parent::markdown($name);
}

protected static function hasType(string $name): bool
{
return Filesystem::exists(self::getTypePath($name)) || class_exists(self::getTypeClassname($name));
}

/**
* @return static<\App\Extend\Concerns\DataCollectionType>
*/
/** @return static<\App\Extend\Concerns\DataCollectionType> */
protected static function getTypedYaml(string $name): static
{
$className = self::getCallableTypeClassName($name);

return parent::yaml($name)->map(fn (FrontMatter $data) => new $className($data->toArray()));
}

/** @return static<\App\Extend\Concerns\DataCollectionType> */
protected static function getTypedMarkdown(string $name): static
{
$className = self::getCallableTypeClassName($name);
return parent::markdown($name)->reject(fn (MarkdownDocument $document, string $key) => basename($key) === 'README.md') // Patch until https://github.com/hydephp/develop/issues/1716
->map(fn (MarkdownDocument $document) => new $className(array_merge(
$document->matter()->toArray(),
['markdown' => $document->markdown()->body()]
)));
}

protected static function getTypePath(string $name): string
{
return sprintf('%s/%s/type.php', static::$sourceDirectory, $name);
}

protected static function getTypeClassname(string $name): string
{
return 'App\\DataCollections\\Types\\'.Str::studly($name);
}

/** @return class-string<\App\Extend\Concerns\DataCollectionType> */
protected static function getCallableTypeClassName(string $name): string
{
// Load the anonymous class and turn it into a new runtime class
$className = self::getTypeClassname($name);
Expand All @@ -42,17 +80,13 @@ protected static function getTypedYaml(string $name): static
class_alias($newClassName, $className);
}

/** @var \App\Extend\Concerns\DataCollectionType $className */
return parent::yaml($name)->map(fn (FrontMatter $data) => new $className($data->toArray()));
return $className;
}

protected static function getTypePath(string $name): string
protected static function findFiles(string $name, array|string $extensions): Collection
{
return sprintf('%s/%s/type.php', static::$sourceDirectory, $name);
}
// Depends on https://github.com/hydephp/develop/issues/1716

protected static function getTypeClassname(string $name): string
{
return 'App\\DataCollections\\Types\\'.Str::studly($name);
return parent::findFiles($name, $extensions)->reject(fn (string $file) => basename($file) === 'README.md');
}
}
31 changes: 31 additions & 0 deletions resources/collections/testimonials/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# HydePHP Testimonials

In this directory are front mattered Markdown partial files that each will become an entry on the [HydePHP Testimonials](https://hydephp.com#testimonials) homepage section.

## Adding a testimonial

To add a testimonial to the HydePHP Testimonials section, create a new Markdown file in this directory with the following format:

```markdown
---
name: "Author Name"
title: "Job Title" # Optional
company: "Company Name" # Optional
company_url: "https://company.com" # Optional
twitter_link: "https://twitter.com/username/status/1234567890" # If the testimonial was shared on Twitter
twitter_username: "username" # If the testimonial was shared on Twitter, this is used to link to the author name
---

The testimonial content goes here. It should be a brief quote that is no more than a few sentences long.
```

### Editing policy

Testimonials may be edited for formatting, spelling, and brevity, but never content.

### License and permissions

We operate under the assumption that if a testimonial is shared publicly, it is okay for us to share it on the HydePHP website.

If you are the author of a testimonial and would like it removed, you can contact us and we will remove it promptly.
You can also submit a [pull request](https://github.com/hydephp/hydephp.com/tree/master/resources/collections/testimonials) to remove it yourself.
8 changes: 8 additions & 0 deletions resources/collections/testimonials/felipe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
name: "Felipe Lecot"
title: "Director"
company: "Do2 Software"
company_url: "https://do2software.com"
---

Holy f. Your project is definitely one of my favorites of the whole [startup] tournament, I constantly keep an eye on the top 50 for it.
Loading
Loading