A Hypothetical website template for bootstrapping new projects.
- Written and maintained by Kevin MacMartin
- A choice between an SPA on top of a PHP backend or a pure SSR site (See the Public section below for more information)
- A flexible dashboard for managing data/assets and displaying collected form data
- Great defaults and popular libraries to build on top of
- A cookie-based language toggle feature that allows multiple languages to be placed inline
- A custom Sass function allowing values to be specified in
px
and output inrem
- A function available in the SPA version of the site that loads webp if supported by the browser and jpg if it isn't
- Bootstrap 5
- Browsersync
- Fontawesome
- Gsap
- Gulp
- Jquery
- Laravel 11.1.5
- Sass
- Vue 3 (Optional)
The following steps can be followed to get things running for the first time:
- Copy the
.env.example
file to.env
and configure its values as required. - Create a new database named whatever you've set
DB_DATABASE
to in the.env
file. - Run the
init.sh
script and wait for it to complete.
The .env
file includes deployment-specific configuration options, and Laravel has documentation explaining it in further detail HERE.
The APP_ENV
and APP_DEBUG
variables should be configured in one of the following combinations depending on the scenario:
- Local development should be configured with
APP_ENV=local
andAPP_DEBUG=true
. - A remote staging server should be configured with
APP_ENV=staging
andAPP_DEBUG=true
. - A remote production server should be configured with
APP_ENV=production
andAPP_DEBUG=false
.
The init.sh
script is located in the root of the project and is used to keep the database and compiled assets in sync with the codebase.
It's the recommended way to handle the initial project setup, and can also be run manually or by deployment scripts to keep things up to date after pulling in changes.
The following steps are performed in this order when run:
- Checks the local system for dependencies required by the script and exits with an error if any are missing.
- Checks to see if the
.env
file exists and exits with an error if it doesn't. - (artisan) Puts the website in maintenance mode.
- Downloads and updates non-development composer dependencies.
- Checks to see if the
APP_KEY
variable in the.env
file is empty, and if it is, generates a value for it. - Clears the route and blade cache to ensure everything will be build fresh against the current codebase and dependencies.
- (artisan) Run new database migrations.
- Cleans, downloads and updates npm dependencies.
- Runs
gulp --production
to build project files and copy fonts topublic/fonts
(uses the local version of gulp installed innode_modules
). - (artisan) Takes the website out of maintenance mode.
NOTE: Items with (artisan)
prepended to them won't be run if init.sh
is run with the --no-artisan
flag.
In the root of the project is a file named gulpfile.js
that can be used by gulp
to copy fonts, compile javascript and sass, and watch files for changes during development.
Reading through its contents is encouraged for a complete understanding of what it does, but the following commands should handle most of what it's needed for out of the box:
gulp
: Update the compiled javascript and css inpublic/js
andpublic/css
, and copy fonts topublic/fonts
.gulp --production
: Does the same asgulp
except the compiled javascript and css is minified, and console logging is removed from the javascript (good for production deployments).gulp default watch
: Does the same asgulp
but continues running to watch for changes to files so it can recompile updated assets and reload them in the browser using Browsersync (good for development environments).
NOTE: If gulp
isn't installed globally or its version is less than 4
, you should use the version included in node_modules
by running "$(npm bin)/gulp"
in place of the gulp
command.
Browsersync is used to keep the browser in sync with your code when running the watch
task with gulp.
The default public facing website is an SPA using Vue.js. To configure a non-SPA traditional SSR website remove the following files before moving the contents of traditional-bootstrap
into the root project:
package-lock.json
resources/components
resources/js/mixins
resources/js/imports
The following list of files and directories are where various pieces of the public website are located:
resources/views/templates/base.blade.php
: The outer template for the entire websiteresources/views/templates/public.blade.php
: The inner template for the public siteresources/fonts
: The folder containing website fonts (these get loaded intopublic/fonts/
by the gulpfile)resources/js/app.js
: The main javascript file that loads the public siteresources/js/mixins
: The folder containing Vue.js mixins that can be applied globally inresources/js/app.js
or in individual componentsresources/js/mixins/base-page.js
: The base-page mixin with page functionality that should be imported into all page componentsresources/components
: The folder containing Vue.js componentsresources/components/pages
: Page components that should be imported into vue-router inresources/js/app.js
resources/components/sections
: Section components (single-use per page) that should be imported into mixins or page componentsresources/components/partials
: Partial components (multi-use per page or section) that should be imported into mixins and/or page and section components
resources/sass/app.scss
: The main sass file for the public siteresources/sass/_fonts.scss
: Stylesheet containing font declarations and mixins declared to use those fonts in other stylesheetsresources/sass/_var.scss
: Stylesheet containing variables to be used in other stylesheetsresources/sass/pages
: Stylesheets for page-specific styles wrapped in the respective page component classresources/sass/sections
: Stylesheets for section-specific styles wrapped in the respective section component classresources/sass/partials
: Stylessheets for partial-specific styles wrapped in the respective partial component classresources/sass/classes
: General stylesheets for classes that can be used anywhereresources/sass/mixins
: Stylesheets declaring SCSS mixins for use in other stylesheetspublic/favicon.ico
andpublic/favicon.png
: Placeholders for the favicon filespublic/img/logo.png
: Placeholder for the website logopublic/img/social-image-card.jpg
andpublic/img/social-image-opengraph.jpg
: Placeholders for images that will show up in social shares
Dependencies can be included with npm and loaded either into the jsPublicLibs
array in the gulpfile or imported in the javascript.
Other information about database interaction, routing, controllers, etc can be viewed in the Laravel Documentation.
The default language is set by the APP_LOCALE
variable in the .env
file; this will be the language used until the cookie has been updated.
The language cookie can be updated a number of ways:
- Visiting a link to
/language/{lang}
will update the language to whatever{lang}
is set to and then reload the current page. - Running
Language::setSessionLanguage($lang)
in PHP will update the language to whatever$lang
is. - Running
this.$store.commit("setAppLang", lang);
in a Vue.js component will update the language to whateverlang
is as well as update component text to the current language on-the-fly.
A multi-language text block can be included in a number of ways depending where it's being done:
In PHP or a Laravel blade:
{{ Language::select([ 'en' => 'This is a sentence', 'fr' => 'C’est une phrase' ]) }}
In a Laravel blade:
@lang([
'en' => 'This is a sentence',
'fr' => 'C’est une phrase'
])
In a Vue.js component:
<lang :c-strings="{ en: 'This is a sentence', fr: 'C’est une phrase' }" />
The naming convention of dashboard database tables and model classes should be the following:
- Database table names should be lower case with hyphen separators:
your_table_name
- Model classes should be the same name but in camel case with its first character capitalized:
YourTableName.php
andclass YourTableName extends DashboardModel
The REGISTRATION
variable in the .env
file controls whether a new dashboard user can be registered.
The system admin can control registration by configuring the REGISTRATION
variable in the following ways:
REGISTRATION=false
: Registration is disabledREGISTRATION=true
: Registration is enabled for everyoneREGISTRATION=192.168.1.123
: Registration is selectively enabled for the IP address192.168.1.123
The dashboard menu can be edited by changing the $menu
array in app/Dashboard.php
.
The each item in the array is itself an array, containing either a menu item or a dropdown of menu items.
Dropdowns should contain the following keys:
title
: The text that appears on the dropdown itemsubmenu
: This is an array of menu items.
Menu items should contain the following keys:
title
: The text that appears on the menu itemtype
: The dashboard type (this can beview
for a viewable table oredit
for an editable list)model
: The lowercase name of the database model
Create a model that extends the DashboardModel
class and override variables that don't fit the defaults.
$dashboard_type
: The dashboard type:view
: Display a viewable table showing the dataedit
: Provides a list of rows and the option to edit their contentslist
: Allows another model to use this one to create an editable list of one or more items
$dashboard_heading
: This sets the heading that appears on the dashboard page; not setting this will use the model name$export
: This enables a button that allows the table to be exported as a spreadsheet
These are variables that only function when the $dashboard_type
variable is set to edit
.
$create
: A boolean determining whether to enable a button that allows new records to be created$delete
: A boolean determining whether to enable a button that allows records to be deleted$filter
: A boolean determining whether to enable an input field that allows records to be searched$dashboard_help_text
: An html string that will add a help box to the top of the edit-item page$dashboard_display
: An array to configure what column data to show on each item in the edit-list$dashboard_reorder
: A boolean determining whether to render drag handles to reorder the items in the list$dashboard_sort_column
: A string containing the column used to sort the list (this column should be aninteger
when$dashboard_reorder
is true)$dashboard_sort_direction
: When$dashboard_reorder
is false this determines the sort direction (this can bedesc
for descending orasc
ascending)$dashboard_button
: Add a dashboard button with custom functionality by populating an array containing the following items in this order:- The title
- Confirmation text asking the user to confirm
- A "success" message to display when the response is
success
- A "failure" message to display when the response is not
success
- The URL to send the POST request to with the respective
id
in the request variable
$dashboard_id_link
: Add a dashboard button linking to another list filtered by the current item by populating an array containing the following items in this order:- The title
- The URL to link to where the id will come after the rest
All DashboardModel
models require a $dashboard_columns
array that declares which columns to show and how to treat them.
All models use the following attributes:
name
: The name of the modeltitle
: (optional) The title that should be associated with the model; when unset this becomes the model name with its first letter capitalized
Models with their $dashboard_type
set to edit
also use:
type
: The column type which can be any of the following:hidden
: Fields that will contain values to pass to the update function but won't appear on the page (this must be used for the sort column)user
: This should point to a foreign key that references the id on the users table; setting this will bind items to the user that created themstring
: Single-line text input fieldtext
: Multi-line text input fieldcurrency
: Text input field for currency datadate
: Date selection tool for date/time datadate-time
: Date and time selection tool for date/time datamkd
: Multi-line text input field with a markdown editorselect
: Text input via option selectlist
: One or moretext
orimage
items saved to a connected tableimage
: Fields that contain image uploadsfile
: Fields that contains file uploadsdisplay
: Displayed information that can't be edited
required
: If set an error will be displayed if the field has no valueunique
: If set an error will be displayed if another row in the table has the same value for a given columntype-new
: This takes the same options astype
and overrides it when creating new items (eg: to allow input on a field during creation but not after)options
(required byselect
) Takes an array of options that are either strings or arrays containing the keystitle
(for what will display with the option) andvalue
(for what will be recorded)name
: (required byfile
andimage
) Used along with the record id to determine the filenamedelete
: (optional forfile
andimage
) Enables a delete button for the upload when set to trueext
: (required byfile
and optional forimage
) Configures the file extension of the upload (image
defaults tojpg
)model
: (required bylist
) The class name of the model that the list will be generated fromforeign
(required bylist
) The name of the list table's foreign id column that references the id on the current tablesort
(required bylist
) The name of the list table's column that the order will be stored inmax_width
: (optional forimage
) Configures the maximum width of an image upload (defaults to0
which sets no maximum width)max_height
: (optional forimage
) Configures the maximum height of an image upload (defaults to0
which sets no maximum height)
Models with their $dashboard_type
set to list
also use:
type
: The column type which can be any of the following:string
: Single-line text input fieldimage
: Fields that contain image uploads
ext
: (optional forimage
) Configures the file extension of the upload (image
defaults tojpg
)
An example of the $dashboard_columns
array in a model with its $dashboard_type
set to view
:
public static $dashboard_columns = [
[ 'title' => 'Date', 'name' => 'created_at' ],
[ 'name' => 'email' ],
[ 'name' => 'name' ]
];
An example of the $dashboard_columns
array in a model with its $dashboard_type
set to edit
:
public static $dashboard_columns = [
[ 'name' => 'user_id', 'type' => 'user' ],
[ 'name' => 'created_at', 'title' => 'Date', 'type' => 'display' ],
[ 'name' => 'title', 'required' => true, 'unique' => true, 'type' => 'string' ],
[ 'name' => 'body', 'required' => true, 'type' => 'mkd' ],
[ 'name' => 'header-image', 'title' => 'Header Image', 'type' => 'image', 'delete' => true, 'ext' => 'jpg' ],
[ 'name' => 'tags', 'type' => 'list', 'model' => 'BlogTags', 'foreign' => 'blog_id', 'sort' => 'order' ]
];
An example of the $dashboard_columns
array in a model with its $dashboard_type
set to list
:
public static $dashboard_columns = [
[ 'type' => 'string', 'name' => 'name' ],
[ 'type' => 'image', 'name' => 'photo' ]
];