bernhard Posted April 2 Share Posted April 2 The RockFrontend site profile for ProcessWire offers a unique combination of benefits by integrating UIKit and TailwindCSS, making it an appealing choice for developers looking for both robust UI components and extensive customization capabilities. Here are some key advantages: Rich UI Components from UIKit UIKit is known for its comprehensive collection of high-quality, ready-to-use UI components. This integration in the RockFrontend site profile allows developers to quickly implement complex components like modals, accordions, and sliders that are visually appealing and functionally robust. Flexibility and Customization with TailwindCSS TailwindCSS is a utility-first CSS framework that provides high granularity in styling elements. It allows developers to build custom designs without stepping out of the framework’s constraints. This can significantly speed up the development process, as it eliminates the need to write custom CSS from scratch. Setup Setup is as simple as these 3 steps: Download the profile Install ProcessWire and choose this profile Follow the instructions on the welcome screen Github: https://github.com/baumrock/site-rockfrontend Modules Directory: https://processwire.com/modules/site-rock-frontend/ 6 Link to comment Share on other sites More sharing options...
wbmnfktr Posted April 2 Share Posted April 2 From the newsletter: RockFrontend ❤️ HTMX And all I can say so far: YES!!! 2 Link to comment Share on other sites More sharing options...
Christophe Posted April 17 Share Posted April 17 Hello Bernhard, basic-page.php and home.php are empty template files. Are they only needed (even empty) if custom page class(es) php files that are related to them exist? Because latte files are used here I'm a bit confused about the (possible) role of these template files. In this site profile, in which use case(s) would they not stay empty? Could you please give one (or more) example(s)? Thanks in advance! NB: I don't want to use tailwind, but I'm curious about _tailwind.css, I think it's the first time I see the "_" prefix on a css file name. 1 Link to comment Share on other sites More sharing options...
bernhard Posted April 18 Author Share Posted April 18 Thx @Christophe that's some good questions ? I've updated the profile to hopefully answer all of them: https://github.com/baumrock/site-rockfrontend/commit/be55adae28ffe6a7aac83944284820f17afdaabf 18 hours ago, Christophe said: NB: I don't want to use tailwind (for several reasons, one of them is that there are resets used but uikit uses normalize already, doesn't it? (I would perhaps prefer modern-normalize or another "at-rest" for the moment project related to one of the css grids evengelists (I don't remember her name right now)), BUT I'm curious about _tailwind.css, I think it's the first time I see the "_" prefix on a css file name. You don't need to use tailwind. If you don't want to use it just remove the _tailwind.css file. If you find anything happening that should not be let me know and I'll fix it. 1 Link to comment Share on other sites More sharing options...
Christophe Posted April 23 Share Posted April 23 (edited) Hello Bernhard, A bit of context before the questions below in the message. I want to display a list of children of the parent pages that are using the template "parent-page". So, I have created parent-page.php (empty for the moment) in /site/templates. And ParentPagePage.php in /site/classes in which I have this (where I tested different things): <?php namespace ProcessWire; class ParentPagePage extends Page { public function listchildren() { return "Clickable list of children"; } } I had more elaborate code(s) in the return statement, but things weren't working so I just put a string in it to keep it simple. (I've just noticed that vscode and intelephense are writing "Undefined type 'ProcessWire\Page'." in the PROBLEMS tab.) So I had : Method DefaultPage::listchildren does not exist or is not callable in this context on pages that do not use the parent-page template (and use the basic-page template). Method HomePage::listchildren does not exist or is not callable in this context on the homepage. For the error messages and blank page(s) to disappear it seems that it is mandatory to use this in main.latte: {if $page->template == 'parent-page'} {$page->listchildren()} {/if} and not just {$page->listchildren()}. At one point with custom page classes I think I was hoping it would also remove the need for that if condition. In /site/templates/sections/main.latte I currently have the code that follows - at the end of the message now (we apparently can't escape having to use the |noescape filter). I simplified the code to only define and check $image (the code borrowed from another website was also defining and checking $images, so not only the first image, I don't remember why/if it was needed). SO, my question(s) is how could this code be simplified, in part in order to have cleaner code in this main.latte file? Which parts of the code should be in main.latte, which ones in ParentPagePage.php and which ones perhaps in parent-page.php? How would you organize/separate them in the different files? Also, can $image and $thumb be defined elsewhere? Etc. Thanks again in advance! I tried yesterday with simpler children list codes (without images and uikit markup), but it seemed complicated and not clean. And now it's more complicated. I've tried with code directly inside the return statement, and also with a variable and then returning the variable. $thumb is currently defined if $image exists. If I used <img n:if="..." src="... it would be changed. But perhaps it wouldn't be important if it wasn't defined inside the {if}...{/if}. <main> <div class="uk-container"> <h1>{$page->title}</h1> {$page->body|noescape} {if $page->template == 'parent-page'} {$page->listchildren()} {/if} <div n:if="$page->template == 'parent-page'" class='uk-child-width-1-3@m uk-grid-match uk-margin-small-top uk-margin-medium-bottom uk-text-center' uk-grid> <div n:foreach="$page->children() as $child"> <div class='uk-card uk-card-small uk-card-default uk-card-body'> <a class="h2" href="{$child->url}"> {var $image = $child->images->first()} {if $image} {var $thumb = $image->size(200, 150)} <img src="{$thumb->url}" width="{$thumb->width}" height="{$thumb->height}" alt="{$image->description}" /> {/if} <h2>{$child->title|noescape}</h2> </a> </div> </div> </div> </div> </main> Edited April 23 by Christophe Problems with the display of code. Still tabulation issue. Link to comment Share on other sites More sharing options...
bernhard Posted April 23 Author Share Posted April 23 Hi @Christophe 7 minutes ago, Christophe said: (I've just noticed that vscode and intelephense are writing "Undefined type 'ProcessWire\Page'." in the PROBLEMS tab.) Unfortunately we don't have Code Intellisense or autocomplete in latte files at the moment ? See https://github.com/smuuf/vscode-latte-lang/issues/5 9 minutes ago, Christophe said: So I had : Method DefaultPage::listchildren does not exist or is not callable in this context on pages that do not use the parent-page template (and use the basic-page template). Method HomePage::listchildren does not exist or is not callable in this context on the homepage. You are adding the method "listchildren()" to your ParentPagePage, nowhere else. That means you can all this method only on pages that have the template "parent-page". 11 minutes ago, Christophe said: At one point with custom page classes I think I was hoping it would also remove the need for that if condition. Why should it do that? You are calling a method of an object. If that does not exist it is expected to throw an error. You CAN do what you describe though. Sometimes it is useful and I'm doing that as well. You could add that method to your DefaultPage.php and there return an empty sting. That would make $page->listchildren() return "" by default, which means it does not throw an error. For some page types you can then implement a different logic: DefaultPage.php --> listchildren() { return ""; } FooPage.php extends DefaultPage --> listchildren() { return "foo!"; } BarPage.php extends DefaultPage --> listchildren() { return "BAR"; } // in any template echo $page->listchildren(); 16 minutes ago, Christophe said: SO, my question(s) is how could this code be simplified, in part in order to have cleaner code in this main.latte file? Which parts of the code should be in main.latte, which ones in ParentPagePage.php and which ones perhaps in parent-page.php? How would you organize/separate them in the different files? Also, can $image and $thumb be defined elsewhere? Etc. Thanks again in advance! That it totally up to you. Same with regular ProcessWire templates. It's up to us devs how we organise things and everybody does it differently. I can only say what I came up with and what works great for all kings of projects (from very simple to very complex ones): layout.latte for main markup /site/templates/sections/... for all sections /site/templates/partials/... for all partials Details: layout.latte --> holds the html markup skeleton of the page, eg: <html> <head>...</head> <body> <header>...</header> <main>...</main> <footer>...</footer> </body> </html> Then all my template files are usually empty (like home.php, basic-page.php, foo.php, bar.php). Next, I divide my design into sections. A section is a portion of the page that goes from the very left to the very right and has an undefined height/content. You can then add those sections to your main markup file like this: <html> <head>...</head> <body> <header> {include "sections/topbar.latte"} {include "sections/navbar.latte"} </header> <main> {include "sections/breadcrumbs.latte"} {include "sections/content.latte"} {include "sections/content-footer.latte"} </main> <footer> {include "sections/footer.latte"} </footer> </body> </html> This is often all I need, because I build all the available sections in RockPageBuilder and then I can simply add them to the pages as I need them. But it works without RockPageBuilder as well. You then just need to code all your page layouts depending on the page template. If all those pages share the same breadcrumbs and content-footer it could look like this: <html> <head>...</head> <body> <header> {include "sections/topbar.latte"} {include "sections/navbar.latte"} </header> <main> {include "sections/breadcrumbs.latte"} {if $page->template == 'foo'} {include "sections/content-foo.latte"} {elseif $page->template == 'bar'} {include "sections/content-bar.latte"} {else} {include "sections/content.latte"} {/if} {include "sections/content-footer.latte"} </main> <footer> {include "sections/footer.latte"} </footer> </body> </html> You could also use a dynamic approach: <html> <head>...</head> <body> <header> {include "sections/topbar.latte"} {include "sections/navbar.latte"} </header> <main> {include "sections/breadcrumbs.latte"} {include "content/" . $page->template . ".latte"} {include "sections/content-footer.latte"} </main> <footer> {include "sections/footer.latte"} </footer> </body> </html> It's just regular PHP inside the latte tags, so you could also do is_file() checks etc: <html> <head>...</head> <body> <header> {include "sections/topbar.latte"} {include "sections/navbar.latte"} </header> <main> {include "sections/breadcrumbs.latte"} {var $file = "content/" . $page->template . ".latte"} {if is_file($file)}{include $file}{/if} {include "sections/content-footer.latte"} </main> <footer> {include "sections/footer.latte"} </footer> </body> </html> Obviously you'd need to create those files. Here I'm placing them into a new folder called "content", which would be /site/templates/content/foo.latte for example. Next, partials: If you have repeating markup inside your sections you can outsource them into the partials folder. For example let's say you want to show a blog overview page that shows all single blog items as cards. You'd have a section like "blog-overview.latte" like this: // blog-overview.latte <div uk-grid> <div n:foreach="$page->children() as $item"> <div class="uk-card"> <h3>{$item->title}</h3> <p>{$item->teaser()}</p> </div> </div> </div> This example is very simple and if you only use your cards here, then it's easier to leave them here. If you are using the exact same cards on two or three places then you can create partials for them: // blog-overview.latte <div uk-grid> {foreach $page->children() as $item} {include "partials/card.latte", item: $item} {/foreach} </div> // /site/templates/partials/card.latte <div> <div class="uk-card"> <h3>{$item->title}</h3> <p>{$item->teaser()}</p> </div> </div> 2 Link to comment Share on other sites More sharing options...
Christophe Posted April 30 Share Posted April 30 [Deleted content] Link to comment Share on other sites More sharing options...
bernhard Posted June 3 Author Share Posted June 3 Update: The module is now available in the modules directory ? 2 Link to comment Share on other sites More sharing options...
HMCB Posted June 15 Share Posted June 15 On 6/3/2024 at 9:44 AM, bernhard said: Update: The module is now available in the modules directory ? @bernhard, this module uses both UIKit and Tailwind in conjunction? The use of UIKit is because it has premade components not available in Tailwind (out of the box)? If in conjunction, won’t the CSS styles clash with each other? My preference is for Tailwind styling so for the components we are beholden to UIKit-way of styling? Link to comment Share on other sites More sharing options...
bernhard Posted June 15 Author Share Posted June 15 7 minutes ago, HMCB said: module uses both UIKit and Tailwind in conjunction? Yes! 7 minutes ago, HMCB said: The use of UIKit is because it has premade components not available in Tailwind (out of the box)? Yes. All the great things that UIkit has to offer: Accordions, Tooltips, Alerts, Offcanvas, Dropdowns etc etc 8 minutes ago, HMCB said: If in conjunction, won’t the CSS styles clash with each other? Some parts do unfortunately, but only very, very little, because the profile only uses the @base directives from Tailwind and obviously also the @utilities (for all the great utility classes). @Stefanowitsch found out that we can even turn off preflight in the base component an we tried that on a recent project - he might have some more information on that topic. 11 minutes ago, HMCB said: My preference is for Tailwind styling so for the components we are beholden to UIKit-way of styling? I'm not sure what you mean here, but you can do whatever you want or prefer. I'm using UIkit components and then add Tailwind for all the individual changes that I need, that are not global. So if I wanted to change the global font-size I'd adjust the UIkit LESS/SCSS variable. If I wanted to change the global "margin-top": Same. But for all the small little changes that would prior go into custom .less files I just add tailwind utility classes. Think of it as UIkit on Steroids ? 1 Link to comment Share on other sites More sharing options...
HMCB Posted June 15 Share Posted June 15 @bernhard, I meant “_not_ beholden to UIKit…” At any rate, I understand everything you’ve explained. I appreciate your input. 1 Link to comment Share on other sites More sharing options...
bernhard Posted June 16 Author Share Posted June 16 Just because I had this example right now I thought it's a nice real world example why I really like the UIkit + Tailwind combo! I'm building this UI for a webshop where you can choose the taxrate: First I tried to use a <select> but I wanted to show more info in the dropdown and less in the spot where the arrow points to, so I went with a UIkit Drop. Such a dropdown sounds easy to build with some alpine magic at first, but doing it right is quite some effort! For example you have to think about accessibility and add support for keyboard navigation. UIkit has you covered. Another nice thing to mention is that the dropdown shows taxrates first and then the description on the right. This was extremely easy thx to tailwind: <span class='w-8 inline-block'> {$taxrate->taxrate()}% </span> {$taxrate->title} So all I had to do was to make the element inline-block and add a dedicated with (here w-8). That leads to a better table-like rendering ? And finally, UIkit power again: Consider the taxrate element has been hovered/clicked on mobile being at the very bottom of the page. There is not enough room for the dropdown, so UIkit will display it on top of the element automatically ? I wouldn't want to implement that on my own with only TailwindCSS + AlpineJS. Both tools are great, but I also find it great to have proven components from UIkit that I can use and adjust to my needs very quickly. PS: Here is the final snippet that combines all the great tools Latte + UIkit + TailwindCSS and is fully reactive thx to AlpineJS ? <div class='text-xs'> Preis <div class="uk-inline" {$rockcommerce->taxselect->attrs()|noescape} > <span class='cursor-pointer underline'> inkl. <span x-text='taxrate'></span>% MwSt. </span> <div class='uk-card uk-card-default uk-width-auto p-3' uk-drop='offset:10'> <div n:foreach='$rockcommerce->taxrates() as $taxrate' class='uk-text-nowrap' data-text='inkl. {$taxrate->taxrate()}% MwSt.' > <label> <input class="uk-radio mr-1" type="radio" name="taxrate" value="{$taxrate->taxrate()}" x-model='taxrate' > <span class='w-8 inline-block'> {$taxrate->taxrate()}% </span> {$taxrate->title} </label> </div> </div> </div> zzgl. Versandkosten. <br> Verfügbarkeit: Auf Anfrage. </div> Oh... There's another element with some TailwindCSS magic: span with class cursor-pointer underline that makes it look like a link so that the user knows he/she can interact with it. Link to comment Share on other sites More sharing options...
bernhard Posted July 16 Author Share Posted July 16 I'll continue the monologue... Installation and setup has recently become a lot easier as I made UIkit and Tailwind a integral part rather than an optional addon. I guess anybody not wanting one of those components will never ever use the profile anyhow. The benefit is that for a full working setup all you have to do is follow the instructions of the welcome screen: No mercy for all those who have not tried this setup! ? Link to comment Share on other sites More sharing options...
MateThemes Posted August 28 Share Posted August 28 Hello everyone, i currently start to use RockFrontend and I start with the starter profile. the problem I discover is, when I remove in _init.php the less file loaded from the uikit folder, it gives me a 500 error. As I don't want to use the less file coz I have a custom uikit file in css, how can I achieve this? <?php namespace ProcessWire; // Optional initialization file, called before rendering any template file. // This is defined by $config->prependTemplateFile in /site/config.php. // Use this to define shared variables, functions, classes, includes, etc. $rf = rockfrontend(); $rf->styles() // add the base uikit theme ->add('/site/templates/uikit/src/less/uikit.theme.less') // add default folders like /sections and /partials ->addDefaultFolders() // add the bundled tailwind utility classes ->add('/site/templates/bundle/tailwind.css') // minify on production ->minify($config->debug ? false : true); $rf->scripts() // load uikit (without defer to avoid FOUC) ->add('/site/templates/uikit/dist/js/uikit.min.js') // load uikit (with defer to avoid FOUC) ->add('/site/templates/uikit/dist/js/uikit-icons.min.js', 'defer') // load custom javascript of this project ->add('/site/templates/scripts/main.js', 'defer') // minify on production ->minify($config->debug ? false : true); For clarification I want to remove uikit.theme.less and replace it with this file: <?php namespace ProcessWire; // Optional initialization file, called before rendering any template file. // This is defined by $config->prependTemplateFile in /site/config.php. // Use this to define shared variables, functions, classes, includes, etc. $rf = rockfrontend(); $rf->styles() // add the base uikit theme ->add('/site/templates/bundle/styles.css') // add default folders like /sections and /partials ->addDefaultFolders() // add the bundled tailwind utility classes ->add('/site/templates/bundle/tailwind.css') // minify on production ->minify($config->debug ? false : true); $rf->scripts() // load uikit (without defer to avoid FOUC) ->add('/site/templates/uikit/dist/js/uikit.min.js') // load uikit (with defer to avoid FOUC) ->add('/site/templates/uikit/dist/js/uikit-icons.min.js', 'defer') // load custom javascript of this project ->add('/site/templates/scripts/main.js', 'defer') // minify on production ->minify($config->debug ? false : true); Thank you Link to comment Share on other sites More sharing options...
bernhard Posted August 28 Author Share Posted August 28 1 minute ago, MateThemes said: it gives me a 500 error. What exactly? Maybe it also loads other .less files (in addDefaultFolders()) that reference a variable from uikit. What you are trying to do should definitely be possible so I'm sure we'll get it to work 😉 Link to comment Share on other sites More sharing options...
MateThemes Posted August 28 Share Posted August 28 thank you for your fast reply. You are right. I forgot that the styles/_custom.less is referenced in the main less file. I removed it and it works fine. Thank you! Link to comment Share on other sites More sharing options...
uliverse Posted September 15 Share Posted September 15 Hi Bernhard. Thanks for creating this. I managed to install the profile and I get the welcome screen. Where I get stuck is the command line instruction... Currently I am on a local machine (MacOS / MAMP) and I have no idea how I would go about this, to be honest... Link to comment Share on other sites More sharing options...
bernhard Posted September 15 Author Share Posted September 15 Hey @uliverse thx for asking. Please invest 15 minutes to understand what npm is and does: I've added this section to the readme: https://github.com/baumrock/site-rockfrontend Quote New to NPM? Please invest 15 minutes in getting to know NPM: https://youtu.be/P3aKRdUyr0s So if you type "npm install -D" that means that you will install the dependencies listed here: https://github.com/baumrock/site-rockfrontend/blob/main/install/assets/package.json At the time of writing this we only load one dependency: "tailwindcss": "^3.4" - obviously we need tailwind for the tailwind profile 🙂 The flag "-D" means that we only need the dependency on development, not on production. So when deploying your site to a remote server you don't need to install anything from NPM (in other words: You don't need the folder "node_modules" on your live server). Does that help? Link to comment Share on other sites More sharing options...
uliverse Posted September 15 Share Posted September 15 Thank you. Helpful tutorial. 1 Link to comment Share on other sites More sharing options...
uliverse Posted September 15 Share Posted September 15 (edited) So I managed to install the npm packages in the root folder of my project (I guess this is where "site" and "wire" also live). However, the topbar.min.css is not loading and the H1 is not turning red. I found that the path to the topbar.min.css is not correct: /pwrockfrontend/pwrockfrontend/site/modules/RockFrontend/topbar/topbar.min.css instead of /pwrockfrontend/site/modules/RockFrontend/topbar/topbar.min.css Edited September 15 by uliverse Link to comment Share on other sites More sharing options...
bernhard Posted September 15 Author Share Posted September 15 Hey @uliverse sorry for the trouble. This cost me some headache today 😞 I can confirm there is an issue and I have to look into that as soon as possible. I really did a lot to make the experience as smooth as possible, but somehow something broke... Link to comment Share on other sites More sharing options...
uliverse Posted September 16 Share Posted September 16 😝 Sorry to be the messenger of bad news... I am glad it was not due to my stupidity... Again - thank you for making this available. Your contributions make PW more accessible to ordinary people like me! 😂 Link to comment Share on other sites More sharing options...
bernhard Posted September 26 Author Share Posted September 26 Hey @uliverse two days of refactoring later... Link to comment Share on other sites More sharing options...
bernhard Posted September 27 Author Share Posted September 27 And I've just pushed extensive docs to https://www.baumrock.com/en/processwire/modules/site-rockfrontend/docs/ If you haven't tried this site profile this might be a good opportunity to do so 🙂 Link to comment Share on other sites More sharing options...
uliverse Posted September 29 Share Posted September 29 (edited) Nice work! Tailwind is installing correctly now. Only the Topbar still gives me trouble, since the topbar.css is also not linked correctly. This is a minor issue, since the fronend editing module is not essential. But still... I noticed that tailwind.css is only generated ONCE. When I change the main.latte template again (to "bg-green-500" p.e.) the css file is not re-created... Is there anything I need to enable for the tailwind.js to work correctly? Edited September 30 by uliverse Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now