From f2104a198e35cb06aea99fb4ddb585c334bcd3b9 Mon Sep 17 00:00:00 2001 From: Marcus Kammer Date: Sat, 15 Jul 2023 12:06:16 +0200 Subject: [PATCH] Define package grid --- cl-sbt.asd | 2 +- src/layout/col.lisp | 193 +++++++++++++++++++++++++++++++++++++++++++ src/layout/grid.lisp | 52 ++++++++++++ src/main.lisp | 24 ------ 4 files changed, 246 insertions(+), 25 deletions(-) create mode 100644 src/layout/col.lisp create mode 100644 src/layout/grid.lisp diff --git a/cl-sbt.asd b/cl-sbt.asd index 535bf42..878e492 100644 --- a/cl-sbt.asd +++ b/cl-sbt.asd @@ -23,7 +23,7 @@ (:file "spinner"))) (:module "src/layout" :components - ((:file "col")))) + ((:file "grid")))) :description "A Common Lisp library for generating Bootstrap-based HTML markup. It provides macros to easily create Bootstrap components such as accordions, alerts, badges, buttons, cards, dropdowns, headers, list groups, navbars, nav-tabs, pagination, and tables. This library is dependent on the Spinneret library for HTML generation." :in-order-to ((test-op (test-op "cl-sbt/tests")))) diff --git a/src/layout/col.lisp b/src/layout/col.lisp new file mode 100644 index 0000000..655d8fc --- /dev/null +++ b/src/layout/col.lisp @@ -0,0 +1,193 @@ +;; Bootstrap's grid system allows you to create flexible and responsive layouts +;; through a series of containers, rows, and columns. It uses a 12-column +;; layout as a base, but allows for combining columns to create wider sections. + +;; Here are the main aspects of Bootstrap's grid system: + +;; Containers: These are the most basic layout element in Bootstrap and are +;; required to wrap site contents. There are two types of containers available: +;; container (which sets a max-width at each responsive breakpoint) and +;; container-fluid (which is always full width). + +;; Rows: Rows are horizontal groups of columns that ensure your columns are +;; lined up properly due to the flexbox layout underneath. They must be placed +;; within a container for proper alignment and padding. + +;; Columns: Columns are the immediate child of rows. Content should be placed +;; within columns, and only columns may be immediate children of rows. They can +;; be customized based on different screen sizes (referred to as breakpoints in +;; Bootstrap) using the appropriate classes (like .col-md-6 for medium +;; screens). Columns create gutters (gaps between column content) via padding. + +;; Breakpoints: Bootstrap has five responsive breakpoints; these are xs (extra +;; small, less than 576px), sm (small, greater than 576px), md (medium, greater +;; than 768px), lg (large, greater than 992px), and xl (extra large, greater +;; than 1200px). Each of these represent a media query, ensuring your layout +;; adapts to the viewing environment. + +;; Offsetting and Ordering: Bootstrap also provides classes to offset and +;; reorder your columns, allowing more granular control over your layout. + +;; Nesting: Columns can be nested, meaning you can have a column be a grid +;; container for additional columns. + +;; The grid system is based on flexbox, ensuring flexibility and feature +;; richness. From mobile to desktop, the grid system will scale up +;; appropriately to ensure your designs are fully responsive. + +(defpackage cl-sbt-grid + (:use :cl) + (:export + :container + :row + :col)) + +(in-package :cl-sbt-grid) + +(defun make-class (name size-offset-pair) + "Generates a Bootstrap class string for a particular breakpoint. + +NAME is the name of the breakpoint (e.g., 'xs', 'sm', 'md', etc.). + +SIZE-OFFSET-PAIR is either nil, or a list of up to two elements. +If it is nil, this function will generate a 'container-NAME' class. +If it is a list, the first element is interpreted as the size, and the +second element (if present) is interpreted as the offset. +In this case, the function generates a 'col-NAME-SIZE offset-NAME-OFFSET' +class string (omitting the offset part if no offset was specified). + +Examples: + (make-class 'md nil) ; => \" container-md\" + (make-class 'xs '(6)) ; => \" col-xs-6\" + (make-class 'sm '(3 1)) ; => \" col-sm-3 offset-sm-1\"" + (if size-offset-pair + (let ((size (first size-offset-pair)) + (offset (second size-offset-pair))) + (concatenate 'string + (if size (format nil " col-~a-~d" name size) "") + (if offset (format nil " offset-~a-~d" name offset) ""))) + (format nil " container-~a" name))) + +(defmacro container ((&key + (fluid nil) + (xs nil) + (sm nil) + (md nil) + (lg nil) + (xl nil) + (xxl nil)) &body body) + "Generates a Bootstrap container. + +FLUID: When non-nil, the container becomes fluid (full width). +XS, SM, MD, LG, XL, XXL: Specify the size of the container at various breakpoints. + +Example: + (container (:fluid t :sm 10) + (col (:md (6 nil)) \"Hello, world!\")) + +This will generate a fluid container with a medium-sized column inside it, +containing the text 'Hello, world!'." + `(spinneret:with-html + (:div :class + ,(concatenate 'string + (if (null fluid) "container" "container-fluid") + (if (null xs) "" (make-class "xs" nil)) + (if (null sm) "" (make-class "sm" nil)) + (if (null md) "" (make-class "md" nil)) + (if (null lg) "" (make-class "lg" nil)) + (if (null xl) "" (make-class "xl" nil)) + (if (null xxl) "" (make-class "xxl" nil))) + ,@body))) + +(defun make-row-class (name value) + "Generates a Bootstrap row class string for a particular breakpoint or a general column setting. + +NAME is the name of the breakpoint (e.g., 'xs', 'sm', 'md', etc.), or 'cols' +for a general setting. + +VALUE is an integer that specifies the number of equal-width columns at the +given breakpoint or in general. + +The function generates a 'row-cols-NAME-VALUE' class string. If NAME is 'cols', +it omits the NAME part. + +Examples: + (make-row-class \"md\" 3) ; => \" row-cols-md-3\" + (make-row-class \"cols\" 2) ; => \" row-cols-2\"" + (if value + (if (string-equal "cols" name) + (format nil " row-cols-~d" value) + (format nil " row-cols-~a-~d" name value)) + "")) + +(defmacro row ((&key + (xs nil) + (sm nil) + (md nil) + (lg nil) + (xl nil) + (xxl nil) + (cols nil)) &body body) + "Generates a Bootstrap row. + +XS, SM, MD, LG, XL, XXL: Specify the number of equal-width columns for extra small, small, medium, large, extra large, and extra extra large devices respectively. +COLS: Specifies the number of columns irrespective of the viewport or breakpoint size. + +Examples: + (row (:xs 2) \"Hello, world!\") + ; Creates a row with two equal-width columns for extra small devices, + ; containing the text 'Hello, world!' + + (row (:sm 4 :md 3 :lg 2) \"Hello, world!\") + ; Creates a row with four equal-width columns for small devices, three for + ; medium devices, and two for large devices, containing the text 'Hello, world!' + + (row (:cols 3) \"Hello, world!\") + ; Creates a row with three equal-width columns irrespective of the viewport + ; or breakpoint size, containing the text 'Hello, world!' + +This will generate a row element with Bootstrap classes based on the given +arguments, containing the specified body content." + `(spinneret:with-html + (:div :class + ,(concatenate 'string + "row" + (if (null xs) "" (make-row-class "xs" xs)) + (if (null sm) "" (make-row-class "sm" sm)) + (if (null md) "" (make-row-class "md" md)) + (if (null lg) "" (make-row-class "lg" lg)) + (if (null xl) "" (make-row-class "xl" xl)) + (if (null xxl) "" (make-row-class "xxl" xxl)) + (if (null cols) "" (make-row-class "cols" cols))) + ,@body))) + +(defmacro col ((&key + (xs nil) + (sm nil) + (md nil) + (lg nil) + (xl nil) + (xxl nil) + (col nil)) &body body) + "Generates a Bootstrap column. + +COL: Specifies the number of columns the element spans (default 12). +XS, SM, MD, LG, XL, XXL: List that specify the number of columns the element spans and optional offset at various breakpoints. + +Example: + (col (:col 6 :md (8 2)) \"Hello, world!\") + +This will generate a column that spans 6 columns by default, 8 medium-sized +columns with an offset of 2 medium-sized columns, containing the text 'Hello, +world!'." + `(spinneret:with-html + (:div :class + ,(concatenate 'string + (if (null col) "col" (format nil "col-~d" col)) + (if (null xs) "" (make-class "xs" xs)) + (if (null sm) "" (make-class "sm" sm)) + (if (null md) "" (make-class "md" md)) + (if (null lg) "" (make-class "lg" lg)) + (if (null xl) "" (make-class "xl" xl)) + (if (null xxl) "" (make-class "xxl" xxl))) + ,@body))) diff --git a/src/layout/grid.lisp b/src/layout/grid.lisp new file mode 100644 index 0000000..b1778b3 --- /dev/null +++ b/src/layout/grid.lisp @@ -0,0 +1,52 @@ +(defpackage cl-sbt-grid + (:use :cl) + (:export + :col + :col-md + :col-xs + :col-sm + :col-lg)) + +(in-package :cl-sbt-grid) + +(defmacro col ((&key + (xs nil) + (sm nil) + (md nil) + (lg nil) + (xl nil) + (xxl nil)) &body body) + `(spinneret:with-html + (:div :class + ,(concatenate 'string + (if (null xs) "" (format nil "col-xs-~d" xs)) + (if (null sm) "" (format nil " col-sm-~d" sm)) + (if (null md) "" (format nil " col-md-~d" md)) + (if (null lg) "" (format nil " col-lg-~d" lg)) + (if (null xl) "" (format nil " col-xl-~d" xl)) + (if (null xxl) "" (format nil " col-xxl-~d" xxl))) + ,@body))) + +(defmacro col-md ((&key (grid 12) (offset 0)) &body body) + "Medium device grid columns >= 992 px" + `(spinneret:with-html + (:div :class (format nil "col-md-~d col-md-offset-~d" ,grid ,offset) + ,@body))) + +(defmacro col-xs ((&key (grid 12) (offset 0)) &body body) + "Extra small device grid columns, Phones < 768 px" + `(spinneret:with-html + (:div :class (format nil "col-xs-~d col-xs-offset-~d" ,grid ,offset) + ,@body))) + +(defmacro col-sm ((&key (grid 12) (offset 0)) &body body) + "Small device grid columns, Tablets >= 768 px" + `(spinneret:with-html + (:div :class (format nil "col-sm-~d col-sm-offset-~d" ,grid ,offset) + ,@body))) + +(defmacro col-lg ((&key (grid 12) (offset 0)) &body body) + "Large devices , Desktops >= 1200 px" + `(spinneret:with-html + (:div :class (format nil "col-lg-~d col-lg-offset-~d" ,grid ,offset) + ,@body))) diff --git a/src/main.lisp b/src/main.lisp index 71ff45a..5a8c154 100644 --- a/src/main.lisp +++ b/src/main.lisp @@ -24,30 +24,6 @@ (:div :class "row" ,@body))) -(defmacro col-md ((&key (grid 12) (offset 0)) &body body) - "Medium device grid columns >= 992 px" - `(spinneret:with-html - (:div :class (format nil "col-md-~d col-md-offset-~d" ,grid ,offset) - ,@body))) - -(defmacro col-xs ((&key (grid 12) (offset 0)) &body body) - "Extra small device grid columns, Phones < 768 px" - `(spinneret:with-html - (:div :class (format nil "col-xs-~d col-xs-offset-~d" ,grid ,offset) - ,@body))) - -(defmacro col-sm ((&key (grid 12) (offset 0)) &body body) - "Small device grid columns, Tablets >= 768 px" - `(spinneret:with-html - (:div :class (format nil "col-sm-~d col-sm-offset-~d" ,grid ,offset) - ,@body))) - -(defmacro col-lg ((&key (grid 12) (offset 0)) &body body) - "Large devices , Desktops >= 1200 px" - `(spinneret:with-html - (:div :class (format nil "col-lg-~d col-lg-offset-~d" ,grid ,offset) - ,@body))) - (defmacro icon ((&key (glyph "asterisk"))) "Glyphicon from bootstrap" `(spinneret:with-html