diff --git a/app/Core/Router.php b/app/Core/Router.php index f516352..28f3dff 100644 --- a/app/Core/Router.php +++ b/app/Core/Router.php @@ -4,7 +4,7 @@ * File: Router.php * Path: /app/Core/ * Purpose: Core router handling HTTP method–specific route dispatching with dynamic path and closure support. - * Version: 1.3 + * Version: 1.4 * Author: Wizdom Networks * ============================================ */ @@ -13,25 +13,30 @@ namespace WizdomNetworks\WizeWeb\Core; use WizdomNetworks\WizeWeb\Utilities\Logger; use WizdomNetworks\WizeWeb\Utilities\ErrorHandler; +use WizdomNetworks\WizeWeb\Core\View; class Router { + /** + * Array of registered routes indexed by HTTP method and path. + * @var array + */ private array $routes = []; /** - * Registers a new route. + * Registers a controller-based route with optional path parameters. * - * @param string $path The URL path (e.g. /contact or /verify/{code}). - * @param string $controller The fully qualified controller class. - * @param string $method The method name in the controller. - * @param string $httpMethod HTTP method (GET, POST, etc.), defaults to GET. + * @param string $path The route path (e.g. "/contact" or "/verify/{code}"). + * @param string $controller Fully qualified controller class. + * @param string $method Method in controller to invoke. + * @param string $httpMethod HTTP method (GET, POST, etc.). Defaults to GET. */ public function add(string $path, string $controller, string $method, string $httpMethod = 'GET'): void { $normalizedPath = trim($path, '/'); $routeKey = strtoupper($httpMethod) . ':' . $normalizedPath; - // Convert path with {param} to regex and store original keys + // Transform path into regex pattern and extract parameter names $paramKeys = []; $regexPath = preg_replace_callback('/\{([a-zA-Z_][a-zA-Z0-9_]*)\}/', function ($matches) use (&$paramKeys) { $paramKeys[] = $matches[1]; @@ -51,9 +56,9 @@ class Router /** * Registers a closure-based route. * - * @param string $path - * @param \Closure $callback - * @param string $httpMethod + * @param string $path The route path. + * @param \Closure $callback Anonymous function to handle the route. + * @param string $httpMethod HTTP method (GET, POST, etc.). Defaults to GET. */ public function addClosure(string $path, \Closure $callback, string $httpMethod = 'GET'): void { @@ -63,9 +68,9 @@ class Router } /** - * Dispatch the request based on the path and HTTP method. + * Dispatches the current request to the matching route or fallback to 404. * - * @param string $path The requested path (from index.php). + * @param string $path The requested path, usually from index.php. */ public function dispatch($path) { @@ -78,19 +83,23 @@ class Router continue; } - $routePattern = $route['pattern'] ?? null; - - // Handle Closure + // Handle closure route directly if ($route instanceof \Closure && $key === $routeKeyBase . $cleanPath) { Logger::info("Executing closure route: [$httpMethod] $cleanPath"); $route(); return; } - // Handle dynamic path matches - if ($routePattern && preg_match($routePattern, $cleanPath, $matches)) { - array_shift($matches); // first match is the whole path + // Only continue if route is an array + if (!is_array($route)) { + continue; + } + $routePattern = $route['pattern'] ?? null; + + // Match dynamic route patterns and extract parameters + if ($routePattern && preg_match($routePattern, $cleanPath, $matches)) { + array_shift($matches); // Remove full match $params = array_combine($route['params'], $matches) ?: []; $controllerName = $route['controller']; $method = $route['method']; @@ -99,7 +108,6 @@ class Router if (!class_exists($controllerName)) { throw new \Exception("Controller not found: $controllerName"); } - $controller = new $controllerName(); if (!method_exists($controller, $method)) { @@ -122,8 +130,9 @@ class Router } } + // If no route matched, render 404 page Logger::error("Route not found: [$httpMethod] $path"); http_response_code(404); - echo "404 Not Found"; + View::render('pages/404'); } } diff --git a/public/assets/css/main.css b/public/assets/css/main.css index 9ddd415..3ae37cb 100644 --- a/public/assets/css/main.css +++ b/public/assets/css/main.css @@ -661,6 +661,19 @@ h6 { font-size: 13px; } +.footer-logo-img { + max-height: 40px; + height: auto; + width: auto; + display: block; +} + +@media (max-width: 576px) { + .footer-logo-img { + max-height: 32px; + } +} + /*-------------------------------------------------------------- # Preloader --------------------------------------------------------------*/ @@ -972,6 +985,35 @@ section, /*-------------------------------------------------------------- # About Section --------------------------------------------------------------*/ +/* === ABOUT SECTION HEADINGS === */ +.about-h1 { + font-size: 1.5rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 1px; + margin-bottom: 1rem; +} + +/* === ABOUT SECTION PARAGRAPH STYLES === */ +.about-i { + font-style: italic; + font-size: 1rem; + font-weight: 400; + margin-bottom: 0.5rem; +} + +/* === ABOUT SECTION LAYOUT === */ +#about-row { + margin-top: 2rem; + row-gap: 3rem; +} + +.about-small { + font-size: 0.95rem; + font-weight: 400; + line-height: 1.6; +} + .about ul { list-style: none; padding: 0; @@ -1131,6 +1173,29 @@ section, max-height: 70%; } +/*-------------------------------------------------------------- +# Ethos Section +--------------------------------------------------------------*/ +.ethos-list { + padding-left: 0; + list-style: none; + margin-top: 1rem; +} + +.ethos-list li { + margin-bottom: 1rem; + display: flex; + align-items: flex-start; +} + +.ethos-list i { + font-size: 1.2rem; + color: var(--primary); + margin-right: 0.75rem; + margin-top: 0.15rem; +} + + /*-------------------------------------------------------------- # Skills Section --------------------------------------------------------------*/ @@ -1669,6 +1734,11 @@ section, margin-left: 8px; } +.greyscale-img { + filter: grayscale(100%); +} + + /*-------------------------------------------------------------- # Pricing Section --------------------------------------------------------------*/ @@ -3632,3 +3702,11 @@ Header override --nav-color: #37517e; --nav-hover-color: #315fac; } + +/* Medium and up screen enhancements */ +@media (min-width: 992px) { + #about-row .col-lg-4 { + padding-left: 1rem; + padding-right: 1rem; + } +} diff --git a/public/assets/img/404-toronto-traffic.png b/public/assets/img/404-toronto-traffic.png new file mode 100644 index 0000000..0f0f95c Binary files /dev/null and b/public/assets/img/404-toronto-traffic.png differ diff --git a/public/assets/img/404-wondering1.webp b/public/assets/img/404-wondering1.webp new file mode 100644 index 0000000..b079d3b Binary files /dev/null and b/public/assets/img/404-wondering1.webp differ diff --git a/public/assets/img/bg/CTA-Toronto-Circuit.webp b/public/assets/img/bg/CTA-Toronto-Circuit.webp new file mode 100644 index 0000000..73a4572 Binary files /dev/null and b/public/assets/img/bg/CTA-Toronto-Circuit.webp differ diff --git a/public/assets/img/cta/CTA-Toronto-Circuit.webp b/public/assets/img/cta/CTA-Toronto-Circuit.webp new file mode 100644 index 0000000..73a4572 Binary files /dev/null and b/public/assets/img/cta/CTA-Toronto-Circuit.webp differ diff --git a/public/assets/img/form-email-related/email-expired.webp b/public/assets/img/form-email-related/email-expired.webp new file mode 100644 index 0000000..cc5ef85 Binary files /dev/null and b/public/assets/img/form-email-related/email-expired.webp differ diff --git a/public/assets/img/form-email-related/email-verified-arsha.png b/public/assets/img/form-email-related/email-verified-arsha.png new file mode 100644 index 0000000..1617ce0 Binary files /dev/null and b/public/assets/img/form-email-related/email-verified-arsha.png differ diff --git a/public/assets/img/form-email-related/email-verified-arsha3.png b/public/assets/img/form-email-related/email-verified-arsha3.png new file mode 100644 index 0000000..be52a04 Binary files /dev/null and b/public/assets/img/form-email-related/email-verified-arsha3.png differ diff --git a/public/assets/img/form-email-related/email-verified-final.webp b/public/assets/img/form-email-related/email-verified-final.webp new file mode 100644 index 0000000..9c1b784 Binary files /dev/null and b/public/assets/img/form-email-related/email-verified-final.webp differ diff --git a/public/assets/img/form-email-related/email-verified.png b/public/assets/img/form-email-related/email-verified.png new file mode 100644 index 0000000..95dd71d Binary files /dev/null and b/public/assets/img/form-email-related/email-verified.png differ diff --git a/public/assets/img/form-email-related/verified-envelope-seal.webp b/public/assets/img/form-email-related/verified-envelope-seal.webp new file mode 100644 index 0000000..735ddb8 Binary files /dev/null and b/public/assets/img/form-email-related/verified-envelope-seal.webp differ diff --git a/public/assets/img/person/l12-headshot-cropped-purplebg.png b/public/assets/img/person/l12-headshot-cropped-purplebg.png new file mode 100644 index 0000000..1ad5baa Binary files /dev/null and b/public/assets/img/person/l12-headshot-cropped-purplebg.png differ diff --git a/public/assets/img/person/l12-headshot.webp b/public/assets/img/person/l12-headshot.webp new file mode 100644 index 0000000..d84299a Binary files /dev/null and b/public/assets/img/person/l12-headshot.webp differ diff --git a/public/assets/img/steps/Strategic Parnership.png b/public/assets/img/steps/Strategic Parnership.png new file mode 100644 index 0000000..b66409b Binary files /dev/null and b/public/assets/img/steps/Strategic Parnership.png differ diff --git a/resources/views/layouts/footer.php b/resources/views/layouts/footer.php index 26618a2..017c001 100644 --- a/resources/views/layouts/footer.php +++ b/resources/views/layouts/footer.php @@ -1,7 +1,7 @@ +