github.com/golazy/golazy@v0.0.7-0.20221012133820-968fe65a0b65/lazyview/document/document.go (about)

     1  // package document provides helpers to generate an html document
     2  package document
     3  
     4  import (
     5  	"io"
     6  
     7  	. "github.com/golazy/golazy/lazyview/html"
     8  	"github.com/golazy/golazy/lazyview/nodes"
     9  )
    10  
    11  type Document struct {
    12  	Styles     []string
    13  	Scripts    []string
    14  	Head       []interface{}
    15  	Components []Component
    16  	Lang       string
    17  	Title      string
    18  	Viewport   string
    19  	LayoutBody func(l *Document, content ...interface{}) io.WriterTo
    20  }
    21  
    22  var DefaultLayout = &Document{}
    23  
    24  func Layout(content ...interface{}) io.WriterTo {
    25  	return DefaultLayout.With(content)
    26  }
    27  
    28  func AddComponent(c Component) {
    29  	DefaultLayout.AddComponent(c)
    30  }
    31  
    32  func (l *Document) AddComponent(c Component) {
    33  	l.Components = append(l.Components, c)
    34  }
    35  
    36  func (l *Document) With(content ...interface{}) io.WriterTo {
    37  	styles := []nodes.Element{}
    38  	for _, s := range l.Styles {
    39  		styles = append(styles, Style(nodes.Raw(s)))
    40  	}
    41  
    42  	var scripts []interface{}
    43  	if len(l.Scripts) > 0 {
    44  		for _, s := range l.Scripts {
    45  			scripts = append(scripts, Script(nodes.Raw(s)))
    46  		}
    47  	}
    48  
    49  	head := l.Head
    50  
    51  	// Append components
    52  	for _, c := range l.Components {
    53  		for _, s := range c.Scripts {
    54  			scripts = append(scripts, Script(nodes.Raw(s)))
    55  		}
    56  		head = append(head, c.Head...)
    57  		for _, s := range c.Styles {
    58  			styles = append(styles, Style(s))
    59  		}
    60  	}
    61  
    62  	var body interface{}
    63  	if l.LayoutBody != nil {
    64  		body = l.LayoutBody(l, content...)
    65  	} else {
    66  		body = Body(content...)
    67  	}
    68  	var lang interface{}
    69  	if l.Lang != "" {
    70  		lang = Lang(l.Lang)
    71  	}
    72  	var title interface{}
    73  	if l.Title != "" {
    74  		title = Title(l.Title)
    75  	}
    76  
    77  	var viewport interface{}
    78  	if l.Viewport != "" {
    79  		viewport = Meta(Name("viewport"), ContentAttr(l.Viewport))
    80  	}
    81  
    82  	return Html(
    83  		lang,
    84  		Head(
    85  			title,
    86  			viewport,
    87  			styles,
    88  			scripts,
    89  			head,
    90  		),
    91  		body,
    92  	)
    93  }
    94  
    95  func LayoutBody(l *Document, content ...interface{}) io.WriterTo {
    96  	return Body(
    97  		Header(
    98  			Nav(
    99  				A(Href("/", "Home")),
   100  				A(Href("/", "Home")),
   101  				A(Href("/", "Home")),
   102  			),
   103  			H1(l.Title),
   104  		),
   105  		Main(content...),
   106  		Footer("© 2022"),
   107  	)
   108  }
   109  
   110  func PageStyle() string {
   111  	return `.post-link {
   112    font-size: 1.6rem;
   113    font-weight: bold;
   114  }
   115  
   116  .meta {
   117    color: var(--text-light);
   118    font-size: 1rem;
   119  }
   120  
   121  .blog-item {
   122    margin-bottom: 4rem;
   123  }
   124  
   125  nav a.current {
   126    color: var(--accent) !important;
   127    border-color: var(--accent);
   128  }
   129  nav a:focus {
   130    color: var(--accent) !important;
   131    border-color: var(--accent);
   132  }
   133  
   134  .notice {
   135    background: var(--accent-bg);
   136    border: 2px solid var(--border);
   137    border-radius: 5px;
   138    padding: 1.5rem;
   139    margin: 2rem 0;
   140  }
   141  
   142  .medium {
   143    font-size: 1.4rem;
   144  }
   145  
   146  .small {
   147    font-size: 1rem;
   148  }
   149  
   150  .button {
   151    border: none;
   152    border-radius: 5px;
   153    background: var(--accent);
   154    font-size: 1rem;
   155    color: var(--bg);
   156    padding: 0.7rem 0.9rem;
   157    margin: 0.5rem 0;
   158  }
   159  
   160  .button:hover,
   161  .button:focus {
   162    filter: brightness(1.4);
   163    cursor: pointer;
   164  }
   165  
   166  .icon {
   167    vertical-align: sub;
   168    padding-right: .25rem;
   169    display: inline-block;
   170    width: 1em;
   171    height: 1em;
   172    stroke-width: 0;
   173    stroke: currentColor;
   174    fill: currentColor;
   175  }`
   176  }
   177  func SimpleCSS() string {
   178  	return `:root{--sans-font:-apple-system,BlinkMacSystemFont,"Avenir Next",Avenir,"Nimbus Sans L",Roboto,Noto,"Segoe UI",Arial,Helvetica,"Helvetica Neue",sans-serif;--mono-font:Consolas,Menlo,Monaco,"Andale Mono","Ubuntu Mono",monospace;--bg:#fff;--accent-bg:#f5f7ff;--text:#212121;--text-light:#585858;--border:#d8dae1;--accent:#0d47a1;--code:#d81b60;--preformatted:#444;--marked:#ffdd33;--disabled:#efefef}@media (prefers-color-scheme:dark){:root{--bg:#212121;--accent-bg:#2b2b2b;--text:#dcdcdc;--text-light:#ababab;--border:#666;--accent:#ffb300;--code:#f06292;--preformatted:#ccc;--disabled:#111}img,video{opacity:.8}}html{font-family:var(--sans-font);scroll-behavior:smooth}body{color:var(--text);background:var(--bg);font-size:1.15rem;line-height:1.5;display:grid;grid-template-columns:1fr min(45rem,90%) 1fr;margin:0}body>*{grid-column:2}header{background:var(--accent-bg);border-bottom:1px solid var(--border);text-align:center;padding:0 .5rem 2rem .5rem;grid-column:1/-1;box-sizing:border-box}header h1{max-width:1200px;margin:1rem auto}header p{max-width:40rem;margin:1rem auto}main{padding-top:1.5rem}footer{margin-top:4rem;padding:2rem 1rem 1.5rem 1rem;color:var(--text-light);font-size:.9rem;text-align:center;border-top:1px solid var(--border)}h1{font-size:3rem}h2{font-size:2.6rem;margin-top:3rem}h3{font-size:2rem;margin-top:3rem}h4{font-size:1.44rem}h5{font-size:1.15rem}h6{font-size:.96rem}h1,h2,h3{line-height:1.1}@media only screen and (max-width:720px){h1{font-size:2.5rem}h2{font-size:2.1rem}h3{font-size:1.75rem}h4{font-size:1.25rem}}a,a:visited{color:var(--accent)}a:hover{text-decoration:none}[role=button],a button,button,input[type=button],input[type=reset],input[type=submit]{border:none;border-radius:5px;background:var(--accent);font-size:1rem;color:var(--bg);padding:.7rem .9rem;margin:.5rem 0}[role=button][aria-disabled=true],a button[disabled],button[disabled],input[type=button][disabled],input[type=checkbox][disabled],input[type=radio][disabled],input[type=reset][disabled],input[type=submit][disabled],select[disabled]{cursor:default;opacity:.5;cursor:not-allowed}input:disabled,select:disabled,textarea:disabled{cursor:not-allowed;background-color:var(--disabled)}input[type=range]{padding:0}abbr{cursor:help}[role=button]:focus,[role=button]:not([aria-disabled=true]):hover,button:enabled:hover,button:focus,input[type=button]:enabled:hover,input[type=button]:focus,input[type=reset]:enabled:hover,input[type=reset]:focus,input[type=submit]:enabled:hover,input[type=submit]:focus{filter:brightness(1.4);cursor:pointer}nav{font-size:1rem;line-height:2;padding:1rem 0}nav a,nav a:visited{margin:0 1rem 0 0;border:1px solid var(--border);border-radius:5px;color:var(--text);display:inline-block;padding:.1rem 1rem;text-decoration:none}nav a:hover{color:var(--accent);border-color:var(--accent)}@media only screen and (max-width:750px){nav a{border:none;padding:0;color:var(--accent);text-decoration:underline;line-height:1}}details{background:var(--accent-bg);border:1px solid var(--border);border-radius:5px;margin-bottom:1rem}summary{cursor:pointer;font-weight:700;padding:.6rem 1rem}details[open]{padding:.6rem 1rem .75rem 1rem}details[open] summary{margin-bottom:.5rem;padding:0}details[open]>:last-child{margin-bottom:0}table{border-collapse:collapse;width:100%;margin:1.5rem 0}td,th{border:1px solid var(--border);text-align:left;padding:.5rem}th{background:var(--accent-bg);font-weight:700}tr:nth-child(even){background:var(--accent-bg)}table caption{font-weight:700;margin-bottom:.5rem}input,select,textarea{font-size:inherit;font-family:inherit;padding:.5rem;margin-bottom:.5rem;color:var(--text);background:var(--bg);border:1px solid var(--border);border-radius:5px;box-shadow:none;box-sizing:border-box;width:60%;-moz-appearance:none;-webkit-appearance:none;appearance:none}select{background-image:linear-gradient(45deg,transparent 49%,var(--text) 51%),linear-gradient(135deg,var(--text) 51%,transparent 49%);background-position:calc(100% - 20px),calc(100% - 15px);background-size:5px 5px,5px 5px;background-repeat:no-repeat}select[multiple]{background-image:none!important}input[type=checkbox],input[type=radio]{vertical-align:bottom;position:relative}input[type=radio]{border-radius:100%}input[type=checkbox]:checked,input[type=radio]:checked{background:var(--accent)}input[type=checkbox]:checked::after{content:" ";width:.1em;height:.25em;border-radius:0;position:absolute;top:.05em;left:.18em;background:0 0;border-right:solid var(--bg) .08em;border-bottom:solid var(--bg) .08em;font-size:1.8em;transform:rotate(45deg)}input[type=radio]:checked::after{content:" ";width:.25em;height:.25em;border-radius:100%;position:absolute;top:.125em;background:var(--bg);left:.125em;font-size:32px}textarea{width:80%}@media only screen and (max-width:720px){input,select,textarea{width:100%}}input[type=checkbox],input[type=radio]{width:auto}input[type=file]{border:0}hr{color:var(--border);border-top:1px;margin:1rem auto}mark{padding:2px 5px;border-radius:4px;background:var(--marked)}main img,main video{max-width:100%;height:auto;border-radius:5px}figure{margin:0;text-align:center}figcaption{font-size:.9rem;color:var(--text-light);margin-bottom:1rem}blockquote{margin:2rem 0 2rem 2rem;padding:.4rem .8rem;border-left:.35rem solid var(--accent);color:var(--text-light);font-style:italic}cite{font-size:.9rem;color:var(--text-light);font-style:normal}code,kbd,pre,pre span,samp{font-size:1.075rem;font-family:var(--mono-font);color:var(--code)}kbd{color:var(--preformatted);border:1px solid var(--preformatted);border-bottom:3px solid var(--preformatted);border-radius:5px;padding:.1rem}pre{padding:1rem 1.4rem;max-width:100%;overflow:auto;overflow-x:auto;color:var(--preformatted);background:var(--accent-bg);border:1px solid var(--border);border-radius:5px}pre code{color:var(--preformatted);background:0 0;margin:0;padding:0}`
   179  }