You've already forked framexEngine-pro
Firts up
This commit is contained in:
68
app/views/about/index.md
Normal file
68
app/views/about/index.md
Normal file
@@ -0,0 +1,68 @@
|
||||
|
||||
|
||||
# About Framex
|
||||
|
||||
Hi, I am **Thanos**. I have been involved with computers, hardware, and practical IT work since 1995. Framex is a small PHP project I built and refined through real use, mostly for fast static pages, custom CSS experiments, presentations, API-driven pages, and lightweight content sites.
|
||||
|
||||

|
||||
|
||||
## Why this project exists
|
||||
|
||||
Framex is built around one simple idea: a website should be easy to understand from its files.
|
||||
|
||||
Routes map to files in `app/views`, templates live in `templates`, public assets live in `public`, and styling is handled through Tailwind CSS 4 or any CSS approach you prefer. There is no heavy framework layer to learn before you can build a page.
|
||||
|
||||
## What it is good for
|
||||
|
||||
- **Static websites** that need clean URLs and reusable templates.
|
||||
- **Markdown documentation** with automatic typography and dark-mode support.
|
||||
- **Small business websites** where speed and maintainability matter.
|
||||
- **Custom landing pages** with modern Tailwind components.
|
||||
- **API-powered pages** when you need PHP logic without a large framework.
|
||||
- **Presentations and prototypes** that should stay portable and simple.
|
||||
|
||||
## Design goals
|
||||
|
||||
Framex tries to stay:
|
||||
|
||||
- **Lightweight:** only the pieces needed to render pages clearly.
|
||||
- **Fast:** no unnecessary runtime complexity.
|
||||
- **Readable:** routes, views, templates, and assets are easy to find.
|
||||
- **Flexible:** use PHP views, Markdown views, Tailwind CSS, or plain CSS.
|
||||
- **Practical:** built for developers who want to ship pages without ceremony.
|
||||
|
||||
## How pages work
|
||||
|
||||
A URL such as `/about` resolves to a file like:
|
||||
|
||||
```text
|
||||
app/views/about/index.md
|
||||
```
|
||||
|
||||
A URL such as `/demo/blog-post` resolves to:
|
||||
|
||||
```text
|
||||
app/views/demo/blog-post.php
|
||||
```
|
||||
|
||||
Markdown pages are automatically parsed and styled. PHP pages can use custom markup, arrays, loops, metadata, and reusable helpers.
|
||||
|
||||
## Usage
|
||||
|
||||
You can use, extend, modify, reduce, or rebuild this project for personal and commercial work. Treat it as a starting point, not a locked system.
|
||||
|
||||
Good next steps:
|
||||
|
||||
- Read the [documentation](/docs).
|
||||
- Explore the [demo pages](/demo).
|
||||
- Create a new PHP view in `app/views`.
|
||||
- Create a new Markdown page with `index.md`.
|
||||
- Rebuild CSS with `npm run build:css` when you add new Tailwind classes.
|
||||
|
||||
## Disclaimer
|
||||
|
||||
This is a personal project shared for developers and people who understand how to work with PHP projects. I have used it for years without issues, but you are responsible for how you use it, modify it, deploy it, and secure it.
|
||||
|
||||
Use it carefully, make backups, and review the code before using it in production.
|
||||
|
||||
**Enjoy building.**
|
||||
53
app/views/blocks/accordion/accordion-1.php
Normal file
53
app/views/blocks/accordion/accordion-1.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<div class="section">
|
||||
<div class="band">
|
||||
<div class="card space-y-4">
|
||||
<details class="group [&_summary::-webkit-details-marker]:hidden">
|
||||
<summary class="flex items-center justify-between gap-1.5 rounded-md border border-gray-100 dark:border-slate-800 bg-gray-50 dark:bg-slate-900 p-4 text-gray-900 dark:text-slate-300 ">
|
||||
<h2 class="text-lg font-medium">Lorem ipsum dolor sit amet consectetur adipisicing?</h2>
|
||||
|
||||
<svg class="size-5 shrink-0 transition-transform duration-300 group-open:-rotate-180" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
|
||||
</svg>
|
||||
</summary>
|
||||
|
||||
<p class="px-4 pt-4 text-gray-900 dark:text-slate-300">
|
||||
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Ab hic veritatis molestias culpa
|
||||
in, recusandae laboriosam neque aliquid libero nesciunt voluptate dicta quo officiis
|
||||
explicabo consequuntur distinctio corporis earum similique!
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<details class="group [&_summary::-webkit-details-marker]:hidden">
|
||||
<summary class="flex items-center justify-between gap-1.5 rounded-md border border-gray-100 dark:border-slate-800 bg-gray-50 dark:bg-slate-900 p-4 text-gray-900 dark:text-slate-300 ">
|
||||
<h2 class="text-lg font-medium">Lorem ipsum dolor sit amet consectetur adipisicing?</h2>
|
||||
|
||||
<svg class="size-5 shrink-0 transition-transform duration-300 group-open:-rotate-180" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
|
||||
</svg>
|
||||
</summary>
|
||||
|
||||
<p class="px-4 pt-4 text-gray-900 dark:text-slate-300">
|
||||
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Ab hic veritatis molestias culpa
|
||||
in, recusandae laboriosam neque aliquid libero nesciunt voluptate dicta quo officiis
|
||||
explicabo consequuntur distinctio corporis earum similique!
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<details class="group [&_summary::-webkit-details-marker]:hidden">
|
||||
<summary class="flex items-center justify-between gap-1.5 rounded-md border border-gray-100 dark:border-slate-800 bg-gray-50 dark:bg-slate-900 p-4 text-gray-900 dark:text-slate-300 ">
|
||||
<h2 class="text-lg font-medium">Lorem ipsum dolor sit amet consectetur adipisicing?</h2>
|
||||
|
||||
<svg class="size-5 shrink-0 transition-transform duration-300 group-open:-rotate-180" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
|
||||
</svg>
|
||||
</summary>
|
||||
|
||||
<p class="px-4 pt-4 text-gray-900 dark:text-slate-300">
|
||||
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Ab hic veritatis molestias culpa
|
||||
in, recusandae laboriosam neque aliquid libero nesciunt voluptate dicta quo officiis
|
||||
explicabo consequuntur distinctio corporis earum similique!
|
||||
</p>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
77
app/views/blocks/accordion/index.php
Normal file
77
app/views/blocks/accordion/index.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<section class="section">
|
||||
<div class="band">
|
||||
<div class="card">
|
||||
<div class="entry-section">
|
||||
<?php
|
||||
$serverURL = rtrim(parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH), '/') ?: '/';
|
||||
$parentURL = $serverURL === '/' ? '/' : dirname($serverURL);
|
||||
$parentURL = $parentURL === '\\' || $parentURL === '.' ? '/' : $parentURL;
|
||||
$folderSlug = basename($serverURL);
|
||||
$folderName = ucwords(str_replace(['-', '_'], ' ', $folderSlug));
|
||||
$directory = __DIR__;
|
||||
$items = scandir($directory) ?: [];
|
||||
|
||||
$folders = [];
|
||||
$files = [];
|
||||
|
||||
foreach ($items as $item) {
|
||||
if ($item === '.' || $item === '..' || str_starts_with($item, '.')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$path = $directory . DIRECTORY_SEPARATOR . $item;
|
||||
|
||||
if (is_dir($path)) {
|
||||
$folders[] = $item;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_file($path) && basename($item) !== 'index.php' && in_array(pathinfo($item, PATHINFO_EXTENSION), ['php', 'md'], true)) {
|
||||
$files[] = pathinfo($item, PATHINFO_FILENAME);
|
||||
}
|
||||
}
|
||||
|
||||
natcasesort($folders);
|
||||
natcasesort($files);
|
||||
?>
|
||||
<div class="flex justify-between items-center border-b border-slate-200 dark:border-slate-700 pb-5">
|
||||
<div class="text-4xl font-bold"><?= e($folderName) ?></div>
|
||||
<a class="btn btn-primary" href="<?= e($parentURL) ?>">
|
||||
Back
|
||||
</a>
|
||||
</div>
|
||||
<ul class="m-4">
|
||||
<?php
|
||||
foreach ($folders as $folder) :
|
||||
$itemName = ucwords(str_replace(['-', '_'], ' ', $folder)); ?>
|
||||
<li class="mt-2">
|
||||
<div class="flex items-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 12.75V12A2.25 2.25 0 0 1 4.5 9.75h15A2.25 2.25 0 0 1 21.75 12v.75m-8.69-6.44-2.12-2.12a1.5 1.5 0 0 0-1.061-.44H4.5A2.25 2.25 0 0 0 2.25 6v12a2.25 2.25 0 0 0 2.25 2.25h15A2.25 2.25 0 0 0 21.75 18V9a2.25 2.25 0 0 0-2.25-2.25h-5.379a1.5 1.5 0 0 1-1.06-.44Z" />
|
||||
</svg>
|
||||
|
||||
<a class=' ms-2 hover:text-blue-600 font-bold' href='<?= e(rtrim($serverURL, '/') . '/' . $folder) ?>'>
|
||||
<?= e($itemName) ?></a>
|
||||
</div>
|
||||
|
||||
</li>
|
||||
<?php endforeach ?>
|
||||
</ul>
|
||||
<ul class="m-4">
|
||||
<?php foreach ($files as $fileName) :
|
||||
$title = ucwords(str_replace(['-', '_'], ' ', $fileName)); ?>
|
||||
<li class="mt-2">
|
||||
<div class="flex items-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-5">
|
||||
<path fill-rule="evenodd" d="M8.22 5.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.75.75 0 0 1-1.06-1.06L11.94 10 8.22 6.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
|
||||
<a class='ms-1 hover:text-blue-600' href='<?= e(rtrim($serverURL, '/') . '/' . $fileName) ?>'><?= e($title) ?></a>
|
||||
</div>
|
||||
</li>
|
||||
<?php endforeach ?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
40
app/views/blocks/blog-list/blog-list-1.php
Normal file
40
app/views/blocks/blog-list/blog-list-1.php
Normal file
@@ -0,0 +1,40 @@
|
||||
|
||||
<section>
|
||||
<!-- Container -->
|
||||
<div class="mx-auto w-full max-w-7xl px-5 py-16 md:px-10 md:py-20">
|
||||
<!-- Title -->
|
||||
<h2 class="text-center mb-16 text-3xl font-bold md:text-5xl">
|
||||
The latest and greatest news
|
||||
</h2>
|
||||
<!-- Content -->
|
||||
<div class="mx-auto grid max-w-xl gap-5">
|
||||
<a href="javascript:void(0);" class="flex flex-col items-center pb-8 text-center border-b border-gray-300 sm:flex-row sm:text-left">
|
||||
<img src="<?= image(640,480) ?>" alt="" class="max-w-40 rounded-xl shadow-2xl" />
|
||||
<div class="px-8">
|
||||
<p class="mb-6 text-sm font-bold sm:text-base lg:mb-8">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit ut
|
||||
</p>
|
||||
<p class="text-sm text-gray-500">November 12, 2022</p>
|
||||
</div>
|
||||
</a>
|
||||
<a href="javascript:void(0);" class="flex flex-col items-center pb-8 text-center border-b border-gray-300 sm:flex-row sm:text-left">
|
||||
<img src="<?= image(640,480) ?>" alt="" class="max-w-40 rounded-xl shadow-2xl" />
|
||||
<div class="px-8">
|
||||
<p class="mb-6 text-sm font-bold sm:text-base lg:mb-8">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit ut
|
||||
</p>
|
||||
<p class="text-sm text-gray-500">November 12, 2022</p>
|
||||
</div>
|
||||
</a>
|
||||
<a href="javascript:void(0);" class="flex flex-col items-center pb-8 text-center border-b border-gray-300 sm:flex-row sm:text-left">
|
||||
<img src="<?= image(640,480) ?>" alt="" class="max-w-40 rounded-xl shadow-2xl" />
|
||||
<div class="px-8">
|
||||
<p class="mb-6 text-sm font-bold sm:text-base lg:mb-8">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit ut
|
||||
</p>
|
||||
<p class="text-sm text-gray-500">November 12, 2022</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
67
app/views/blocks/blog-list/blog-list-2.php
Normal file
67
app/views/blocks/blog-list/blog-list-2.php
Normal file
@@ -0,0 +1,67 @@
|
||||
|
||||
<section>
|
||||
<!-- Container -->
|
||||
<div class="mx-auto w-full max-w-7xl px-5 py-16 md:px-10 md:py-20">
|
||||
<!-- Component -->
|
||||
<div class="flex flex-col items-center">
|
||||
<h2 class="text-center text-3xl font-bold md:text-5xl">
|
||||
The latest and greatest news
|
||||
</h2>
|
||||
<p class="mb-8 mt-4 text-center text-sm text-gray-500 sm:text-base md:mb-12 lg:mb-16">
|
||||
Lorem ipsum dolor sit amet elit ut aliquam
|
||||
</p>
|
||||
<!-- Content -->
|
||||
<div class="mb-8 grid gap-5 sm:grid-cols-2 sm:justify-items-stretch md:mb-12 md:grid-cols-3 lg:mb-16 lg:gap-6">
|
||||
<!-- Item -->
|
||||
<a href="javascript:void(0);" class="flex flex-col gap-4 bg-white rounded-md shadow px-4 py-8 md:p-0">
|
||||
<img src="<?= image() ?>" alt="" class="rounded-t-lg object-cover" />
|
||||
<div class="flex flex-col items-start pb-5 px-4">
|
||||
|
||||
<p class="mb-4 text-xl font-bold md:text-2xl">
|
||||
The latest news with Flowspark
|
||||
</p>
|
||||
<div class="flex flex-col items-start text-sm text-gray-500 lg:flex-row lg:items-center">
|
||||
<p>Laila Bahar</p>
|
||||
<p class="mx-2 hidden lg:block">-</p>
|
||||
<p>6 mins read</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<!-- Item -->
|
||||
<a href="javascript:void(0);" class="flex flex-col gap-4 bg-white rounded-md shadow px-4 py-8 md:p-0">
|
||||
<img src="<?= image() ?>" alt="" class="rounded-t-lg object-cover" />
|
||||
<div class="flex flex-col items-start pb-5 px-4">
|
||||
|
||||
<p class="mb-4 text-xl font-bold md:text-2xl">
|
||||
The latest news with Flowspark
|
||||
</p>
|
||||
<div class="flex flex-col items-start text-sm text-gray-500 lg:flex-row lg:items-center">
|
||||
<p>Laila Bahar</p>
|
||||
<p class="mx-2 hidden lg:block">-</p>
|
||||
<p>6 mins read</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<!-- Item -->
|
||||
<a href="javascript:void(0);" class="flex flex-col gap-4 bg-white rounded-md shadow px-4 py-8 md:p-0">
|
||||
<img src="<?= image() ?>" alt="" class="rounded-t-lg object-cover" />
|
||||
<div class="flex flex-col items-start pb-5 px-4">
|
||||
|
||||
<p class="mb-4 text-xl font-bold md:text-2xl">
|
||||
The latest news with Flowspark
|
||||
</p>
|
||||
<div class="flex flex-col items-start text-sm text-gray-500 lg:flex-row lg:items-center">
|
||||
<p>Laila Bahar</p>
|
||||
<p class="mx-2 hidden lg:block">-</p>
|
||||
<p>6 mins read</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<!-- Button -->
|
||||
<a href="javascript:void(0);" class="rounded-md bg-black px-6 py-3 text-center font-semibold text-white">
|
||||
View More
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
96
app/views/blocks/blog-list/blog-list-3.php
Normal file
96
app/views/blocks/blog-list/blog-list-3.php
Normal file
@@ -0,0 +1,96 @@
|
||||
|
||||
<section>
|
||||
<!-- Container -->
|
||||
<div class="band">
|
||||
<!-- Title -->
|
||||
<h2 class="text-center text-3xl font-bold md:text-5xl md:text-left">
|
||||
The latest and greatest news
|
||||
</h2>
|
||||
<p class="mb-8 mt-4 text-center text-sm text-gray-500 sm:text-base md:mb-12 lg:mb-16 md:text-left">
|
||||
Lorem ipsum dolor sit amet elit ut aliquam
|
||||
</p>
|
||||
<!-- Content -->
|
||||
<div class="mx-auto grid gap-8 md:grid-cols-2">
|
||||
<a href="javascript:void(0);" class="flex flex-col gap-4 rounded-md [grid-area:1/1/4/2] c-grid-area-1_1_4_2 md:pr-8">
|
||||
<img src="<?= image() ?>" alt="" class="inline-block h-72 w-full rounded object-cover" />
|
||||
<div class="flex flex-col items-start py-4">
|
||||
<div class="mb-4 rounded-md bg-gray-100 dark:bg-slate-900 px-2 py-1.5">
|
||||
<p class="text-sm eyebrow">
|
||||
FramexEngine
|
||||
</p>
|
||||
</div>
|
||||
<p class="mb-4 text-xl font-bold md:text-2xl">
|
||||
The latest news with Flowspark
|
||||
</p>
|
||||
<div class="flex flex-col text-sm text-gray-500 md:flex-row">
|
||||
<p>Laila Bahar</p>
|
||||
<p class="mx-2 hidden md:block">-</p>
|
||||
<p>6 mins read</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<div class="md:flex md:justify-between md:flex-col">
|
||||
<a href="javascript:void(0);" class="flex flex-col pb-5 md:mb-3 md:flex-row md:border-b md:border-gray-300">
|
||||
<img src="<?= image() ?>" alt="" class="inline-block h-60 w-full rounded object-cover md:h-32 md:w-32" />
|
||||
<div class="flex flex-col items-start pt-4 md:px-8">
|
||||
<div class="mb-2 rounded-md bg-gray-100 dark:bg-slate-900 px-2 py-1.5">
|
||||
<p class="text-sm eyebrow">
|
||||
FramexEngine
|
||||
</p>
|
||||
</div>
|
||||
<p class="mb-2 text-sm font-bold sm:text-base">
|
||||
Here is the title for this blog
|
||||
</p>
|
||||
<div class="flex flex-col items-start">
|
||||
<div class="flex flex-col text-sm text-gray-500 sm:text-base md:flex-row md:items-center">
|
||||
<p>Laila Bahar</p>
|
||||
<p class="mx-2 hidden md:block">-</p>
|
||||
<p>6 mins read</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="javascript:void(0);" class="flex flex-col pb-5 md:mb-3 md:flex-row md:border-b md:border-gray-300">
|
||||
<img src="<?= image() ?>" alt="" class="inline-block h-60 w-full rounded object-cover md:h-32 md:w-32" />
|
||||
<div class="flex flex-col items-start pt-4 md:px-8">
|
||||
<div class="mb-2 rounded-md bg-gray-100 dark:bg-slate-900 px-2 py-1.5">
|
||||
<p class="text-sm eyebrow">
|
||||
FramexEngine
|
||||
</p>
|
||||
</div>
|
||||
<p class="mb-2 text-sm font-bold sm:text-base">
|
||||
Here is the title for this blog
|
||||
</p>
|
||||
<div class="flex flex-col items-start">
|
||||
<div class="flex flex-col text-sm text-gray-500 sm:text-base md:flex-row md:items-center">
|
||||
<p>Laila Bahar</p>
|
||||
<p class="mx-2 hidden md:block">-</p>
|
||||
<p>6 mins read</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="javascript:void(0);" class="flex flex-col pb-5 md:mb-3 md:flex-row md:border-b md:border-gray-300">
|
||||
<img src="<?= image() ?>" alt="" class="inline-block h-60 w-full rounded object-cover md:h-32 md:w-32" />
|
||||
<div class="flex flex-col items-start pt-4 md:px-8">
|
||||
<div class="mb-2 rounded-md bg-gray-100 dark:bg-slate-900 px-2 py-1.5">
|
||||
<p class="text-sm eyebrow">
|
||||
FramexEngine
|
||||
</p>
|
||||
</div>
|
||||
<p class="mb-2 text-sm font-bold sm:text-base">
|
||||
Here is the title for this blog
|
||||
</p>
|
||||
<div class="flex flex-col items-start">
|
||||
<div class="flex flex-col text-sm text-gray-500 sm:text-base md:flex-row md:items-center">
|
||||
<p>Laila Bahar</p>
|
||||
<p class="mx-2 hidden md:block">-</p>
|
||||
<p>6 mins read</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
155
app/views/blocks/blog-list/blog-list-4.php
Normal file
155
app/views/blocks/blog-list/blog-list-4.php
Normal file
@@ -0,0 +1,155 @@
|
||||
|
||||
<section>
|
||||
<!-- Container -->
|
||||
<div class="mx-auto w-full max-w-7xl px-5 py-16 md:px-10 md:py-20">
|
||||
<div class="text-center mb-12">
|
||||
<!-- Title -->
|
||||
<h2 class="mb-4 mt-6 text-3xl font-bold md:text-5xl">
|
||||
The latest and greatest news
|
||||
</h2>
|
||||
<p class="text-gray-500 mt-2">
|
||||
Lorem ipsum dolor sit amet elit ut aliquam
|
||||
</p>
|
||||
<!-- Buttons -->
|
||||
<div class="my-10 md:my-20 flex flex-col md:flex-row justify-center gap-3">
|
||||
<button class="px-4 py-2 bg-gray-100 font-semibold rounded-full">
|
||||
Engaging Articles
|
||||
</button>
|
||||
<button class="px-4 py-2 bg-black text-white font-semibold rounded-full">
|
||||
Product Updates
|
||||
</button>
|
||||
<button class="px-4 py-2 bg-gray-100 font-semibold rounded-full">
|
||||
Reflex Workflows
|
||||
</button>
|
||||
<button class="px-4 py-2 bg-gray-100 font-semibold rounded-full">
|
||||
Artificial Intelligence
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Blog Content -->
|
||||
<div class="max-w-6xl mx-auto">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
|
||||
<!-- Blog Item -->
|
||||
<div class=" bg-gray-50 rounded-lg overflow-hidden">
|
||||
<div class="relative h-80">
|
||||
<img class="h-80 w-full object-cover" src="<?= image() ?>" alt="" />
|
||||
<a class="absolute bottom-5 right-5 btn btn-secondary ">
|
||||
Product Updates
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="p-4 flex justify-between items-center">
|
||||
<div>
|
||||
<h2 class="text-lg font-semibold mt-2">
|
||||
Here is the title for this News
|
||||
</h2>
|
||||
<p>Lorem ipsum dolor sit amet elit ut aliquam</p>
|
||||
</div>
|
||||
|
||||
<button class="cursor-pointer h-14 w-14">
|
||||
<svg class="h-14 w-14" width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M30.0001 52.5001C42.4265 52.5001 52.5001 42.4265 52.5001 30.0001C52.5001 17.5736 42.4265 7.5 30.0001 7.5C17.5736 7.5 7.5 17.5736 7.5 30.0001C7.5 42.4265 17.5736 52.5001 30.0001 52.5001Z" fill="black" stroke="black" stroke-width="2" stroke-miterlimit="10" />
|
||||
<path d="M31.4297 37.9454L39.375 30L31.4297 22.0547" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M20.625 30H39.3751" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Blog Item -->
|
||||
<div class="relative bg-gray-50 rounded-lg overflow-hidden">
|
||||
<div class="relative h-80">
|
||||
<img class="h-80 w-full object-cover" src="<?= image() ?>" alt="" />
|
||||
<a class="absolute bottom-5 right-5 btn btn-secondary ">
|
||||
Product Updates
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="p-4 flex justify-between items-center">
|
||||
<div>
|
||||
<h2 class="text-lg font-semibold mt-2">
|
||||
Here is the title for this News
|
||||
</h2>
|
||||
<p>Lorem ipsum dolor sit amet elit ut aliquam</p>
|
||||
</div>
|
||||
|
||||
<button class="cursor-pointer h-14 w-14">
|
||||
<svg class="h-14 w-14" width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M30.0001 52.5001C42.4265 52.5001 52.5001 42.4265 52.5001 30.0001C52.5001 17.5736 42.4265 7.5 30.0001 7.5C17.5736 7.5 7.5 17.5736 7.5 30.0001C7.5 42.4265 17.5736 52.5001 30.0001 52.5001Z" fill="black" stroke="black" stroke-width="2" stroke-miterlimit="10" />
|
||||
<path d="M31.4297 37.9454L39.375 30L31.4297 22.0547" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M20.625 30H39.3751" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<!-- Blog Item -->
|
||||
<div class="bg-gray-50 rounded-lg overflow-hidden">
|
||||
<div class="relative h-72">
|
||||
<img class="h-72 w-full object-cover" src="<?= image() ?>" alt="" />
|
||||
<a class="absolute bottom-5 right-5 btn btn-secondary ">
|
||||
Product Updates
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="p-4">
|
||||
<h2 class="text-lg font-semibold mt-2">
|
||||
Here is the title for this News
|
||||
</h2>
|
||||
<p class="text-gray-500">
|
||||
We make every expression of Hero Spirits with precision and
|
||||
passion
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Blog Item -->
|
||||
<div class=" bg-gray-50 rounded-lg overflow-hidden">
|
||||
<div class="relative h-72">
|
||||
<img class="h-72 w-full object-cover" src="<?= image() ?>" alt="" />
|
||||
<a class="absolute bottom-5 right-5 btn btn-secondary ">
|
||||
Product Updates
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="p-4">
|
||||
<h2 class="text-lg font-semibold mt-2">
|
||||
Here is the title for this News
|
||||
</h2>
|
||||
<p class="text-gray-500">
|
||||
We make every expression of Hero Spirits with precision and
|
||||
passion
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Blog Item -->
|
||||
<div class="bg-gray-50 rounded-lg overflow-hidden">
|
||||
<div class="relative h-72">
|
||||
<img class="h-72 w-full object-cover" src="<?= image() ?>" alt="" />
|
||||
<a class="absolute bottom-5 right-5 btn btn-secondary ">
|
||||
Product Updates
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="p-4">
|
||||
<h2 class="text-lg font-semibold mt-2">
|
||||
Here is the title for this News
|
||||
</h2>
|
||||
<p class="text-gray-500">
|
||||
We make every expression of Hero Spirits with precision and
|
||||
passion
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Button -->
|
||||
<div class="mt-10 md:mt-20 text-center">
|
||||
<button class="px-6 py-2 bg-black text-white rounded-lg">
|
||||
Load More
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
77
app/views/blocks/blog-list/index.php
Normal file
77
app/views/blocks/blog-list/index.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<section class="section">
|
||||
<div class="band">
|
||||
<div class="card">
|
||||
<div class="entry-section">
|
||||
<?php
|
||||
$serverURL = rtrim(parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH), '/') ?: '/';
|
||||
$parentURL = $serverURL === '/' ? '/' : dirname($serverURL);
|
||||
$parentURL = $parentURL === '\\' || $parentURL === '.' ? '/' : $parentURL;
|
||||
$folderSlug = basename($serverURL);
|
||||
$folderName = ucwords(str_replace(['-', '_'], ' ', $folderSlug));
|
||||
$directory = __DIR__;
|
||||
$items = scandir($directory) ?: [];
|
||||
|
||||
$folders = [];
|
||||
$files = [];
|
||||
|
||||
foreach ($items as $item) {
|
||||
if ($item === '.' || $item === '..' || str_starts_with($item, '.')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$path = $directory . DIRECTORY_SEPARATOR . $item;
|
||||
|
||||
if (is_dir($path)) {
|
||||
$folders[] = $item;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_file($path) && basename($item) !== 'index.php' && in_array(pathinfo($item, PATHINFO_EXTENSION), ['php', 'md'], true)) {
|
||||
$files[] = pathinfo($item, PATHINFO_FILENAME);
|
||||
}
|
||||
}
|
||||
|
||||
natcasesort($folders);
|
||||
natcasesort($files);
|
||||
?>
|
||||
<div class="flex justify-between items-center border-b border-slate-200 dark:border-slate-700 pb-5">
|
||||
<div class="text-4xl font-bold"><?= e($folderName) ?></div>
|
||||
<a class="btn btn-primary" href="<?= e($parentURL) ?>">
|
||||
Back
|
||||
</a>
|
||||
</div>
|
||||
<ul class="m-4">
|
||||
<?php
|
||||
foreach ($folders as $folder) :
|
||||
$itemName = ucwords(str_replace(['-', '_'], ' ', $folder)); ?>
|
||||
<li class="mt-2">
|
||||
<div class="flex items-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 12.75V12A2.25 2.25 0 0 1 4.5 9.75h15A2.25 2.25 0 0 1 21.75 12v.75m-8.69-6.44-2.12-2.12a1.5 1.5 0 0 0-1.061-.44H4.5A2.25 2.25 0 0 0 2.25 6v12a2.25 2.25 0 0 0 2.25 2.25h15A2.25 2.25 0 0 0 21.75 18V9a2.25 2.25 0 0 0-2.25-2.25h-5.379a1.5 1.5 0 0 1-1.06-.44Z" />
|
||||
</svg>
|
||||
|
||||
<a class=' ms-2 hover:text-blue-600 font-bold' href='<?= e(rtrim($serverURL, '/') . '/' . $folder) ?>'>
|
||||
<?= e($itemName) ?></a>
|
||||
</div>
|
||||
|
||||
</li>
|
||||
<?php endforeach ?>
|
||||
</ul>
|
||||
<ul class="m-4">
|
||||
<?php foreach ($files as $fileName) :
|
||||
$title = ucwords(str_replace(['-', '_'], ' ', $fileName)); ?>
|
||||
<li class="mt-2">
|
||||
<div class="flex items-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-5">
|
||||
<path fill-rule="evenodd" d="M8.22 5.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.75.75 0 0 1-1.06-1.06L11.94 10 8.22 6.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
|
||||
<a class='ms-1 hover:text-blue-600' href='<?= e(rtrim($serverURL, '/') . '/' . $fileName) ?>'><?= e($title) ?></a>
|
||||
</div>
|
||||
</li>
|
||||
<?php endforeach ?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
26
app/views/blocks/heros/hero-1.php
Normal file
26
app/views/blocks/heros/hero-1.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<section class="bg-white dark:bg-slate-900">
|
||||
<div class="mx-auto w-screen max-w-7xl px-4 py-16 sm:px-6 sm:py-24 lg:px-8 lg:py-32">
|
||||
<div class="mx-auto max-w-prose text-center">
|
||||
<h1 class="text-4xl font-bold text-gray-900 dark:text-white/90 sm:text-5xl">
|
||||
Understand user flow and
|
||||
<strong class="text-indigo-600"> increase </strong>
|
||||
conversions
|
||||
</h1>
|
||||
|
||||
<p class="mt-4 text-base text-pretty text-gray-700 dark:text-white/60 sm:text-lg/relaxed">
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eaque, nisi. Natus, provident
|
||||
accusamus impedit minima harum corporis iusto.
|
||||
</p>
|
||||
|
||||
<div class="mt-4 flex justify-center gap-4 sm:mt-6">
|
||||
<a class="btn btn-primary" href="#">
|
||||
Get Started
|
||||
</a>
|
||||
|
||||
<a class="btn btn-secondary" href="#">
|
||||
Learn More
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
33
app/views/blocks/heros/hero-2.php
Normal file
33
app/views/blocks/heros/hero-2.php
Normal file
@@ -0,0 +1,33 @@
|
||||
|
||||
<section class="section">
|
||||
<!-- Container -->
|
||||
<div class="band">
|
||||
<!-- Title -->
|
||||
<h2 class="mb-8 text-3xl font-bold md:text-5xl md:mb-10">
|
||||
Meet Flowspark
|
||||
</h2>
|
||||
<p class="mb-8 max-w-lg text-sm text-gray-500 sm:text-base md:mb-16">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse
|
||||
varius enim in eros elementum tristique. Duis cursus, mi quis viverra
|
||||
ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat.
|
||||
</p>
|
||||
<div class="grid gap-8 lg:grid-cols-2 lg:gap-10">
|
||||
<img src="<?= image() ?>image" alt="" class="inline-block h-full w-full rounded-2xl object-cover" />
|
||||
<div class="flex flex-col gap-5 rounded-2xl border border-solid border-black p-10 sm:p-12">
|
||||
<h2 class="text-3xl font-bold md:text-5xl">Our Mission</h2>
|
||||
<p class="text-sm text-gray-500 sm:text-base">
|
||||
Aliquet risus feugiat in ante metus. Arcu dui vivamus arcu felis
|
||||
bibendum ut. Vestibulum lorem sed risus ultricies tristique nulla.
|
||||
Vitae et leo duis ut diam quam. Bibendum arcu vitae elementum
|
||||
curabitur vitae nunc. Dictumst vestibulum rhoncus est
|
||||
pellentesque. Lectus proin nibh nisl condimentum id. Ullamcorper
|
||||
dignissim cras tincidunt lobortis feugiat vivamus.
|
||||
<br />
|
||||
<br />
|
||||
Massa id neque aliquam vestibulum morbi blandit. Nulla
|
||||
pellentesque dignissim enim sit amet venenatis.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
77
app/views/blocks/heros/index.php
Normal file
77
app/views/blocks/heros/index.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<section class="section">
|
||||
<div class="band">
|
||||
<div class="card">
|
||||
<div class="entry-section">
|
||||
<?php
|
||||
$serverURL = rtrim(parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH), '/') ?: '/';
|
||||
$parentURL = $serverURL === '/' ? '/' : dirname($serverURL);
|
||||
$parentURL = $parentURL === '\\' || $parentURL === '.' ? '/' : $parentURL;
|
||||
$folderSlug = basename($serverURL);
|
||||
$folderName = ucwords(str_replace(['-', '_'], ' ', $folderSlug));
|
||||
$directory = __DIR__;
|
||||
$items = scandir($directory) ?: [];
|
||||
|
||||
$folders = [];
|
||||
$files = [];
|
||||
|
||||
foreach ($items as $item) {
|
||||
if ($item === '.' || $item === '..' || str_starts_with($item, '.')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$path = $directory . DIRECTORY_SEPARATOR . $item;
|
||||
|
||||
if (is_dir($path)) {
|
||||
$folders[] = $item;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_file($path) && basename($item) !== 'index.php' && in_array(pathinfo($item, PATHINFO_EXTENSION), ['php', 'md'], true)) {
|
||||
$files[] = pathinfo($item, PATHINFO_FILENAME);
|
||||
}
|
||||
}
|
||||
|
||||
natcasesort($folders);
|
||||
natcasesort($files);
|
||||
?>
|
||||
<div class="flex justify-between items-center border-b border-slate-200 dark:border-slate-700 pb-5">
|
||||
<div class="text-4xl font-bold"><?= e($folderName) ?></div>
|
||||
<a class="btn btn-primary" href="<?= e($parentURL) ?>">
|
||||
Back
|
||||
</a>
|
||||
</div>
|
||||
<ul class="m-4">
|
||||
<?php
|
||||
foreach ($folders as $folder) :
|
||||
$itemName = ucwords(str_replace(['-', '_'], ' ', $folder)); ?>
|
||||
<li class="mt-2">
|
||||
<div class="flex items-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 12.75V12A2.25 2.25 0 0 1 4.5 9.75h15A2.25 2.25 0 0 1 21.75 12v.75m-8.69-6.44-2.12-2.12a1.5 1.5 0 0 0-1.061-.44H4.5A2.25 2.25 0 0 0 2.25 6v12a2.25 2.25 0 0 0 2.25 2.25h15A2.25 2.25 0 0 0 21.75 18V9a2.25 2.25 0 0 0-2.25-2.25h-5.379a1.5 1.5 0 0 1-1.06-.44Z" />
|
||||
</svg>
|
||||
|
||||
<a class=' ms-2 hover:text-blue-600 font-bold' href='<?= e(rtrim($serverURL, '/') . '/' . $folder) ?>'>
|
||||
<?= e($itemName) ?></a>
|
||||
</div>
|
||||
|
||||
</li>
|
||||
<?php endforeach ?>
|
||||
</ul>
|
||||
<ul class="m-4">
|
||||
<?php foreach ($files as $fileName) :
|
||||
$title = ucwords(str_replace(['-', '_'], ' ', $fileName)); ?>
|
||||
<li class="mt-2">
|
||||
<div class="flex items-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-5">
|
||||
<path fill-rule="evenodd" d="M8.22 5.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.75.75 0 0 1-1.06-1.06L11.94 10 8.22 6.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
|
||||
<a class='ms-1 hover:text-blue-600' href='<?= e(rtrim($serverURL, '/') . '/' . $fileName) ?>'><?= e($title) ?></a>
|
||||
</div>
|
||||
</li>
|
||||
<?php endforeach ?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
77
app/views/blocks/index.php
Normal file
77
app/views/blocks/index.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<section class="section">
|
||||
<div class="band">
|
||||
<div class="card">
|
||||
<div class="entry-section">
|
||||
<?php
|
||||
$serverURL = rtrim(parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH), '/') ?: '/';
|
||||
$parentURL = $serverURL === '/' ? '/' : dirname($serverURL);
|
||||
$parentURL = $parentURL === '\\' || $parentURL === '.' ? '/' : $parentURL;
|
||||
$folderSlug = basename($serverURL);
|
||||
$folderName = ucwords(str_replace(['-', '_'], ' ', $folderSlug));
|
||||
$directory = __DIR__;
|
||||
$items = scandir($directory) ?: [];
|
||||
|
||||
$folders = [];
|
||||
$files = [];
|
||||
|
||||
foreach ($items as $item) {
|
||||
if ($item === '.' || $item === '..' || str_starts_with($item, '.')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$path = $directory . DIRECTORY_SEPARATOR . $item;
|
||||
|
||||
if (is_dir($path)) {
|
||||
$folders[] = $item;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_file($path) && basename($item) !== 'index.php' && in_array(pathinfo($item, PATHINFO_EXTENSION), ['php', 'md'], true)) {
|
||||
$files[] = pathinfo($item, PATHINFO_FILENAME);
|
||||
}
|
||||
}
|
||||
|
||||
natcasesort($folders);
|
||||
natcasesort($files);
|
||||
?>
|
||||
<div class="flex justify-between items-center border-b border-slate-200 dark:border-slate-700 pb-5">
|
||||
<div class="text-4xl font-bold"><?= e($folderName) ?></div>
|
||||
<a class="btn btn-primary" href="<?= e($parentURL) ?>">
|
||||
Back
|
||||
</a>
|
||||
</div>
|
||||
<ul class="m-4">
|
||||
<?php
|
||||
foreach ($folders as $folder) :
|
||||
$itemName = ucwords(str_replace(['-', '_'], ' ', $folder)); ?>
|
||||
<li class="mt-2">
|
||||
<div class="flex items-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 12.75V12A2.25 2.25 0 0 1 4.5 9.75h15A2.25 2.25 0 0 1 21.75 12v.75m-8.69-6.44-2.12-2.12a1.5 1.5 0 0 0-1.061-.44H4.5A2.25 2.25 0 0 0 2.25 6v12a2.25 2.25 0 0 0 2.25 2.25h15A2.25 2.25 0 0 0 21.75 18V9a2.25 2.25 0 0 0-2.25-2.25h-5.379a1.5 1.5 0 0 1-1.06-.44Z" />
|
||||
</svg>
|
||||
|
||||
<a class=' ms-2 hover:text-blue-600 font-bold' href='<?= e(rtrim($serverURL, '/') . '/' . $folder) ?>'>
|
||||
<?= e($itemName) ?></a>
|
||||
</div>
|
||||
|
||||
</li>
|
||||
<?php endforeach ?>
|
||||
</ul>
|
||||
<ul class="m-4">
|
||||
<?php foreach ($files as $fileName) :
|
||||
$title = ucwords(str_replace(['-', '_'], ' ', $fileName)); ?>
|
||||
<li class="mt-2">
|
||||
<div class="flex items-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-5">
|
||||
<path fill-rule="evenodd" d="M8.22 5.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.75.75 0 0 1-1.06-1.06L11.94 10 8.22 6.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
|
||||
<a class='ms-1 hover:text-blue-600' href='<?= e(rtrim($serverURL, '/') . '/' . $fileName) ?>'><?= e($title) ?></a>
|
||||
</div>
|
||||
</li>
|
||||
<?php endforeach ?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
77
app/views/blocks/sections/index.php
Normal file
77
app/views/blocks/sections/index.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<section class="section">
|
||||
<div class="band">
|
||||
<div class="card">
|
||||
<div class="entry-section">
|
||||
<?php
|
||||
$serverURL = rtrim(parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH), '/') ?: '/';
|
||||
$parentURL = $serverURL === '/' ? '/' : dirname($serverURL);
|
||||
$parentURL = $parentURL === '\\' || $parentURL === '.' ? '/' : $parentURL;
|
||||
$folderSlug = basename($serverURL);
|
||||
$folderName = ucwords(str_replace(['-', '_'], ' ', $folderSlug));
|
||||
$directory = __DIR__;
|
||||
$items = scandir($directory) ?: [];
|
||||
|
||||
$folders = [];
|
||||
$files = [];
|
||||
|
||||
foreach ($items as $item) {
|
||||
if ($item === '.' || $item === '..' || str_starts_with($item, '.')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$path = $directory . DIRECTORY_SEPARATOR . $item;
|
||||
|
||||
if (is_dir($path)) {
|
||||
$folders[] = $item;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_file($path) && basename($item) !== 'index.php' && in_array(pathinfo($item, PATHINFO_EXTENSION), ['php', 'md'], true)) {
|
||||
$files[] = pathinfo($item, PATHINFO_FILENAME);
|
||||
}
|
||||
}
|
||||
|
||||
natcasesort($folders);
|
||||
natcasesort($files);
|
||||
?>
|
||||
<div class="flex justify-between items-center border-b border-slate-200 dark:border-slate-700 pb-5">
|
||||
<div class="text-4xl font-bold"><?= e($folderName) ?></div>
|
||||
<a class="btn btn-primary" href="<?= e($parentURL) ?>">
|
||||
Back
|
||||
</a>
|
||||
</div>
|
||||
<ul class="m-4">
|
||||
<?php
|
||||
foreach ($folders as $folder) :
|
||||
$itemName = ucwords(str_replace(['-', '_'], ' ', $folder)); ?>
|
||||
<li class="mt-2">
|
||||
<div class="flex items-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 12.75V12A2.25 2.25 0 0 1 4.5 9.75h15A2.25 2.25 0 0 1 21.75 12v.75m-8.69-6.44-2.12-2.12a1.5 1.5 0 0 0-1.061-.44H4.5A2.25 2.25 0 0 0 2.25 6v12a2.25 2.25 0 0 0 2.25 2.25h15A2.25 2.25 0 0 0 21.75 18V9a2.25 2.25 0 0 0-2.25-2.25h-5.379a1.5 1.5 0 0 1-1.06-.44Z" />
|
||||
</svg>
|
||||
|
||||
<a class=' ms-2 hover:text-blue-600 font-bold' href='<?= e(rtrim($serverURL, '/') . '/' . $folder) ?>'>
|
||||
<?= e($itemName) ?></a>
|
||||
</div>
|
||||
|
||||
</li>
|
||||
<?php endforeach ?>
|
||||
</ul>
|
||||
<ul class="m-4">
|
||||
<?php foreach ($files as $fileName) :
|
||||
$title = ucwords(str_replace(['-', '_'], ' ', $fileName)); ?>
|
||||
<li class="mt-2">
|
||||
<div class="flex items-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-5">
|
||||
<path fill-rule="evenodd" d="M8.22 5.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.75.75 0 0 1-1.06-1.06L11.94 10 8.22 6.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
|
||||
<a class='ms-1 hover:text-blue-600' href='<?= e(rtrim($serverURL, '/') . '/' . $fileName) ?>'><?= e($title) ?></a>
|
||||
</div>
|
||||
</li>
|
||||
<?php endforeach ?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
20
app/views/blocks/sections/section-1.php
Normal file
20
app/views/blocks/sections/section-1.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<section class="section">
|
||||
<div class="band">
|
||||
<div class="space-y-4 md:space-y-8">
|
||||
<div class="max-w-prose">
|
||||
<h2 class="text-2xl font-semibold text-gray-900 dark:text-white/90 sm:text-3xl">
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit.
|
||||
</h2>
|
||||
|
||||
|
||||
<p class="mt-4 text-gray-700 dark:text-white/60">
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Tenetur doloremque saepe
|
||||
architecto maiores repudiandae amet perferendis repellendus, reprehenderit voluptas
|
||||
sequi.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<img src="<?= image(1140, 600) ?>" class="rounded shadow-2xl" alt="">
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
88
app/views/demo/blog-list.php
Normal file
88
app/views/demo/blog-list.php
Normal file
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
$data['title'] = 'Blog List Demo - Framex';
|
||||
$data['metaDescription'] = 'A modern blog listing page demo built as a PHP view in Framex.';
|
||||
|
||||
$posts = [
|
||||
[
|
||||
'title' => 'Designing fast content systems with plain PHP',
|
||||
'category' => 'Architecture',
|
||||
'date' => 'May 12, 2026',
|
||||
'read' => '7 min read',
|
||||
'description' => 'A practical look at keeping site structure simple while still giving editors polished pages.',
|
||||
'color' => 'bg-pre-blue',
|
||||
],
|
||||
[
|
||||
'title' => 'Markdown pages that look finished by default',
|
||||
'category' => 'Content',
|
||||
'date' => 'May 8, 2026',
|
||||
'read' => '5 min read',
|
||||
'description' => 'How automatic prose styling lets documentation and articles ship without custom templates.',
|
||||
'color' => 'bg-pre-emerald',
|
||||
],
|
||||
[
|
||||
'title' => 'A small Tailwind design system for real websites',
|
||||
'category' => 'Design',
|
||||
'date' => 'May 4, 2026',
|
||||
'read' => '6 min read',
|
||||
'description' => 'Reusable sections, cards, buttons, and preset colors keep page building consistent.',
|
||||
'color' => 'bg-pre-amber',
|
||||
],
|
||||
[
|
||||
'title' => 'Dark mode without making every page complicated',
|
||||
'category' => 'Frontend',
|
||||
'date' => 'April 28, 2026',
|
||||
'read' => '4 min read',
|
||||
'description' => 'Persisted preferences, system fallback, and theme-aware utility classes in one flow.',
|
||||
'color' => 'bg-pre-rose',
|
||||
],
|
||||
];
|
||||
?>
|
||||
|
||||
<main>
|
||||
<section class="section">
|
||||
<div class="contain">
|
||||
<div class="grid gap-10 lg:grid-cols-[0.85fr_1.15fr] lg:items-end">
|
||||
<div>
|
||||
<p class="eyebrow">Blog list demo</p>
|
||||
<h1 class="mt-4 text-4xl font-semibold leading-tight text-slate-950 sm:text-6xl dark:text-white">
|
||||
Editorial cards for a modern content index.
|
||||
</h1>
|
||||
</div>
|
||||
<p class="text-lg leading-8 text-slate-600 dark:text-slate-400">
|
||||
This page is a PHP view. It uses an array of posts, loops through the data, and renders a responsive grid without needing a separate component system.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="mt-10 flex flex-wrap gap-3">
|
||||
<span class="btn btn-secondary">All posts</span>
|
||||
<span class="btn btn-ghost">Architecture</span>
|
||||
<span class="btn btn-ghost">Content</span>
|
||||
<span class="btn btn-ghost">Design</span>
|
||||
</div>
|
||||
|
||||
<div class="mt-10 grid gap-5 md:grid-cols-2">
|
||||
<?php foreach ($posts as $index => $post): ?>
|
||||
<article class="card overflow-hidden p-0 <?= $index === 0 ? 'md:col-span-2' : '' ?>">
|
||||
<div class="<?= e($post['color']) ?> p-6">
|
||||
<div class="flex flex-wrap items-center gap-3 text-sm">
|
||||
<span class="font-semibold"><?= e($post['category']) ?></span>
|
||||
<span class="opacity-60">/</span>
|
||||
<span class="opacity-80"><?= e($post['date']) ?></span>
|
||||
</div>
|
||||
<h2 class="mt-8 max-w-3xl text-2xl font-semibold leading-tight <?= $index === 0 ? 'sm:text-4xl' : '' ?>">
|
||||
<?= e($post['title']) ?>
|
||||
</h2>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<p class="text-sm leading-6 text-slate-600 dark:text-slate-400"><?= e($post['description']) ?></p>
|
||||
<div class="mt-6 flex items-center justify-between gap-4">
|
||||
<span class="text-sm text-slate-500 dark:text-slate-400"><?= e($post['read']) ?></span>
|
||||
<a class="btn btn-secondary" href="/demo/blog-post">Read post</a>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
98
app/views/demo/blog-post.php
Normal file
98
app/views/demo/blog-post.php
Normal file
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
$data['title'] = 'Blog Post Demo - Framex';
|
||||
$data['metaDescription'] = 'A modern blog post page demo built as a PHP view in Framex.';
|
||||
?>
|
||||
|
||||
<main>
|
||||
<article>
|
||||
<header class="section">
|
||||
<div class="contain">
|
||||
<div class="mx-auto max-w-4xl text-center">
|
||||
<p class="eyebrow">Architecture / 7 min read</p>
|
||||
<h1 class="mt-5 text-4xl font-bold tracking-tight text-slate-950 sm:text-6xl dark:text-white">
|
||||
Designing fast content systems with plain PHP.
|
||||
</h1>
|
||||
<p class="mt-6 text-lg leading-8 text-slate-600 dark:text-slate-400">
|
||||
A modern site does not need a heavy runtime to feel polished. Framex keeps page resolution, templates, assets, and Markdown close to the filesystem.
|
||||
</p>
|
||||
<div class="mt-8 flex items-center justify-center gap-4 text-sm text-slate-500 dark:text-slate-400">
|
||||
<span class="grid size-11 place-items-center rounded-full bg-blue-600 font-semibold text-white">Fx</span>
|
||||
<div class="text-left">
|
||||
<p class="font-semibold text-slate-900 dark:text-white">Framex Team</p>
|
||||
<p>Published May 12, 2026</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section class="contain">
|
||||
<div class="bg-pre-blue rounded-lg p-8 md:p-12">
|
||||
<div class="grid gap-6 md:grid-cols-3">
|
||||
<div>
|
||||
<p class="text-sm font-semibold uppercase tracking-widest opacity-70">Routing</p>
|
||||
<p class="mt-3 text-2xl font-semibold">Files become URLs</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm font-semibold uppercase tracking-widest opacity-70">Views</p>
|
||||
<p class="mt-3 text-2xl font-semibold">PHP and Markdown</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm font-semibold uppercase tracking-widest opacity-70">Design</p>
|
||||
<p class="mt-3 text-2xl font-semibold">Tailwind CSS 4</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<div class="contain grid gap-10 lg:grid-cols-[0.75fr_1.25fr]">
|
||||
<aside class="lg:sticky lg:top-24 lg:self-start">
|
||||
<div class="card">
|
||||
<p class="text-sm font-semibold text-slate-950 dark:text-white">In this article</p>
|
||||
<div class="mt-4 grid gap-3 text-sm text-slate-600 dark:text-slate-400">
|
||||
<a href="#simple-routing" class="hover:text-blue-600 dark:hover:text-blue-400">Simple routing</a>
|
||||
<a href="#shared-layouts" class="hover:text-blue-600 dark:hover:text-blue-400">Shared layouts</a>
|
||||
<a href="#content-speed" class="hover:text-blue-600 dark:hover:text-blue-400">Content speed</a>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<div class="prose">
|
||||
<h2 id="simple-routing">Simple routing</h2>
|
||||
<p>Framex resolves URLs by checking for matching PHP and Markdown files inside <code>app/views</code>. This keeps page creation predictable for new developers and small teams.</p>
|
||||
|
||||
<p>A route such as <code>/demo/blog-post</code> can be backed by <code>app/views/demo/blog-post.php</code>, while documentation can be written as Markdown in <code>app/views/docs/index.md</code>.</p>
|
||||
|
||||
<h2 id="shared-layouts">Shared layouts</h2>
|
||||
<p>Every page is wrapped by the main template, which includes the top menu, current view content, footer, compiled CSS, and JavaScript. PHP views can set metadata through the <code>$data</code> array.</p>
|
||||
|
||||
<blockquote>
|
||||
<p>Keep page-specific content in views, shared structure in templates, and reusable visual rules in Tailwind source CSS.</p>
|
||||
</blockquote>
|
||||
|
||||
<h2 id="content-speed">Content speed</h2>
|
||||
<p>Markdown pages are useful for documentation and simple publishing workflows. PHP views are better when a page needs custom data, cards, grids, forms, or conditional rendering.</p>
|
||||
|
||||
<pre><code>// PHP view route
|
||||
app/views/demo/blog-post.php
|
||||
|
||||
// Markdown view route
|
||||
app/views/demo/page.md</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</article>
|
||||
|
||||
<section class="section-tight border-t border-slate-200 bg-white dark:border-slate-800 dark:bg-slate-900/40">
|
||||
<div class="contain">
|
||||
<div class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div>
|
||||
<p class="eyebrow">Next demo</p>
|
||||
<h2 class="mt-2 text-2xl font-semibold text-slate-950 dark:text-white">Explore the Markdown page.</h2>
|
||||
</div>
|
||||
<a class="btn btn-primary" href="/demo/page">Open Markdown demo</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
86
app/views/demo/index.php
Normal file
86
app/views/demo/index.php
Normal file
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
$data['title'] = 'Framex Demo Pages';
|
||||
$data['metaDescription'] = 'Explore modern demo pages built with Framex PHP views, Markdown views, Tailwind CSS, and reusable UI classes.';
|
||||
$data['bodyClass'] = 'bg-slate-50 text-slate-950 dark:bg-slate-950 dark:text-slate-100';
|
||||
|
||||
$demoPages = [
|
||||
[
|
||||
'title' => 'Blog List',
|
||||
'description' => 'A polished editorial index with featured content, filters, and responsive cards.',
|
||||
'href' => '/demo/blog-list',
|
||||
'label' => 'PHP view',
|
||||
'color' => 'bg-pre-blue',
|
||||
],
|
||||
[
|
||||
'title' => 'Blog Post',
|
||||
'description' => 'A long-form article layout with author metadata, hero content, and related cards.',
|
||||
'href' => '/demo/blog-post',
|
||||
'label' => 'PHP view',
|
||||
'color' => 'bg-pre-emerald',
|
||||
],
|
||||
[
|
||||
'title' => 'Markdown Page',
|
||||
'description' => 'A content page rendered from Markdown and automatically styled by `.prose`.',
|
||||
'href' => '/demo/page',
|
||||
'label' => 'MD view',
|
||||
'color' => 'bg-pre-amber',
|
||||
],
|
||||
];
|
||||
?>
|
||||
|
||||
<main>
|
||||
<section class="section">
|
||||
<div class="contain">
|
||||
<div class="max-w-3xl">
|
||||
<p class="eyebrow">Demo library</p>
|
||||
<h1 class="mt-4 text-4xl font-bold text-gradient sm:text-6xl dark:text-white">
|
||||
Modern pages built with the Framex view system.
|
||||
</h1>
|
||||
<p class="mt-6 text-lg leading-8 text-slate-600 dark:text-slate-400">
|
||||
These demos show how PHP views and Markdown views can share the same template, navigation, footer, light/dark mode, and reusable Tailwind classes.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="mt-12 grid gap-5 md:grid-cols-3">
|
||||
<?php foreach ($demoPages as $page): ?>
|
||||
<a class="card group flex min-h-72 flex-col justify-between overflow-hidden p-0" href="<?= e($page['href']) ?>">
|
||||
<div class="<?= e($page['color']) ?> p-6">
|
||||
<span class="inline-flex rounded-md bg-white/70 px-3 py-1 text-xs font-semibold text-slate-700 ring-1 ring-black/5 dark:bg-black/20 dark:text-white dark:ring-white/10">
|
||||
<?= e($page['label']) ?>
|
||||
</span>
|
||||
<h2 class="mt-8 text-2xl font-bold text-current"><?= e($page['title']) ?></h2>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<p class="text-sm leading-6 text-slate-600 dark:text-slate-400"><?= e($page['description']) ?></p>
|
||||
<div class="mt-6 inline-flex items-center gap-2 text-sm font-semibold text-blue-600 group-hover:text-blue-500 dark:text-blue-400">
|
||||
Open demo
|
||||
<span aria-hidden="true">-></span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section-tight border-y border-slate-200 bg-white dark:border-slate-800 dark:bg-slate-900/40">
|
||||
<div class="contain grid gap-5 md:grid-cols-4">
|
||||
<div class="card">
|
||||
<p class="text-3xl font-semibold text-slate-950 dark:text-white">4</p>
|
||||
<p class="mt-2 text-sm text-slate-600 dark:text-slate-400">Demo routes</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="text-3xl font-semibold text-slate-950 dark:text-white">2</p>
|
||||
<p class="mt-2 text-sm text-slate-600 dark:text-slate-400">View types</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="text-3xl font-semibold text-slate-950 dark:text-white">4</p>
|
||||
<p class="mt-2 text-sm text-slate-600 dark:text-slate-400">Preset colors</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="text-3xl font-semibold text-slate-950 dark:text-white">1</p>
|
||||
<p class="mt-2 text-sm text-slate-600 dark:text-slate-400">Shared layout</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
54
app/views/demo/page.md
Normal file
54
app/views/demo/page.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# Markdown Page Demo
|
||||
|
||||
This page is rendered from `app/views/demo/page.md`. It uses the same main template, top menu, footer, CSS, JavaScript, and light/dark mode as PHP views.
|
||||
|
||||
Markdown pages are ideal for documentation, policies, articles, guides, landing copy drafts, and simple content pages.
|
||||
|
||||
## What gets styled automatically
|
||||
|
||||
Framex wraps Markdown output in `.prose prose-shell`, so common content elements are styled without extra markup:
|
||||
|
||||
- Headings
|
||||
- Paragraphs
|
||||
- Links
|
||||
- Ordered and unordered lists
|
||||
- Inline code
|
||||
- Code blocks
|
||||
- Blockquotes
|
||||
- Tables
|
||||
- Images
|
||||
- Horizontal rules
|
||||
|
||||
## Example content
|
||||
|
||||
You can write ordinary Markdown:
|
||||
|
||||
```md
|
||||
## Feature section
|
||||
|
||||
- Fast routes
|
||||
- PHP views
|
||||
- Markdown views
|
||||
- Tailwind styling
|
||||
```
|
||||
|
||||
And it becomes a fully styled content page.
|
||||
|
||||
## Table example
|
||||
|
||||
| View type | Best for | Route example |
|
||||
| --- | --- | --- |
|
||||
| PHP | Dynamic layouts, cards, forms | `/demo/blog-list` |
|
||||
| Markdown | Docs, articles, simple pages | `/demo/page` |
|
||||
|
||||
## Blockquote example
|
||||
|
||||
> Markdown is the fastest way to add polished content when the page does not need custom PHP logic.
|
||||
|
||||
## Next steps
|
||||
|
||||
Open the other demo pages:
|
||||
|
||||
- [Demo index](/demo)
|
||||
- [Blog list](/demo/blog-list)
|
||||
- [Blog post](/demo/blog-post)
|
||||
415
app/views/docs/index.md
Normal file
415
app/views/docs/index.md
Normal file
@@ -0,0 +1,415 @@
|
||||
# Framex Engine Documentation
|
||||
|
||||
Framex is a small PHP engine for building fast websites with plain PHP views, Markdown pages, reusable templates, and Tailwind CSS 4. It is designed to stay simple: URLs map to files, templates wrap views, and assets live in `public`.
|
||||
|
||||
## Project Structure
|
||||
|
||||
The important folders are:
|
||||
|
||||
```text
|
||||
app/views/ Page views for URLs
|
||||
core/ Router, renderer, helpers, and configuration
|
||||
templates/ Layout templates and partials
|
||||
templates/partials/ Shared pieces such as top menu and footer
|
||||
public/ Web root for CSS, JS, images, and index.php
|
||||
public/css/src/ Tailwind source CSS
|
||||
public/css/style.css Compiled production CSS
|
||||
public/js/init.js Theme toggle and menu behavior
|
||||
```
|
||||
|
||||
The web server should point to `public` as the document root.
|
||||
|
||||
## URL Routing
|
||||
|
||||
Framex resolves the browser URL to a file inside `app/views`.
|
||||
|
||||
For a request like:
|
||||
|
||||
```text
|
||||
/about
|
||||
```
|
||||
|
||||
Framex checks these files in order:
|
||||
|
||||
```text
|
||||
app/views/about.php
|
||||
app/views/about/index.php
|
||||
app/views/about.md
|
||||
app/views/about/index.md
|
||||
```
|
||||
|
||||
The first file that exists is rendered. If none exists, Framex falls back to `templates/error404.php`.
|
||||
|
||||
Examples:
|
||||
|
||||
```text
|
||||
/ -> app/views/index.php
|
||||
/docs -> app/views/docs/index.md
|
||||
/about -> app/views/about/index.md
|
||||
/pricing -> app/views/pricing.php
|
||||
/blog/hello -> app/views/blog/hello.php or app/views/blog/hello/index.md
|
||||
```
|
||||
|
||||
Trailing slashes are normalized, so `/docs/` and `/docs` resolve the same way.
|
||||
|
||||
## PHP Views
|
||||
|
||||
Use PHP views when a page needs custom markup, variables, conditionals, loops, forms, or reusable PHP logic.
|
||||
|
||||
Create a file:
|
||||
|
||||
```text
|
||||
app/views/pricing.php
|
||||
```
|
||||
|
||||
Then visit:
|
||||
|
||||
```text
|
||||
/pricing
|
||||
```
|
||||
|
||||
A PHP view can set page metadata by assigning values to the `$data` array:
|
||||
|
||||
```php
|
||||
<?php
|
||||
$data['title'] = 'Pricing - Framex';
|
||||
$data['metaDescription'] = 'Simple pricing page built with Framex.';
|
||||
$data['bodyClass'] = 'bg-slate-50 text-slate-950 dark:bg-slate-950 dark:text-slate-100';
|
||||
?>
|
||||
|
||||
<main class="section">
|
||||
<div class="contain">
|
||||
<h1 class="text-4xl font-semibold">Pricing</h1>
|
||||
<p class="mt-4 text-slate-600 dark:text-slate-400">Choose the right plan.</p>
|
||||
</div>
|
||||
</main>
|
||||
```
|
||||
|
||||
The rendered PHP view is injected into the main template through `<?= $view ?>`.
|
||||
|
||||
## Markdown Views
|
||||
|
||||
Use Markdown views for documentation, simple content pages, articles, and static text-heavy pages.
|
||||
|
||||
Create a file:
|
||||
|
||||
```text
|
||||
app/views/guide/index.md
|
||||
```
|
||||
|
||||
Then visit:
|
||||
|
||||
```text
|
||||
/guide
|
||||
```
|
||||
|
||||
Markdown files are parsed by `Parsedown` and automatically wrapped in:
|
||||
|
||||
```html
|
||||
<article class="prose prose-shell">
|
||||
...
|
||||
</article>
|
||||
```
|
||||
|
||||
That means Markdown pages automatically get readable typography, spacing, links, lists, code blocks, tables, blockquotes, images, and light/dark colors.
|
||||
|
||||
Example Markdown page:
|
||||
|
||||
```md
|
||||
# My Guide
|
||||
|
||||
This page is rendered from Markdown.
|
||||
|
||||
## Features
|
||||
|
||||
- Clean URLs
|
||||
- Automatic styling
|
||||
- Light and dark mode
|
||||
|
||||
```php
|
||||
echo 'Code blocks are styled too';
|
||||
```
|
||||
```
|
||||
|
||||
## Templates
|
||||
|
||||
The default layout is:
|
||||
|
||||
```text
|
||||
templates/main.php
|
||||
```
|
||||
|
||||
It handles:
|
||||
|
||||
- HTML document structure
|
||||
- Meta tags
|
||||
- CSS include
|
||||
- Dark-mode bootstrap
|
||||
- Top menu partial
|
||||
- Current view output
|
||||
- Footer partial
|
||||
- JavaScript include
|
||||
|
||||
The main content flow is:
|
||||
|
||||
```php
|
||||
<?= partial('topmenu') ?>
|
||||
<?= $view ?>
|
||||
<?= partial('footer') ?>
|
||||
```
|
||||
|
||||
Partials live in:
|
||||
|
||||
```text
|
||||
templates/partials/
|
||||
```
|
||||
|
||||
For example:
|
||||
|
||||
```text
|
||||
templates/partials/topmenu.php
|
||||
templates/partials/footer.php
|
||||
```
|
||||
|
||||
Load a partial with:
|
||||
|
||||
```php
|
||||
<?= partial('topmenu') ?>
|
||||
```
|
||||
|
||||
## Metadata
|
||||
|
||||
PHP views can customize metadata with `$data`.
|
||||
|
||||
Common keys:
|
||||
|
||||
```php
|
||||
$data['title'] = 'Page title';
|
||||
$data['metaDescription'] = 'Page description for search and sharing.';
|
||||
$data['metaImage'] = image(1200, 630);
|
||||
$data['bodyClass'] = 'custom body classes';
|
||||
$data['template'] = 'main';
|
||||
```
|
||||
|
||||
If a key is not set, `templates/main.php` uses sensible defaults.
|
||||
|
||||
Markdown views currently use the default metadata unless the renderer is extended to read front matter.
|
||||
|
||||
## Assets
|
||||
|
||||
Public files are served from `public`.
|
||||
|
||||
Examples:
|
||||
|
||||
```text
|
||||
public/css/style.css -> /css/style.css
|
||||
public/js/init.js -> /js/init.js
|
||||
public/images/logo.png -> /images/logo.png
|
||||
```
|
||||
|
||||
Use the `asset()` helper for cache-busted URLs:
|
||||
|
||||
```php
|
||||
<link rel="stylesheet" href="<?= asset('css/style.css') ?>">
|
||||
<script src="<?= asset('js/init.js', ['prefix' => 'framex', 'hash' => true]) ?>"></script>
|
||||
```
|
||||
|
||||
Useful asset options:
|
||||
|
||||
```php
|
||||
asset('css/style.css');
|
||||
asset('js/init.js', ['hash' => true]);
|
||||
asset('images/logo.png', ['absolute' => true]);
|
||||
asset('images/missing.png', ['fallback' => '/images/default.png']);
|
||||
```
|
||||
|
||||
## Tailwind CSS
|
||||
|
||||
Framex uses Tailwind CSS 4 through the Tailwind CLI.
|
||||
|
||||
Install dependencies:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
Build CSS:
|
||||
|
||||
```bash
|
||||
npm run build:css
|
||||
```
|
||||
|
||||
Watch CSS during development:
|
||||
|
||||
```bash
|
||||
npm run watch:css
|
||||
```
|
||||
|
||||
Source CSS:
|
||||
|
||||
```text
|
||||
public/css/src/style.css
|
||||
```
|
||||
|
||||
Compiled CSS:
|
||||
|
||||
```text
|
||||
public/css/style.css
|
||||
```
|
||||
|
||||
Tailwind scans these sources:
|
||||
|
||||
```css
|
||||
@source "../../../templates/**/*.php";
|
||||
@source "../../../app/**/*.php";
|
||||
@source "../../../app/**/*.md";
|
||||
```
|
||||
|
||||
When you add new Tailwind classes in PHP or Markdown files, rebuild the CSS.
|
||||
|
||||
## Reusable CSS Classes
|
||||
|
||||
The project includes reusable classes in `public/css/src/style.css`.
|
||||
|
||||
Layout:
|
||||
|
||||
```html
|
||||
<section class="section">
|
||||
<div class="contain">...</div>
|
||||
</section>
|
||||
```
|
||||
|
||||
Buttons:
|
||||
|
||||
```html
|
||||
<a class="btn btn-primary" href="/docs">Primary</a>
|
||||
<a class="btn btn-secondary" href="/about">Secondary</a>
|
||||
<button class="btn btn-ghost">Ghost</button>
|
||||
```
|
||||
|
||||
Cards:
|
||||
|
||||
```html
|
||||
<article class="card">
|
||||
<h2>Card title</h2>
|
||||
<p>Card content.</p>
|
||||
</article>
|
||||
```
|
||||
|
||||
Preset backgrounds:
|
||||
|
||||
```html
|
||||
<div class="bg-pre-blue">Blue preset</div>
|
||||
<div class="bg-pre-emerald">Emerald preset</div>
|
||||
<div class="bg-pre-amber">Amber preset</div>
|
||||
<div class="bg-pre-rose">Rose preset</div>
|
||||
```
|
||||
|
||||
These presets include both light and dark colors.
|
||||
|
||||
## Light and Dark Mode
|
||||
|
||||
Dark mode is controlled by the `dark` class on the `<html>` element.
|
||||
|
||||
The inline script in `templates/main.php` runs before the stylesheet loads. It checks:
|
||||
|
||||
1. The saved `framex-theme` value in `localStorage`.
|
||||
2. The browser system preference.
|
||||
3. Light mode as the fallback.
|
||||
|
||||
The toggle buttons in `templates/partials/topmenu.php` use:
|
||||
|
||||
```html
|
||||
data-theme-toggle
|
||||
```
|
||||
|
||||
The behavior is implemented in:
|
||||
|
||||
```text
|
||||
public/js/init.js
|
||||
```
|
||||
|
||||
Use Tailwind dark variants anywhere:
|
||||
|
||||
```html
|
||||
<div class="bg-white text-slate-950 dark:bg-slate-900 dark:text-white">
|
||||
Theme-aware content
|
||||
</div>
|
||||
```
|
||||
|
||||
## Running Locally
|
||||
|
||||
Install dependencies and build CSS:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run build:css
|
||||
```
|
||||
|
||||
Start PHP's built-in server:
|
||||
|
||||
```bash
|
||||
php -S localhost:8000 -t public
|
||||
```
|
||||
|
||||
Open:
|
||||
|
||||
```text
|
||||
http://localhost:8000/
|
||||
```
|
||||
|
||||
Useful URLs:
|
||||
|
||||
```text
|
||||
/ Landing page
|
||||
/docs This documentation
|
||||
/about Example Markdown page
|
||||
```
|
||||
|
||||
## Adding a New Page
|
||||
|
||||
For a PHP page:
|
||||
|
||||
```text
|
||||
app/views/services.php
|
||||
```
|
||||
|
||||
Visit:
|
||||
|
||||
```text
|
||||
/services
|
||||
```
|
||||
|
||||
For a Markdown page:
|
||||
|
||||
```text
|
||||
app/views/services/index.md
|
||||
```
|
||||
|
||||
Visit:
|
||||
|
||||
```text
|
||||
/services
|
||||
```
|
||||
|
||||
For a nested page:
|
||||
|
||||
```text
|
||||
app/views/blog/hello-world/index.md
|
||||
```
|
||||
|
||||
Visit:
|
||||
|
||||
```text
|
||||
/blog/hello-world
|
||||
```
|
||||
|
||||
## Recommended Workflow
|
||||
|
||||
1. Add or edit a PHP or Markdown view in `app/views`.
|
||||
2. Use `templates/partials` for shared UI.
|
||||
3. Use `.section`, `.contain`, `.btn`, `.card`, and preset backgrounds for consistent design.
|
||||
4. Run `npm run build:css` after changing Tailwind classes.
|
||||
5. Test the URL in the browser.
|
||||
|
||||
Framex works best when pages stay close to the filesystem, shared layout stays in templates, and reusable styling stays in the Tailwind source CSS.
|
||||
178
app/views/index.php
Normal file
178
app/views/index.php
Normal file
@@ -0,0 +1,178 @@
|
||||
<?php
|
||||
$data['title'] = "Framex Engine — Build Static Sites at Lightspeed";
|
||||
$data['metaDescription'] = "Framex is a lightweight PHP engine for building blazing-fast static sites. No database, no bloat, just pure performance.";
|
||||
$data['bodyClass'] = "bg-slate-50 text-slate-950 dark:bg-slate-950 dark:text-slate-100";
|
||||
?>
|
||||
|
||||
<main>
|
||||
<section class="section relative overflow-hidden">
|
||||
<div class="contain grid items-center gap-12 lg:grid-cols-[1.05fr_0.95fr]">
|
||||
<div>
|
||||
<p class="eyebrow">PHP engine plus Tailwind CSS 4</p>
|
||||
<h1 class="mt-5 max-w-4xl text-5xl font-bold text-gradient tracking-tight sm:text-6xl lg:text-7xl dark:text-white/80">
|
||||
Build static sites that feel fast before you even optimize them.
|
||||
</h1>
|
||||
<p class="mt-6 max-w-2xl text-lg leading-8 text-slate-600 dark:text-slate-400">
|
||||
FramexEngine keeps routing, markdown, templates, and assets simple so you can ship lightweight PHP sites with a modern design system already in place.
|
||||
</p>
|
||||
<div id="start" class="mt-8 flex flex-col gap-3 sm:flex-row">
|
||||
<a class="btn btn-primary" href="/docs">Read the docs</a>
|
||||
<a class="btn btn-secondary" href="#features">Explore features</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card p-0">
|
||||
<div class="border-b border-slate-200 px-4 py-3 dark:border-slate-800">
|
||||
<div class="flex gap-2">
|
||||
<span class="size-3 rounded-full bg-rose-400"></span>
|
||||
<span class="size-3 rounded-full bg-amber-400"></span>
|
||||
<span class="size-3 rounded-full bg-emerald-400"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-5 p-6">
|
||||
<div class="rounded-lg bg-slate-950 p-5 font-mono text-sm leading-7 text-slate-200 dark:bg-black">
|
||||
<p><span class="text-emerald-300"><?php</span></p>
|
||||
<p><span class="text-blue-300">$data['title']</span> = <span class="text-amber-200">'Framex'</span>;</p>
|
||||
<p><span class="text-slate-500">// templates, markdown, Tailwind</span></p>
|
||||
<p><span class="text-rose-300">?></span></p>
|
||||
</div>
|
||||
<div class="grid gap-3 sm:grid-cols-2">
|
||||
<div class="bg-pre-blue rounded-lg p-4">
|
||||
<p class="text-sm font-semibold">CSS-first</p>
|
||||
<p class="mt-1 text-sm opacity-80">Tailwind v4 build flow.</p>
|
||||
</div>
|
||||
<div class="bg-pre-emerald rounded-lg p-4">
|
||||
<p class="text-sm font-semibold">Markdown</p>
|
||||
<p class="mt-1 text-sm opacity-80">Auto styled pages.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="features" class="section border-y border-slate-200 bg-white dark:border-slate-800 dark:bg-slate-900/40">
|
||||
<div class="contain">
|
||||
<div class="max-w-2xl">
|
||||
<p class="eyebrow">Features</p>
|
||||
<h2 class="mt-4 text-3xl font-semibold text-slate-950 sm:text-4xl dark:text-white">A compact foundation for real projects.</h2>
|
||||
</div>
|
||||
<div class="mt-10 grid gap-5 md:grid-cols-3">
|
||||
<article class="card">
|
||||
<h3 class="text-lg font-semibold text-slate-950 dark:text-white">Simple routing</h3>
|
||||
<p class="mt-3 text-sm leading-6 text-slate-600 dark:text-slate-400">PHP and markdown views resolve cleanly from the app views directory.</p>
|
||||
</article>
|
||||
<article class="card">
|
||||
<h3 class="text-lg font-semibold text-slate-950 dark:text-white">Reusable UI</h3>
|
||||
<p class="mt-3 text-sm leading-6 text-slate-600 dark:text-slate-400">Sections, buttons, cards, containers, and preset backgrounds are ready to use.</p>
|
||||
</article>
|
||||
<article class="card">
|
||||
<h3 class="text-lg font-semibold text-slate-950 dark:text-white">Dark mode</h3>
|
||||
<p class="mt-3 text-sm leading-6 text-slate-600 dark:text-slate-400">Theme preference follows the system first, then persists your manual choice.</p>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="ideas" class="section">
|
||||
<div class="contain">
|
||||
<div class="grid gap-10 lg:grid-cols-[0.8fr_1.2fr] lg:items-start">
|
||||
<div>
|
||||
<p class="eyebrow">FramexEngine ideas</p>
|
||||
<h2 class="mt-4 text-3xl font-semibold text-slate-950 sm:text-4xl dark:text-white">Start small, then grow only where the project needs it.</h2>
|
||||
<p class="mt-5 text-base leading-7 text-slate-600 dark:text-slate-400">
|
||||
Framex works well for pages that should be easy to edit, fast to ship, and simple to understand from the filesystem.
|
||||
</p>
|
||||
<div class="mt-8">
|
||||
<a class="btn btn-secondary" href="/demo">View demo pages</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-4 sm:grid-cols-2">
|
||||
<article class="card">
|
||||
<div class="bg-pre-blue mb-5 inline-flex rounded-lg px-3 py-2 text-sm font-semibold">01</div>
|
||||
<h3 class="text-lg font-semibold text-slate-950 dark:text-white">Documentation hub</h3>
|
||||
<p class="mt-3 text-sm leading-6 text-slate-600 dark:text-slate-400">Use Markdown views for guides, API notes, changelogs, and internal knowledge bases.</p>
|
||||
</article>
|
||||
<article class="card">
|
||||
<div class="bg-pre-emerald mb-5 inline-flex rounded-lg px-3 py-2 text-sm font-semibold">02</div>
|
||||
<h3 class="text-lg font-semibold text-slate-950 dark:text-white">Client landing pages</h3>
|
||||
<p class="mt-3 text-sm leading-6 text-slate-600 dark:text-slate-400">Build fast campaign pages with shared templates, reusable cards, and Tailwind utilities.</p>
|
||||
</article>
|
||||
<article class="card">
|
||||
<div class="bg-pre-amber mb-5 inline-flex rounded-lg px-3 py-2 text-sm font-semibold">03</div>
|
||||
<h3 class="text-lg font-semibold text-slate-950 dark:text-white">API dashboards</h3>
|
||||
<p class="mt-3 text-sm leading-6 text-slate-600 dark:text-slate-400">Use PHP views for simple data pages, status panels, metrics, and external API summaries.</p>
|
||||
</article>
|
||||
<article class="card">
|
||||
<div class="bg-pre-rose mb-5 inline-flex rounded-lg px-3 py-2 text-sm font-semibold">04</div>
|
||||
<h3 class="text-lg font-semibold text-slate-950 dark:text-white">Personal publishing</h3>
|
||||
<p class="mt-3 text-sm leading-6 text-slate-600 dark:text-slate-400">Create a lightweight blog, portfolio, or notes site without adding a database first.</p>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="markdown" class="section">
|
||||
<div class="contain grid gap-10 lg:grid-cols-[0.9fr_1.1fr] lg:items-start">
|
||||
<div>
|
||||
<p class="eyebrow">Markdown pages</p>
|
||||
<h2 class="mt-4 text-3xl font-semibold text-slate-950 sm:text-4xl dark:text-white">Drop in a `.md` file and get a designed page.</h2>
|
||||
<p class="mt-5 text-base leading-7 text-slate-600 dark:text-slate-400">
|
||||
Framex already parses markdown views. The refreshed `.prose` layer now styles content, code, images, tables, and blockquotes automatically in both themes.
|
||||
</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<article class="prose">
|
||||
<h1>Markdown preview</h1>
|
||||
<p>Write normal content and let the design system handle spacing, readable line length, and theme colors.</p>
|
||||
<blockquote><p>Markdown pages should look intentional without extra template work.</p></blockquote>
|
||||
<pre><code>## Fast content
|
||||
- Create a view.md file
|
||||
- Publish clean HTML
|
||||
- Keep styling automatic</code></pre>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="themes" class="section border-y border-slate-200 bg-white dark:border-slate-800 dark:bg-slate-900/40">
|
||||
<div class="contain">
|
||||
<div class="max-w-2xl">
|
||||
<p class="eyebrow">Preset colors</p>
|
||||
<h2 class="mt-4 text-3xl font-semibold text-slate-950 sm:text-4xl dark:text-white">Four reusable light and dark background helpers.</h2>
|
||||
</div>
|
||||
<div class="mt-10 grid gap-4 md:grid-cols-4">
|
||||
<div class="bg-pre-blue rounded-lg p-5">
|
||||
<p class="font-semibold">Blue</p>
|
||||
<p class="mt-2 text-sm opacity-80">Primary calls and product highlights.</p>
|
||||
</div>
|
||||
<div class="bg-pre-emerald rounded-lg p-5">
|
||||
<p class="font-semibold">Emerald</p>
|
||||
<p class="mt-2 text-sm opacity-80">Success states and fresh sections.</p>
|
||||
</div>
|
||||
<div class="bg-pre-amber rounded-lg p-5">
|
||||
<p class="font-semibold">Amber</p>
|
||||
<p class="mt-2 text-sm opacity-80">Notes, warnings, and warm accents.</p>
|
||||
</div>
|
||||
<div class="bg-pre-rose rounded-lg p-5">
|
||||
<p class="font-semibold">Rose</p>
|
||||
<p class="mt-2 text-sm opacity-80">Promos and energetic content blocks.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<div class="contain">
|
||||
<div class="rounded-lg bg-slate-950 px-6 py-12 text-center text-white shadow-xl shadow-slate-950/20 dark:bg-white dark:text-slate-950">
|
||||
<p class="text-sm font-semibold uppercase tracking-widest text-blue-300 dark:text-blue-600">Ready foundation</p>
|
||||
<h2 class="mx-auto mt-4 max-w-2xl text-3xl font-semibold sm:text-4xl">Start with structure, styling, and markdown already connected.</h2>
|
||||
<div class="mt-8 flex justify-center">
|
||||
<a class="btn bg-white text-slate-950 hover:bg-slate-100 dark:bg-slate-950 dark:text-white dark:hover:bg-slate-900" href="/docs">Open documentation</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
11
app/views/lab.php
Normal file
11
app/views/lab.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<div class="section bg-amber-100">
|
||||
<div class="contain">
|
||||
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Qui excepturi soluta quos nostrum, est ex, maxime repudiandae laborum molestias inventore debitis. Nihil quidem explicabo assumenda debitis quas, beatae molestiae officiis.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section bg-pre-blue">
|
||||
<div class="contain">
|
||||
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Qui excepturi soluta quos nostrum, est ex, maxime repudiandae laborum molestias inventore debitis. Nihil quidem explicabo assumenda debitis quas, beatae molestiae officiis.</p>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user