-
= htmlspecialchars($stat['number']) ?>
-
= htmlspecialchars($stat['label']) ?>
+
= safe($stat['number']) ?>
+
= safe($stat['label']) ?>
diff --git a/components/testimonials.php b/components/example/testimonials.php
similarity index 93%
rename from components/testimonials.php
rename to components/example/testimonials.php
index 70ff1e0..6663248 100644
--- a/components/testimonials.php
+++ b/components/example/testimonials.php
@@ -36,7 +36,7 @@
"
-
= htmlspecialchars($testimonial['content']) ?>
+
= safe($testimonial['content']) ?>
★
@@ -44,10 +44,10 @@
-
+
-
= htmlspecialchars($testimonial['name']) ?>
-
= htmlspecialchars($testimonial['role']) ?>
+
= safe($testimonial['name']) ?>
+
= safe($testimonial['role']) ?>
diff --git a/components/theme-switcher.php b/components/example/theme-switcher.php
similarity index 97%
rename from components/theme-switcher.php
rename to components/example/theme-switcher.php
index c04a00a..03a6019 100644
--- a/components/theme-switcher.php
+++ b/components/example/theme-switcher.php
@@ -41,11 +41,12 @@
if (!themeToggle) return;
- // Get current theme from localStorage or default to light
- let currentTheme = localStorage.getItem('theme') || 'light';
+ let defaultTheme = 'dark';
+ let currentTheme = localStorage.getItem('theme') || defaultTheme;
// Apply current theme on load
- applyTheme(currentTheme);
+ if(currentTheme != defaultTheme)
+ applyTheme(currentTheme);
// Handle theme toggle click
themeToggle.addEventListener('click', function() {
diff --git a/config/settings.php b/config/settings.php
index aaa2607..2b4479f 100755
--- a/config/settings.php
+++ b/config/settings.php
@@ -29,13 +29,15 @@
'site' => array(
'name' => 'Web App Starter',
'default_page_title' => 'Home',
+ 'include_paths' => ['views/', 'components/', ''],
),
'users' => array(
'enable_signup' => true,
),
'menu' => array(
'' => array('title' => 'Home', 'hidden' => true),
- 'page1' => array('title' => 'Page 1',),
+ 'page1' => array('title' => 'Components',),
+ 'features' => array('title' => 'Features',),
'page2' => array('title' => 'Page 2',),
),
diff --git a/index.php b/index.php
index d3579f9..1ef4d63 100755
--- a/index.php
+++ b/index.php
@@ -6,12 +6,24 @@
URL::MakeRoute();
- Profiler::log('ready');
+ Profiler::log('main content: start', 1);
+ $content_file = 'views/'.first(URL::$route['l-path'], 'index');
ob_start();
- print(component('views/'.first(URL::$route['l-path'], 'index'), array($prop['id'] => $_REQUEST['attr']['id'])));
+ if(file_exists($content_file.'.php'))
+ {
+ require($content_file.'.php');
+ }
+ else
+ {
+ header('HTTP/1.0 404 Not Found');
+ echo '
404 Not Found ';
+ echo '
The requested page does not exist.
';
+ }
URL::$fragments['main'] = ob_get_clean();
+ Profiler::log('main content: end', -1);
+
$page_template = cfg('theme/path').'/page.'.URL::$page_type.'.php';
if(!file_exists($page_template))
$page_template = 'themes/common/page.'.URL::$page_type.'.php';
diff --git a/js/ag-grid/ag-grid-community.min.js b/js/ag-grid/ag-grid-community.min.js
new file mode 100644
index 0000000..1a78246
--- /dev/null
+++ b/js/ag-grid/ag-grid-community.min.js
@@ -0,0 +1,8 @@
+/**
+ * @ag-grid-community/all-modules - Advanced Data Grid / Data Table supporting Javascript / Typescript / React / Angular / Vue
+ * @version v31.1.0
+ * @link https://www.ag-grid.com/
+ * @license MIT
+ */
+// @ag-grid-community/all-modules v31.1.0
+!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.agGrid=t():e.agGrid=t()}(window,(function(){return function(e){var t={};function a(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,a),o.l=!0,o.exports}return a.m=e,a.c=t,a.d=function(e,t,r){a.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},a.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,t){if(1&t&&(e=a(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(a.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)a.d(r,o,function(t){return e[t]}.bind(null,o));return r},a.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(t,"a",t),t},a.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},a.p="",a(a.s=6)}([function(e,t,a){"use strict";a.r(t),a.d(t,"ColumnFactory",(function(){return it})),a.d(t,"ColumnModel",(function(){return kt})),a.d(t,"ColumnKeyCreator",(function(){return M})),a.d(t,"ColumnUtils",(function(){return At})),a.d(t,"DisplayedGroupCreator",(function(){return Ot})),a.d(t,"GroupInstanceIdCreator",(function(){return gt})),a.d(t,"GROUP_AUTO_COLUMN_ID",(function(){return ct})),a.d(t,"ComponentUtil",(function(){return Nt})),a.d(t,"AgStackComponentsRegistry",(function(){return Ut})),a.d(t,"UserComponentRegistry",(function(){return un})),a.d(t,"UserComponentFactory",(function(){return Pn})),a.d(t,"ColDefUtil",(function(){return Ln})),a.d(t,"BeanStub",(function(){return at})),a.d(t,"Context",(function(){return ie})),a.d(t,"Autowired",(function(){return de})),a.d(t,"PostConstruct",(function(){return le})),a.d(t,"PreConstruct",(function(){return ne})),a.d(t,"Optional",(function(){return ce})),a.d(t,"Bean",(function(){return ge})),a.d(t,"Qualifier",(function(){return pe})),a.d(t,"PreDestroy",(function(){return se})),a.d(t,"QuerySelector",(function(){return po})),a.d(t,"RefSelector",(function(){return ho})),a.d(t,"ExcelFactoryMode",(function(){return Nn})),a.d(t,"DragAndDropService",(function(){return Ii})),a.d(t,"DragSourceType",(function(){return Ni})),a.d(t,"DragService",(function(){return In})),a.d(t,"VirtualListDragFeature",(function(){return _n})),a.d(t,"Column",(function(){return Ee})),a.d(t,"ColumnGroup",(function(){return lt})),a.d(t,"ProvidedColumnGroup",(function(){return xe})),a.d(t,"RowNode",(function(){return Ai})),a.d(t,"RowHighlightPosition",(function(){return Bn})),a.d(t,"FilterManager",(function(){return Jn})),a.d(t,"ProvidedFilter",(function(){return ko})),a.d(t,"SimpleFilter",(function(){return Ho})),a.d(t,"ScalarFilter",(function(){return _o})),a.d(t,"NumberFilter",(function(){return ei})),a.d(t,"TextFilter",(function(){return ai})),a.d(t,"DateFilter",(function(){return Wo})),a.d(t,"TextFloatingFilter",(function(){return si})),a.d(t,"HeaderFilterCellComp",(function(){return $n})),a.d(t,"FloatingFilterMapper",(function(){return On})),a.d(t,"GridBodyComp",(function(){return $l})),a.d(t,"GridBodyCtrl",(function(){return cl})),a.d(t,"RowAnimationCssClasses",(function(){return gl})),a.d(t,"ScrollVisibleService",(function(){return ts})),a.d(t,"MouseEventService",(function(){return os})),a.d(t,"NavigationService",(function(){return ns})),a.d(t,"RowContainerComp",(function(){return us})),a.d(t,"RowContainerName",(function(){return Wl})),a.d(t,"RowContainerCtrl",(function(){return Jl})),a.d(t,"RowContainerType",(function(){return Ul})),a.d(t,"getRowContainerTypeForName",(function(){return Kl})),a.d(t,"BodyDropPivotTarget",(function(){return hs})),a.d(t,"BodyDropTarget",(function(){return bs})),a.d(t,"CssClassApplier",(function(){return Rl})),a.d(t,"HeaderRowContainerComp",(function(){return Xs})),a.d(t,"GridHeaderComp",(function(){return og})),a.d(t,"GridHeaderCtrl",(function(){return ag})),a.d(t,"HeaderRowComp",(function(){return ks})),a.d(t,"HeaderRowType",(function(){return Rs})),a.d(t,"HeaderRowCtrl",(function(){return Ks})),a.d(t,"HeaderCellCtrl",(function(){return Vs})),a.d(t,"SortIndicatorComp",(function(){return ci})),a.d(t,"HeaderFilterCellCtrl",(function(){return Ls})),a.d(t,"HeaderGroupCellCtrl",(function(){return Ws})),a.d(t,"AbstractHeaderCellCtrl",(function(){return As})),a.d(t,"HeaderRowContainerCtrl",(function(){return Qs})),a.d(t,"HorizontalResizeService",(function(){return ng})),a.d(t,"MoveColumnFeature",(function(){return fs})),a.d(t,"StandardMenuFactory",(function(){return sg})),a.d(t,"TabbedLayout",(function(){return hg})),a.d(t,"ResizeObserverService",(function(){return vg})),a.d(t,"AnimationFrameService",(function(){return wg})),a.d(t,"ExpansionService",(function(){return yg})),a.d(t,"MenuService",(function(){return Eg})),a.d(t,"LargeTextCellEditor",(function(){return wi})),a.d(t,"PopupEditorWrapper",(function(){return ss})),a.d(t,"SelectCellEditor",(function(){return Ci})),a.d(t,"TextCellEditor",(function(){return Ri})),a.d(t,"NumberCellEditor",(function(){return $i})),a.d(t,"DateCellEditor",(function(){return tn})),a.d(t,"DateStringCellEditor",(function(){return on})),a.d(t,"CheckboxCellEditor",(function(){return gn})),a.d(t,"Beans",(function(){return bl})),a.d(t,"AnimateShowChangeCellRenderer",(function(){return ki})),a.d(t,"AnimateSlideCellRenderer",(function(){return Ti})),a.d(t,"GroupCellRenderer",(function(){return ji})),a.d(t,"GroupCellRendererCtrl",(function(){return Wi})),a.d(t,"SetLeftFeature",(function(){return Os})),a.d(t,"PositionableFeature",(function(){return Ro})),a.d(t,"AutoWidthCalculator",(function(){return xg})),a.d(t,"CheckboxSelectionComponent",(function(){return Pi})),a.d(t,"CellComp",(function(){return gs})),a.d(t,"CellCtrl",(function(){return kl})),a.d(t,"RowCtrl",(function(){return Al})),a.d(t,"RowRenderer",(function(){return Ag})),a.d(t,"ValueFormatterService",(function(){return Mg})),a.d(t,"CssClassManager",(function(){return so})),a.d(t,"CheckboxCellRenderer",(function(){return ln})),a.d(t,"PinnedRowModel",(function(){return Lg})),a.d(t,"ServerSideTransactionResultStatus",(function(){return Ng})),a.d(t,"ChangedPath",(function(){return Fg})),a.d(t,"RowNodeBlock",(function(){return Ig})),a.d(t,"RowNodeBlockLoader",(function(){return _g})),a.d(t,"PaginationProxy",(function(){return qg})),a.d(t,"ClientSideRowModelSteps",(function(){return bg})),a.d(t,"StylingService",(function(){return Ug})),a.d(t,"LayoutCssClasses",(function(){return el})),a.d(t,"AgAbstractField",(function(){return Ao})),a.d(t,"AgCheckbox",(function(){return Io})),a.d(t,"AgRadioButton",(function(){return Go})),a.d(t,"AgToggleButton",(function(){return jg})),a.d(t,"AgInputTextField",(function(){return Jo})),a.d(t,"AgInputTextArea",(function(){return Kg})),a.d(t,"AgInputNumberField",(function(){return Xo})),a.d(t,"AgInputDateField",(function(){return Yg})),a.d(t,"AgInputRange",(function(){return Qg})),a.d(t,"AgRichSelect",(function(){return td})),a.d(t,"AgSelect",(function(){return Lo})),a.d(t,"AgSlider",(function(){return rd})),a.d(t,"AgGroupComponent",(function(){return id})),a.d(t,"AgMenuItemRenderer",(function(){return dn})),a.d(t,"AgMenuItemComponent",(function(){return cd})),a.d(t,"AgMenuList",(function(){return ld})),a.d(t,"AgMenuPanel",(function(){return gd})),a.d(t,"AgDialog",(function(){return md})),a.d(t,"AgPanel",(function(){return pd})),a.d(t,"Component",(function(){return uo})),a.d(t,"ManagedFocusFeature",(function(){return So})),a.d(t,"TabGuardComp",(function(){return ug})),a.d(t,"TabGuardCtrl",(function(){return cg})),a.d(t,"TabGuardClassNames",(function(){return gg})),a.d(t,"PopupComponent",(function(){return vi})),a.d(t,"PopupService",(function(){return Cd})),a.d(t,"TouchListener",(function(){return gi})),a.d(t,"VirtualList",(function(){return $g})),a.d(t,"AgAbstractLabel",(function(){return To})),a.d(t,"AgPickerField",(function(){return Oo})),a.d(t,"AgAutocomplete",(function(){return xd})),a.d(t,"CellRangeType",(function(){return pl})),a.d(t,"SelectionHandleType",(function(){return ul})),a.d(t,"AutoScrollService",(function(){return Gn})),a.d(t,"VanillaFrameworkOverrides",(function(){return zd})),a.d(t,"CellNavigationService",(function(){return Ad})),a.d(t,"AlignedGridsService",(function(){return Md})),a.d(t,"KeyCode",(function(){return Wr})),a.d(t,"VerticalDirection",(function(){return Di})),a.d(t,"HorizontalDirection",(function(){return Oi})),a.d(t,"Grid",(function(){return _u})),a.d(t,"GridCoreCreator",(function(){return qu})),a.d(t,"createGrid",(function(){return Hu})),a.d(t,"GridApi",(function(){return Un})),a.d(t,"Events",(function(){return st})),a.d(t,"FocusService",(function(){return rc})),a.d(t,"GridOptionsService",(function(){return mu})),a.d(t,"EventService",(function(){return fe})),a.d(t,"SelectableService",(function(){return kc})),a.d(t,"RowNodeSorter",(function(){return Kc})),a.d(t,"CtrlsService",(function(){return Jc})),a.d(t,"GridComp",(function(){return Xd})),a.d(t,"GridCtrl",(function(){return Qd})),a.d(t,"Logger",(function(){return Kd})),a.d(t,"LoggerFactory",(function(){return jd})),a.d(t,"SortController",(function(){return ec})),a.d(t,"TemplateService",(function(){return qd})),a.d(t,"LocaleService",(function(){return fu})),a.d(t,"_",(function(){return $r})),a.d(t,"NumberSequence",(function(){return eo})),a.d(t,"AgPromiseStatus",(function(){return to})),a.d(t,"AgPromise",(function(){return ao})),a.d(t,"Timer",(function(){return ro})),a.d(t,"ValueService",(function(){return Gd})),a.d(t,"ValueCache",(function(){return cc})),a.d(t,"ExpressionService",(function(){return _d})),a.d(t,"ValueParserService",(function(){return xu})),a.d(t,"CellPositionUtils",(function(){return Lc})),a.d(t,"RowPositionUtils",(function(){return Mc})),a.d(t,"HeaderPositionUtils",(function(){return _c})),a.d(t,"HeaderNavigationService",(function(){return eg})),a.d(t,"HeaderNavigationDirection",(function(){return Zs})),a.d(t,"DataTypeService",(function(){return Eu})),a.d(t,"PropertyKeys",(function(){return Pt})),a.d(t,"ColumnApi",(function(){return Fd})),a.d(t,"BaseComponentWrapper",(function(){return Wu})),a.d(t,"Environment",(function(){return yc})),a.d(t,"TooltipFeature",(function(){return fl})),a.d(t,"CustomTooltipFeature",(function(){return lo})),a.d(t,"DEFAULT_CHART_GROUPS",(function(){return Uu})),a.d(t,"CHART_TOOL_PANEL_ALLOW_LIST",(function(){return ju})),a.d(t,"CHART_TOOLBAR_ALLOW_LIST",(function(){return Ku})),a.d(t,"CHART_TOOL_PANEL_MENU_OPTIONS",(function(){return Yu})),a.d(t,"__FORCE_MODULE_DETECTION",(function(){return Qu})),a.d(t,"BarColumnLabelPlacement",(function(){return Ju})),a.d(t,"ModuleNames",(function(){return re})),a.d(t,"ModuleRegistry",(function(){return oe}));var r={};a.r(r),a.d(r,"makeNull",(function(){return y})),a.d(r,"exists",(function(){return S})),a.d(r,"missing",(function(){return E})),a.d(r,"missingOrEmpty",(function(){return R})),a.d(r,"toStringOrNull",(function(){return x})),a.d(r,"attrToNumber",(function(){return k})),a.d(r,"attrToBoolean",(function(){return z})),a.d(r,"attrToString",(function(){return T})),a.d(r,"jsonEquals",(function(){return A})),a.d(r,"defaultComparator",(function(){return D})),a.d(r,"values",(function(){return O}));var o={};a.r(o),a.d(o,"iterateObject",(function(){return P})),a.d(o,"cloneObject",(function(){return L})),a.d(o,"deepCloneDefinition",(function(){return N})),a.d(o,"getAllValuesInObject",(function(){return F})),a.d(o,"mergeDeep",(function(){return I})),a.d(o,"getValueUsingField",(function(){return G})),a.d(o,"removeAllReferences",(function(){return V})),a.d(o,"isNonNullObject",(function(){return H}));var i={};a.r(i),a.d(i,"doOnce",(function(){return B})),a.d(i,"warnOnce",(function(){return q})),a.d(i,"errorOnce",(function(){return W})),a.d(i,"getFunctionName",(function(){return U})),a.d(i,"isFunction",(function(){return j})),a.d(i,"executeInAWhile",(function(){return K})),a.d(i,"executeNextVMTurn",(function(){return J})),a.d(i,"executeAfter",(function(){return X})),a.d(i,"debounce",(function(){return Z})),a.d(i,"throttle",(function(){return $})),a.d(i,"waitUntil",(function(){return ee})),a.d(i,"compose",(function(){return te})),a.d(i,"noop",(function(){return ae}));var n={};a.r(n),a.d(n,"existsAndNotEmpty",(function(){return ze})),a.d(n,"last",(function(){return Te})),a.d(n,"areEqual",(function(){return Ae})),a.d(n,"shallowCompare",(function(){return De})),a.d(n,"sortNumerically",(function(){return Oe})),a.d(n,"removeRepeatsFromArray",(function(){return Me})),a.d(n,"removeFromUnorderedArray",(function(){return Pe})),a.d(n,"removeFromArray",(function(){return Le})),a.d(n,"removeAllFromUnorderedArray",(function(){return Ne})),a.d(n,"removeAllFromArray",(function(){return Fe})),a.d(n,"insertIntoArray",(function(){return Ie})),a.d(n,"insertArrayIntoArray",(function(){return Ge})),a.d(n,"moveInArray",(function(){return Ve})),a.d(n,"includes",(function(){return He})),a.d(n,"flatten",(function(){return _e})),a.d(n,"pushAll",(function(){return Be})),a.d(n,"toStrings",(function(){return qe})),a.d(n,"forEachReverse",(function(){return We}));var l={};a.r(l),a.d(l,"stopPropagationForAgGrid",(function(){return Ke})),a.d(l,"isStopPropagationForAgGrid",(function(){return Ye})),a.d(l,"isEventSupported",(function(){return Qe})),a.d(l,"getCtrlForEventTarget",(function(){return Je})),a.d(l,"isElementInEventPath",(function(){return Xe})),a.d(l,"createEventPath",(function(){return Ze})),a.d(l,"getEventPath",(function(){return $e})),a.d(l,"addSafePassiveEventListener",(function(){return et}));var s={};a.r(s),a.d(s,"utf8_encode",(function(){return mt})),a.d(s,"capitalise",(function(){return vt})),a.d(s,"escapeString",(function(){return ft})),a.d(s,"camelCaseToHumanText",(function(){return wt})),a.d(s,"camelCaseToHyphenated",(function(){return bt}));var g={};a.r(g),a.d(g,"convertToMap",(function(){return Ct})),a.d(g,"mapById",(function(){return yt})),a.d(g,"keys",(function(){return St}));var d={};a.r(d),a.d(d,"setAriaRole",(function(){return Jt})),a.d(d,"getAriaSortState",(function(){return Xt})),a.d(d,"getAriaLevel",(function(){return Zt})),a.d(d,"getAriaPosInSet",(function(){return $t})),a.d(d,"getAriaLabel",(function(){return ea})),a.d(d,"setAriaLabel",(function(){return ta})),a.d(d,"setAriaLabelledBy",(function(){return aa})),a.d(d,"setAriaDescribedBy",(function(){return ra})),a.d(d,"setAriaLive",(function(){return oa})),a.d(d,"setAriaAtomic",(function(){return ia})),a.d(d,"setAriaRelevant",(function(){return na})),a.d(d,"setAriaLevel",(function(){return la})),a.d(d,"setAriaDisabled",(function(){return sa})),a.d(d,"setAriaHidden",(function(){return ga})),a.d(d,"setAriaActiveDescendant",(function(){return da})),a.d(d,"setAriaExpanded",(function(){return ca})),a.d(d,"removeAriaExpanded",(function(){return ua})),a.d(d,"setAriaSetSize",(function(){return pa})),a.d(d,"setAriaPosInSet",(function(){return ha})),a.d(d,"setAriaMultiSelectable",(function(){return ma})),a.d(d,"setAriaRowCount",(function(){return va})),a.d(d,"setAriaRowIndex",(function(){return fa})),a.d(d,"setAriaColCount",(function(){return wa})),a.d(d,"setAriaColIndex",(function(){return ba})),a.d(d,"setAriaColSpan",(function(){return Ca})),a.d(d,"setAriaSort",(function(){return ya})),a.d(d,"removeAriaSort",(function(){return Sa})),a.d(d,"setAriaSelected",(function(){return Ea})),a.d(d,"setAriaChecked",(function(){return Ra})),a.d(d,"setAriaControls",(function(){return xa})),a.d(d,"getAriaCheckboxStateName",(function(){return ka}));var c={};a.r(c),a.d(c,"isBrowserSafari",(function(){return za})),a.d(c,"getSafariVersion",(function(){return Ta})),a.d(c,"isBrowserChrome",(function(){return Aa})),a.d(c,"isBrowserFirefox",(function(){return Da})),a.d(c,"isMacOsUserAgent",(function(){return Oa})),a.d(c,"isIOSUserAgent",(function(){return Ma})),a.d(c,"browserSupportsPreventScroll",(function(){return Pa})),a.d(c,"getTabIndex",(function(){return La})),a.d(c,"getMaxDivHeight",(function(){return Na})),a.d(c,"getBodyWidth",(function(){return Fa})),a.d(c,"getBodyHeight",(function(){return Ia})),a.d(c,"getScrollbarWidth",(function(){return Ga})),a.d(c,"isInvisibleScrollbar",(function(){return Ha}));var u={};a.r(u),a.d(u,"padStartWidthZeros",(function(){return _a})),a.d(u,"createArrayOfNumbers",(function(){return Ba})),a.d(u,"cleanNumber",(function(){return qa})),a.d(u,"decToHex",(function(){return Wa})),a.d(u,"formatNumberTwoDecimalPlacesAndCommas",(function(){return Ua})),a.d(u,"formatNumberCommas",(function(){return ja})),a.d(u,"sum",(function(){return Ka}));var p={};a.r(p),a.d(p,"serialiseDate",(function(){return Ya})),a.d(p,"dateToFormattedString",(function(){return Ja})),a.d(p,"parseDateTimeFromString",(function(){return Xa}));var h={};a.r(h),a.d(h,"radioCssClass",(function(){return $a})),a.d(h,"FOCUSABLE_SELECTOR",(function(){return er})),a.d(h,"FOCUSABLE_EXCLUDE",(function(){return tr})),a.d(h,"isFocusableFormField",(function(){return ar})),a.d(h,"setDisplayed",(function(){return rr})),a.d(h,"setVisible",(function(){return or})),a.d(h,"setDisabled",(function(){return ir})),a.d(h,"isElementChildOfClass",(function(){return nr})),a.d(h,"getElementSize",(function(){return lr})),a.d(h,"getInnerHeight",(function(){return sr})),a.d(h,"getInnerWidth",(function(){return gr})),a.d(h,"getAbsoluteHeight",(function(){return dr})),a.d(h,"getAbsoluteWidth",(function(){return cr})),a.d(h,"getElementRectWithOffset",(function(){return ur})),a.d(h,"isRtlNegativeScroll",(function(){return pr})),a.d(h,"getScrollLeft",(function(){return hr})),a.d(h,"setScrollLeft",(function(){return mr})),a.d(h,"clearElement",(function(){return vr})),a.d(h,"removeFromParent",(function(){return fr})),a.d(h,"isInDOM",(function(){return wr})),a.d(h,"isVisible",(function(){return br})),a.d(h,"loadTemplate",(function(){return Cr})),a.d(h,"ensureDomOrder",(function(){return yr})),a.d(h,"setDomChildOrder",(function(){return Sr})),a.d(h,"insertWithDomOrder",(function(){return Er})),a.d(h,"addStylesToElement",(function(){return Rr})),a.d(h,"isHorizontalScrollShowing",(function(){return xr})),a.d(h,"isVerticalScrollShowing",(function(){return kr})),a.d(h,"setElementWidth",(function(){return zr})),a.d(h,"setFixedWidth",(function(){return Tr})),a.d(h,"setElementHeight",(function(){return Ar})),a.d(h,"setFixedHeight",(function(){return Dr})),a.d(h,"formatSize",(function(){return Or})),a.d(h,"isNodeOrElement",(function(){return Mr})),a.d(h,"copyNodeList",(function(){return Pr})),a.d(h,"iterateNamedNodeMap",(function(){return Lr})),a.d(h,"addOrRemoveAttribute",(function(){return Nr})),a.d(h,"nodeListForEach",(function(){return Fr})),a.d(h,"bindCellRendererToHtmlElement",(function(){return Ir}));var m={};a.r(m),a.d(m,"fuzzyCheckStrings",(function(){return Gr})),a.d(m,"fuzzySuggestions",(function(){return Vr}));var v={};a.r(v),a.d(v,"iconNameClassMap",(function(){return _r})),a.d(v,"createIcon",(function(){return Br})),a.d(v,"createIconNoSpan",(function(){return qr}));var f={};a.r(f),a.d(f,"isEventFromPrintableCharacter",(function(){return Ur})),a.d(f,"isUserSuppressingKeyboardEvent",(function(){return jr})),a.d(f,"isUserSuppressingHeaderKeyboardEvent",(function(){return Kr})),a.d(f,"normaliseQwertyAzerty",(function(){return Yr})),a.d(f,"isDeleteKey",(function(){return Qr}));var w={};a.r(w),a.d(w,"areEventsNear",(function(){return Jr}));var b={};a.r(b),a.d(b,"sortRowNodesByOrder",(function(){return Xr}));var C={};function y(e){return null==e||""===e?null:e}function S(e,t=!1){return null!=e&&(""!==e||t)}function E(e){return!S(e)}function R(e){return null==e||0===e.length}function x(e){return null!=e&&"function"==typeof e.toString?e.toString():null}function k(e){if(void 0===e)return;if(null===e||""===e)return null;if("number"==typeof e)return isNaN(e)?void 0:e;const t=parseInt(e,10);return isNaN(t)?void 0:t}function z(e){if(void 0!==e)return null!==e&&""!==e&&("boolean"==typeof e?e:/true/i.test(e))}function T(e){if(null!=e&&""!==e)return e}function A(e,t){return(e?JSON.stringify(e):null)===(t?JSON.stringify(t):null)}function D(e,t,a=!1){const r=null==e,o=null==t;if(e&&e.toNumber&&(e=e.toNumber()),t&&t.toNumber&&(t=t.toNumber()),r&&o)return 0;if(r)return-1;if(o)return 1;function i(e,t){return e>t?1:e
t.push(e)),t}return Object.values(e)}a.r(C),a.d(C,"convertToSet",(function(){return Zr}));class M{constructor(){this.existingKeys={}}addExistingKeys(e){for(let t=0;t{if(t&&t.indexOf(e)>=0)return;const o=a[e],i=H(o)&&o.constructor===Object;r[e]=i?N(o):o}),r}function F(e){if(!e)return[];const t=Object;if("function"==typeof t.values)return t.values(e);const a=[];for(const t in e)e.hasOwnProperty(t)&&e.propertyIsEnumerable(t)&&a.push(e[t]);return a}function I(e,t,a=!0,r=!1){S(t)&&P(t,(t,o)=>{let i=e[t];if(i!==o){if(r){if(null==i&&null!=o){"object"==typeof o&&o.constructor===Object&&(i={},e[t]=i)}}H(o)&&H(i)&&!Array.isArray(i)?I(i,o,a,r):(a||void 0!==o)&&(e[t]=o)}})}function G(e,t,a){if(!t||!e)return;if(!a)return e[t];const r=t.split(".");let o=e;for(let e=0;e{"object"!=typeof e[a]||t.includes(a)||(e[a]=void 0)});const r=Object.getPrototypeOf(e),o={};Object.getOwnPropertyNames(r).forEach(e=>{if("function"==typeof r[e]&&!t.includes(e)){const t=()=>{console.warn((e=>`AG Grid: Grid API function ${e}() cannot be called as the grid has been destroyed.\n It is recommended to remove local references to the grid api. Alternatively, check gridApi.isDestroyed() to avoid calling methods against a destroyed grid.\n To run logic when the grid is about to be destroyed use the gridPreDestroy event. See: ${a}`)(e))};o[e]={value:t,writable:!0}}}),Object.defineProperties(e,o)}function H(e){return"object"==typeof e&&null!==e}const _={};function B(e,t){_[t]||(e(),_[t]=!0)}function q(e){B(()=>console.warn("AG Grid: "+e),e)}function W(e){B(()=>console.error("AG Grid: "+e),e)}function U(e){if(e.name)return e.name;const t=/function\s+([^\(]+)/.exec(e.toString());return t&&2===t.length?t[1].trim():null}function j(e){return!!(e&&e.constructor&&e.call&&e.apply)}function K(e){X(e,400)}const Y=[];let Q=!1;function J(e){Y.push(e),Q||(Q=!0,window.setTimeout(()=>{const e=Y.slice();Y.length=0,Q=!1,e.forEach(e=>e())},0))}function X(e,t=0){e.length>0&&window.setTimeout(()=>e.forEach(e=>e()),t)}function Z(e,t){let a;return function(...r){const o=this;window.clearTimeout(a),a=window.setTimeout((function(){e.apply(o,r)}),t)}}function $(e,t){let a=0;return function(...r){const o=(new Date).getTime();o-a{const l=(new Date).getTime()-o>a;(e()||l)&&(t(),n=!0,null!=i&&(window.clearInterval(i),i=null),l&&r&&console.warn(r))};l(),n||(i=window.setInterval(l,10))}function te(...e){return t=>e.reduce((e,t)=>t(e),t)}const ae=()=>{};var re;!function(e){e.CommunityCoreModule="@ag-grid-community/core",e.InfiniteRowModelModule="@ag-grid-community/infinite-row-model",e.ClientSideRowModelModule="@ag-grid-community/client-side-row-model",e.CsvExportModule="@ag-grid-community/csv-export",e.EnterpriseCoreModule="@ag-grid-enterprise/core",e.RowGroupingModule="@ag-grid-enterprise/row-grouping",e.ColumnsToolPanelModule="@ag-grid-enterprise/column-tool-panel",e.FiltersToolPanelModule="@ag-grid-enterprise/filter-tool-panel",e.MenuModule="@ag-grid-enterprise/menu",e.SetFilterModule="@ag-grid-enterprise/set-filter",e.MultiFilterModule="@ag-grid-enterprise/multi-filter",e.StatusBarModule="@ag-grid-enterprise/status-bar",e.SideBarModule="@ag-grid-enterprise/side-bar",e.RangeSelectionModule="@ag-grid-enterprise/range-selection",e.MasterDetailModule="@ag-grid-enterprise/master-detail",e.RichSelectModule="@ag-grid-enterprise/rich-select",e.GridChartsModule="@ag-grid-enterprise/charts",e.ViewportRowModelModule="@ag-grid-enterprise/viewport-row-model",e.ServerSideRowModelModule="@ag-grid-enterprise/server-side-row-model",e.ExcelExportModule="@ag-grid-enterprise/excel-export",e.ClipboardModule="@ag-grid-enterprise/clipboard",e.SparklinesModule="@ag-grid-enterprise/sparklines",e.AdvancedFilterModule="@ag-grid-enterprise/advanced-filter",e.AngularModule="@ag-grid-community/angular",e.ReactModule="@ag-grid-community/react",e.VueModule="@ag-grid-community/vue"}(re||(re={}));class oe{static register(e){oe.__register(e,!0,void 0)}static registerModules(e){oe.__registerModules(e,!0,void 0)}static __register(e,t,a){oe.runVersionChecks(e),void 0!==a?(oe.areGridScopedModules=!0,void 0===oe.gridModulesMap[a]&&(oe.gridModulesMap[a]={}),oe.gridModulesMap[a][e.moduleName]=e):oe.globalModulesMap[e.moduleName]=e,oe.setModuleBased(t)}static __unRegisterGridModules(e){delete oe.gridModulesMap[e]}static __registerModules(e,t,a){oe.setModuleBased(t),e&&e.forEach(e=>oe.__register(e,t,a))}static isValidModuleVersion(e){const[t,a]=e.version.split(".")||[],[r,o]=oe.currentModuleVersion.split(".")||[];return t===r&&a===o}static runVersionChecks(e){if(oe.currentModuleVersion||(oe.currentModuleVersion=e.version),e.version?oe.isValidModuleVersion(e)||console.error(`AG Grid: You are using incompatible versions of AG Grid modules. Major and minor versions should always match across modules. '${e.moduleName}' is version ${e.version} but the other modules are version ${this.currentModuleVersion}. Please update all modules to the same version.`):console.error(`AG Grid: You are using incompatible versions of AG Grid modules. Major and minor versions should always match across modules. '${e.moduleName}' is incompatible. Please update all modules to the same version.`),e.validate){const t=e.validate();if(!t.isValid){const e=t;console.error("AG Grid: "+e.message)}}}static setModuleBased(e){void 0===oe.moduleBased?oe.moduleBased=e:oe.moduleBased!==e&&B(()=>{console.warn("AG Grid: You are mixing modules (i.e. @ag-grid-community/core) and packages (ag-grid-community) - you can only use one or the other of these mechanisms."),console.warn("Please see https://www.ag-grid.com/javascript-grid/packages-modules/ for more information.")},"ModulePackageCheck")}static __setIsBundled(){oe.isBundled=!0}static __assertRegistered(e,t,a){var r;if(this.__isRegistered(e,a))return!0;const o=t+e;let i;if(oe.isBundled)i=`AG Grid: unable to use ${t} as 'ag-grid-enterprise' has not been loaded. Check you are using the Enterprise bundle:\n \n ');
},
@@ -27,7 +27,7 @@
function component_component_error_banner($s)
{
- ?>= htmlspecialchars($s) ?>
+ ?>= safe($s) ?>
}
/**
diff --git a/lib/odt.class.php b/lib/odt.class.php
index c2761dd..aff8028 100644
--- a/lib/odt.class.php
+++ b/lib/odt.class.php
@@ -255,7 +255,7 @@ class ODT
function odt_entities($raw)
{
- return str_replace(chr(10), ' ', htmlspecialchars($raw, ENT_XML1 | ENT_QUOTES, 'UTF-8'));
+ return str_replace(chr(10), ' ', safe($raw, ENT_XML1 | ENT_QUOTES, 'UTF-8'));
}
function break_into_segments($s)
diff --git a/lib/render.php b/lib/render.php
deleted file mode 100755
index d334575..0000000
--- a/lib/render.php
+++ /dev/null
@@ -1,137 +0,0 @@
-= htmlspecialchars($s) ?>
- }
-
- class Renderer
- {
- static $id_counter = 1000;
- static $render_funcs = array();
- static $call_stack = array();
-
- static function get_func($file_name, $return_false_if_not_found = false)
- {
- if(!isset(self::$render_funcs[$file_name]))
- {
- ob_start();
- if(file_exists('views/'.$file_name.'.php'))
- {
- $f = require('views/'.$file_name.'.php');
- URL::$route['components-invoked'][] = 'views/'.$file_name.'';
- }
- else if(file_exists('views/'.$file_name.'/index.php'))
- {
- $f = require('views/'.$file_name.'/index.php');
- URL::$route['components-invoked'][] = 'views/'.$file_name.'/index';
- }
- else
- {
- if($return_false_if_not_found) return(false);
- $f = function() use($file_name, $rcontent) {
- return('component not found: '.$file_name.'
');
- };
- }
- $rcontent = ob_get_clean();
- if(!is_callable($f))
- {
- $f = function() use($file_name, $rcontent) {
- print($rcontent);
- };
- }
- else
- {
- print($rcontent);
- }
- self::$render_funcs[$file_name] = $f;
- }
- return(self::$render_funcs[$file_name]);
- }
- }
-
- function component_path($file_name, $prop = array(), $opt = array())
- {
- $f = Renderer::get_func($file_name, true);
- if($f) return(component($file_name, $prop, $opt));
- $fpath = array();
- $seg = explode('/', $file_name);
- array_unshift($seg, '');
- $tried = array();
- $possible_paths = array();
- $path_current = '';
- foreach($seg as $idx => $s) if($s != '' || $idx == 0)
- {
- $path_current .= ($idx > 0 ? '/' : '').$s;
- $possible_paths[] = $path_current;
- }
- foreach(array_reverse($possible_paths) as $fpath) if(!$was_handled)
- {
- $fn = 'views'.$fpath.'/_path';
- $tried[] = htmlspecialchars($fn);
- if(file_exists($fn.'.php'))
- {
- $was_handled = include($fn.'.php');
- if($was_handled) URL::$route['components-invoked'][] = $fn;
- }
- }
- if(!$was_handled)
- {
- URL::$route['errors'][] = array('type' => 'component not found', 'file' => $file_name);
- return(error_banner('Component not found: '.htmlspecialchars($file_name).
- ' Also tried: - '.implode(' - ', $tried)));
- }
- }
-
- function component_open($file_name, $prop = array(), $opt = array())
- {
- $prop['open'] = true;
- return(component($file_name, $prop, $opt));
- }
-
- function component_close($file_name, $prop = array(), $opt = array())
- {
- $prop['close'] = true;
- return(component($file_name, $prop, $opt));
- }
-
- function component_open_close($file_name, $prop = array(), $opt = array())
- {
- $prop['open'] = true;
- $prop['close'] = true;
- return(component($file_name, $prop, $opt));
- }
-
- function component($file_name, $prop = array(), $opt = array())
- {
- if($file_name == '')
- {
- URL::$route['errors'][] = array('type' => 'component not found', 'file' => $file_name);
- return(error_banner('Component not found: '.htmlspecialchars($file_name)));
- }
- $f = Renderer::get_func($file_name);
- $prop['id'] = $prop['id'] ? $prop['id'] : 'c'.(Renderer::$id_counter++);
- $prop['filename'] = $file_name;
- Renderer::$call_stack[] = &$prop;
- $result = $f($prop, $opt);
- array_pop(Renderer::$call_stack);
- return($result);
- }
-
- function update($plevel)
- {
- $prop = &Renderer::$call_stack[sizeof(Renderer::$call_stack)-(1+$plevel)];
- return('K.update('.str_replace('"', '\'', json_encode($prop['id'])).');');
- }
-
- function ap(&$prop) # auto props
- {
- return('id="'.$prop['id'].'" data-com="'.$prop['filename'].'"');
- }
-
- function banner($s)
- {
- print(''.$s.'
');
- }
-
-
diff --git a/lib/ulib.php b/lib/ulib.php
index b7f4749..3f5c59f 100755
--- a/lib/ulib.php
+++ b/lib/ulib.php
@@ -11,18 +11,49 @@ spl_autoload_register(function ($class_name) {
Profiler::start();
+function get_file_location($file, $error_if_not_found = true)
+{
+ if(file_exists($file)) return $file;
+ foreach($GLOBALS['config']['site']['include_paths'] as $path)
+ {
+ if(file_exists($path.$file)) return $path.$file;
+ }
+ if($error_if_not_found)
+ die('file not found: '.$file);
+ return false;
+}
+
function include_js($src_file)
{
- ?>
+ if(!($file_location = get_file_location($src_file))) return;
+ ?>
}
function include_css($src_file)
{
- ?>
+ if(!($file_location = get_file_location($src_file))) return;
+ ?>
}
# **************************** GENERAL UTILITY FUNCTIONS ******************************
+// escapes a string for use in HTML attributes
+function asafe($s)
+{
+ return htmlspecialchars(str_replace(array("\r", "\n"), ' ', $s), ENT_QUOTES, 'UTF-8');
+}
+
+// escapes a string for use in HTML text
+function safe($s)
+{
+ return htmlspecialchars($s, ENT_QUOTES, 'UTF-8');
+}
+
+function jsafe($s)
+{
+ return json_encode($s);
+}
+
/**
* Can have any number of arguments. Returns the first of its arguments that is not false, empty string, or null.
*/
diff --git a/themes/dark/css/style.css b/themes/dark/css/style.css
index 921b6cb..b86b622 100644
--- a/themes/dark/css/style.css
+++ b/themes/dark/css/style.css
@@ -198,7 +198,6 @@ h3 {
}
#content > div:hover, .block:hover, .card:hover {
- transform: translateY(-2px);
box-shadow: var(--shadow-lg);
border-color: var(--border-hover);
}
diff --git a/themes/dark/page.html.php b/themes/dark/page.html.php
index 2438c41..966c69c 100644
--- a/themes/dark/page.html.php
+++ b/themes/dark/page.html.php
@@ -27,11 +27,13 @@
+ = component('components/example/theme-switcher') ?>
+ = component('components/basic/cookie-consent') ?>
= cfg('site/name') ?> $menu_item) if(!$menu_item['hidden'])
{
- ?>= htmlspecialchars($menu_item['title']) ?>
+ ?>= safe($menu_item['title']) ?>
}
?>
@@ -41,9 +43,6 @@
diff --git a/themes/light/css/style.css b/themes/light/css/style.css
index a7c290c..ae20e47 100755
--- a/themes/light/css/style.css
+++ b/themes/light/css/style.css
@@ -3,8 +3,8 @@
--bg-color: #f8fafc;
--bg-secondary: #ffffff;
--bg-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- --surface: #ffffff;
- --surface-elevated: #ffffff;
+ --surface: #eeeeee;
+ --surface-elevated: #eeeeee;
--surface-hover: #f1f5f9;
--primary: #3b82f6;
--primary-dark: #1d4ed8;
@@ -39,7 +39,7 @@
--error-border: #dc2626;
}
-/* Dark theme variables */
+/* Dark theme variables
.dark-theme {
--bg-color: #0f172a;
--bg-secondary: #1e293b;
@@ -62,7 +62,6 @@
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.4), 0 4px 6px -2px rgba(0, 0, 0, 0.3);
--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.5), 0 10px 10px -5px rgba(0, 0, 0, 0.4);
- /* Dark theme specific variables */
--glass-bg: rgba(30, 41, 59, 0.8);
--glass-border: rgba(148, 163, 184, 0.1);
--overlay: rgba(0, 0, 0, 0.6);
@@ -75,7 +74,7 @@
--error: #ef4444;
--error-bg: rgba(239, 68, 68, 0.1);
--error-border: rgba(239, 68, 68, 0.3);
-}
+}*/
* {
margin: 0;
@@ -235,8 +234,7 @@ h3 {
}
#content > div:hover, .block:hover, .card:hover {
- transform: translateY(-2px);
- box-shadow: var(--shadow-lg);
+ box-shadow: var(--shadow-lg);
border-color: var(--border-hover);
}
diff --git a/themes/light/page.html.php b/themes/light/page.html.php
index cc7357c..e354f3b 100755
--- a/themes/light/page.html.php
+++ b/themes/light/page.html.php
@@ -27,11 +27,13 @@
+ = component('components/example/theme-switcher') ?>
+ = component('components/basic/cookie-consent') ?>
= cfg('site/name') ?> $menu_item) if(!$menu_item['hidden'])
{
- ?>= htmlspecialchars($menu_item['title']) ?>
+ ?>= safe($menu_item['title']) ?>
}
?>
@@ -41,9 +43,6 @@
diff --git a/views/elements/error.php b/views/elements/error.php
index c486def..48f7778 100755
--- a/views/elements/error.php
+++ b/views/elements/error.php
@@ -1,5 +1,5 @@
= htmlspecialchars($prop['text']) ?>
+ ?>= safe($prop['text']) ?>
});
\ No newline at end of file
diff --git a/views/index.php b/views/index.php
index deaeefa..73dc310 100755
--- a/views/index.php
+++ b/views/index.php
@@ -1,14 +1,17 @@
-= component('components/hero-section', [
- 'title' => 'Build Amazing Impressive Stunning Web Apps',
+
+
+= component('components/example/hero-section', [
+ 'title' => 'Stunning Apps',
'subtitle' => 'Experience the power of super bloated PHP development with our gigantic and truly unwieldy component-based framework.
- Fast, secure, and developer-friendly.',
+ Seriously though this page only serves as an example repository of
+ different styles and blocks.',
'cta_text' => 'Get Started Free(mium)',
'cta_link' => '#features'
]) ?>
-= component('components/features-grid') ?>
+= component('components/example/features-grid') ?>
-= component('components/stats-section', [
+= component('components/example/stats-section', [
'stats' => [
['number' => '10K+', 'label' => 'Happy Vibe Coders'],
['number' => '<1s', 'label' => 'Page Load Time'],
@@ -17,11 +20,11 @@
]
]) ?>
-= component('components/brands-showcase') ?>
+= component('components/example/brands-showcase') ?>
-= component('components/testimonials') ?>
+= component('components/example/testimonials') ?>
-= component('components/pricing-table') ?>
+= component('components/example/pricing-table') ?>
-= component('components/cta-section', [
+= component('components/example/cta-section', [
'title' => 'Ready to Transform Your Development?',
'subtitle' => 'Join thousands of developers who have already modernized their workflow with our framework.',
'cta_text' => 'Start Your Project',
'secondary_text' => 'View GitHub'
]) ?>
-
-
-= component('components/theme-switcher') ?>
diff --git a/views/marketing.css b/views/marketing.css
new file mode 100644
index 0000000..77c5028
--- /dev/null
+++ b/views/marketing.css
@@ -0,0 +1,233 @@
+
+/* Shared base styles */
+.mono-text,
+.code-block {
+ font-family: 'SF Mono', 'Monaco', 'Menlo', monospace;
+}
+
+/* Code block container with terminal styling */
+.code-block-container {
+ background: linear-gradient(135deg, var(--surface) 0%, var(--surface-elevated) 100%);
+ padding: 2rem;
+ border-radius: var(--radius-lg);
+ border: 1px solid var(--border);
+ margin: 1rem 0;
+ position: relative;
+ overflow: hidden;
+}
+
+/* Terminal header bar */
+.terminal-header {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 3px;
+}
+
+.terminal-header.primary-gradient {
+ background: linear-gradient(90deg, var(--primary) 0%, var(--secondary) 50%, var(--accent) 100%);
+}
+
+.terminal-header.success-gradient {
+ background: linear-gradient(90deg, var(--success) 0%, var(--primary) 50%, var(--secondary) 100%);
+}
+
+.terminal-header.warning-gradient {
+ background: linear-gradient(90deg, var(--warning) 0%, var(--accent) 50%, var(--primary) 100%);
+}
+
+/* Terminal window controls */
+.terminal-controls {
+ display: flex;
+ align-items: center;
+ margin-bottom: 1rem;
+}
+
+.window-dot {
+ width: 12px;
+ height: 12px;
+ border-radius: 50%;
+ margin-right: 8px;
+}
+
+.window-dot.red { background: #ff5f56; }
+.window-dot.yellow { background: #ffbd2e; }
+.window-dot.green {
+ background: #27ca3f;
+ margin-right: 1rem;
+}
+
+/* Monospace text styling */
+.mono-text {
+ font-size: 0.875rem;
+ color: var(--text-muted);
+}
+
+/* Code block styling */
+.code-block {
+ margin: 0;
+ font-size: 0.9rem;
+ line-height: 1.6;
+ color: var(--text-primary);
+ background: none;
+}
+
+/* Card components - using shared base styles */
+.component-card,
+.success-card,
+.enhancement-card {
+ padding: 1rem;
+ border-radius: var(--radius);
+ border: 1px solid var(--border);
+}
+
+.component-card {
+ background: var(--surface-elevated);
+}
+
+.success-card {
+ background: var(--success-bg);
+ border-color: var(--success-border);
+}
+
+.enhancement-card {
+ color: var(--bg-color);
+ text-align: center;
+ border: none;
+}
+
+/* Grid layouts - shared base properties */
+.components-grid,
+.theme-grid,
+.enhancements-grid,
+.guidelines-grid {
+ display: grid;
+ gap: 1rem;
+}
+
+.components-grid {
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
+ margin: 1rem 0;
+}
+
+.theme-grid {
+ grid-template-columns: 1fr 1fr;
+ margin: 1rem 0;
+}
+
+.enhancements-grid {
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
+}
+
+.guidelines-grid {
+ gap: 0.5rem;
+}
+
+/* Guideline items */
+.guideline-item {
+ display: flex;
+ align-items: center;
+ background: var(--surface-elevated);
+ padding: 1rem;
+ border-radius: var(--radius);
+ border-left: 4px solid;
+}
+
+.guideline-icon {
+ font-size: 1.5rem;
+ margin-right: 1rem;
+}
+
+/* Demo section styling */
+.demo-section {
+ padding: 4rem 0;
+ background: var(--bg-color);
+}
+
+.demo-container {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 0 1rem;
+ text-align: center;
+}
+
+.demo-container h2 {
+ font-size: 2.5rem;
+ margin-bottom: 1rem;
+ background: linear-gradient(135deg, var(--primary), var(--secondary));
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+}
+
+.demo-container > p {
+ font-size: 1.25rem;
+ color: var(--text-secondary);
+ margin-bottom: 3rem;
+}
+
+.demo-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(500px, 1fr));
+ gap: 2rem;
+ margin-top: 3rem;
+}
+
+.demo-card {
+ background: var(--surface);
+ border: 1px solid var(--border);
+ border-radius: var(--radius-xl);
+ padding: 2.5rem;
+ box-shadow: var(--shadow-md);
+ text-align: left;
+}
+
+.demo-card h3 {
+ margin-bottom: 2rem;
+ color: var(--text-primary);
+ text-align: center;
+}
+
+.demo-form {
+ max-width: none;
+}
+
+/* Flex layouts */
+.button-showcase,
+.notification-demo {
+ display: flex;
+ gap: 1rem;
+}
+
+.button-showcase {
+ flex-wrap: wrap;
+ margin-bottom: 2rem;
+ justify-content: center;
+}
+
+.notification-demo {
+ flex-direction: column;
+}
+
+/* Responsive design lol */
+@media (max-width: 768px) {
+ .demo-grid {
+ grid-template-columns: 1fr;
+ gap: 1.5rem;
+ }
+
+ .demo-card {
+ padding: 2rem 1.5rem;
+ }
+
+ .button-showcase {
+ flex-direction: column;
+ align-items: center;
+ }
+
+ .button-showcase .btn {
+ width: 100%;
+ max-width: 250px;
+ }
+}
\ No newline at end of file
diff --git a/views/page1.php b/views/page1.php
index 4b07328..3af458c 100755
--- a/views/page1.php
+++ b/views/page1.php
@@ -1,19 +1,19 @@
Component System
-= component('components/theme-switcher:render') ?>
-
Component Declaration
-
-
-
-
-
-
-
component.php
+
+
+
+
+
-
<?php return [
+<?php return [
'render' => function ($prop ) {
// render the component
@@ -28,36 +28,36 @@
Example Components
-
-
+
+
hero-section
Landing page hero with CTA buttons
-
+
features-grid
3-column feature showcase
-
+
stats-section
Animated statistics display
-
+
testimonials
Customer testimonial carousel
-
+
cta-section
Call-to-action with background
-
+
pricing-table
Responsive pricing tiers
-
+
brands-showcase
Logo grid with animations
-
+
theme-switcher
Light/dark theme toggle
@@ -66,19 +66,19 @@
Usage Examples
-
-
-
-
-
-
-
usage-examples.php
+
+
+
+
+
+
+
usage-examples.php
-
// Basic component
-<?php component ('components/hero-section' ); ?>
+// Basic component
+<?php component ('components/example/hero-section' ); ?>
// Component with data
-<?php component ('components/stats-section' , [
+<?php component ('components/example/stats-section' , [
'title' => 'Our Growth' ,
'stats' => [
['number' => '50K+' , 'label' => 'Users' ],
@@ -90,29 +90,29 @@
-
Theme System
-
Components automatically adapt to the current theme using CSS custom properties:
-
-
+
Theme Info
+
This starter pack includes a light and a dark theme
+
+
Light Theme
themes/light/css/style.css
-
+
Dark Theme
themes/dark/css/style.css
-
-
-
-
-
-
-
variables.css
+
+
+
CSS Variables
-
/* Core theme variables */
+/* Core theme variables */
--bg-color , --bg-secondary , --surface
--text-primary , --text-secondary , --text-muted
--primary , --primary-dark , --primary-light
@@ -121,52 +121,6 @@
-
-
⚡ JavaScript Enhancements
-
-
-
Intersection Observer
-
Scroll animations
-
-
-
Theme Switching
-
localStorage persistence
-
-
-
Form Validation
-
Real-time enhancement
-
-
-
Navigation Effects
-
Scroll-based styling
-
-
-
-
-
-
Component Development Guidelines
-
-
- 🏷️
- Use semantic HTML5 elements
-
-
- 🎨
- Implement CSS custom properties for theming
-
-
- 📱
- Add responsive design with mobile-first approach
-
-
- ♿
- Include accessibility attributes (ARIA, alt text)
-
-
- ⚡
- Use progressive enhancement for JavaScript features
-
-
-
+
diff --git a/views/page2.php b/views/page2.php
index 9b452a7..1b30726 100755
--- a/views/page2.php
+++ b/views/page2.php
@@ -5,12 +5,11 @@
= nl2br('Sed at dolor leo. Morbi a tellus sed nisl dictum ultricies sit amet at purus. Nam mattis metus sed nunc egestas convallis. Fusce sagittis tellus convallis sem volutpat, a aliquam nulla posuere. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed malesuada, nunc at iaculis tempus, augue sem venenatis augue, nec hendrerit dolor arcu tempus tortor. Proin euismod nunc mi, ut ultrices elit porttitor et.
Aliquam erat volutpat. Ut non purus sit amet orci pulvinar elementum. Curabitur pharetra mi eget viverra sagittis. Maecenas consequat metus vitae gravida commodo. Sed vitae neque sed massa ultricies convallis. Duis venenatis, lacus non volutpat aliquam, augue elit aliquam odio, vitae iaculis tortor urna rhoncus magna. Morbi lacus dui, egestas vitae turpis quis, volutpat aliquam purus. Fusce in libero sapien. Pellentesque quis neque eget mauris scelerisque tempus quis iaculis arcu. Duis sollicitudin sit amet magna non finibus. Donec hendrerit erat vel nunc scelerisque viverra. Donec et elementum augue, eget fringilla arcu.') ?>
+
-
+
+
Load new text
+