|
56 | 56 | .ic.orange{background:rgba(224,138,91,.16); color:var(--orange); border-color:rgba(224,138,91,.3)} |
57 | 57 | .ic.teal{background:rgba(79,184,154,.16); color:var(--teal); border-color:rgba(79,184,154,.3)} |
58 | 58 | .ic.green{background:rgba(79,192,138,.16); color:var(--green); border-color:rgba(79,192,138,.3)} |
| 59 | +/* breadcrumb */ |
| 60 | +.crumb{font-family:var(--mono); font-size:11.5px; color:var(--faint); margin:0 0 10px; word-break:break-word} |
| 61 | +.crumb a{color:var(--muted); text-decoration:none} .crumb a:hover{color:var(--amber)} |
| 62 | +.crumb .sep{color:var(--line2); margin:0 6px} |
| 63 | +/* sub-area cards (when this node is a branch) */ |
| 64 | +.grid{display:grid; grid-template-columns:1fr; gap:9px} |
| 65 | +@media(min-width:560px){.grid{grid-template-columns:1fr 1fr}} |
| 66 | +.card{display:flex; align-items:center; gap:13px; padding:13px 14px; cursor:pointer; |
| 67 | + background:var(--panel); border:1px solid var(--line); border-radius:10px; |
| 68 | + text-decoration:none; color:inherit; transition:border-color .15s, background .15s, transform .12s} |
| 69 | +.card:hover{border-color:var(--line2); background:linear-gradient(var(--panel),var(--panel2))} |
| 70 | +.card:active{transform:translateY(1px)} |
| 71 | +.card .ic{width:40px;height:40px;font-size:18px;border-radius:9px} |
| 72 | +.cbody{flex:1 1 auto; min-width:0} |
| 73 | +.ctitle{font-size:14.5px; color:var(--ink); font-weight:600; display:flex; align-items:center; gap:8px} |
| 74 | +.tag{font-family:var(--mono); font-size:9.5px; letter-spacing:.08em; padding:2px 6px; border-radius:5px; |
| 75 | + border:1px solid var(--line2); color:var(--muted); flex:0 0 auto} |
| 76 | +.cblurb{font-size:12.5px; color:var(--muted); margin-top:2px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap} |
| 77 | +.cmeta{font-family:var(--mono); font-size:11px; color:var(--faint); flex:0 0 auto; text-align:right} |
| 78 | +.arrow{color:var(--faint); font-family:var(--mono); font-size:16px; flex:0 0 auto; transition:color .15s, transform .15s} |
| 79 | +.card:hover .arrow{color:var(--amber); transform:translateX(2px)} |
59 | 80 | h1{font-family:var(--mono); font-weight:700; font-size:23px; letter-spacing:-.01em; margin:0; line-height:1.15} |
60 | 81 | @media(min-width:560px){h1{font-size:27px}} |
61 | 82 | .sub{color:var(--muted); font-size:13.5px; margin:8px 0 2px} |
|
96 | 117 | <span class="termtitle" id="ttl">realmathmodel — bash — 80×24</span> |
97 | 118 | </div> |
98 | 119 | <div class="termbody"> |
99 | | - <a class="back" href="index.html">‹ cd ..</a> |
100 | 120 | <div id="content"></div> |
101 | 121 | <p class="foot">> realmathmodel.github.io</p> |
102 | 122 | </div> |
|
110 | 130 | function param(k){return new URLSearchParams(location.search).get(k);} |
111 | 131 | var id = param('id'); |
112 | 132 | var cats = (window.CATALOG && CATALOG.categories) || []; |
113 | | - var c = cats.filter(function(x){return x.id===id;})[0]; |
| 133 | + var owner=(window.CATALOG&&CATALOG.owner)||'hasan', host=(window.CATALOG&&CATALOG.host)||'iug'; |
114 | 134 | var box = document.getElementById('content'); |
115 | | - var owner=(CATALOG&&CATALOG.owner)||'hasan', host=(CATALOG&&CATALOG.host)||'iug'; |
| 135 | + |
| 136 | + // find path root..node (array of nodes) for breadcrumbs + back |
| 137 | + function findPath(nodes, target, trail){ |
| 138 | + for(var i=0;i<nodes.length;i++){ |
| 139 | + var n=nodes[i], t=trail.concat([n]); |
| 140 | + if(n.id===target) return t; |
| 141 | + if(n.children){ var r=findPath(n.children, target, t); if(r) return r; } |
| 142 | + } |
| 143 | + return null; |
| 144 | + } |
| 145 | + function countMeta(c){ |
| 146 | + if(c.children){ var k=c.children.length; return k+' area'+(k===1?'':'s'); } |
| 147 | + var r=(c.resources||[]); return r.length+' link'+(r.length===1?'':'s'); |
| 148 | + } |
| 149 | + |
| 150 | + var path = findPath(cats, id, []); |
| 151 | + var c = path ? path[path.length-1] : null; |
116 | 152 |
|
117 | 153 | if(!c){ |
118 | 154 | document.getElementById('ttl').textContent = 'not found — bash'; |
119 | | - box.innerHTML = '<p class="prompt"><span class="u">'+esc(owner)+'</span>@<span class="p">'+esc(host)+ |
| 155 | + box.innerHTML = '<a class="back" href="index.html">‹ cd ~</a>'+ |
| 156 | + '<p class="prompt"><span class="u">'+esc(owner)+'</span>@<span class="p">'+esc(host)+ |
120 | 157 | '</span>:<span class="d">~</span>$ cat '+esc(id||'?')+'</p>'+ |
121 | 158 | '<p class="miss">No such area. <a href="index.html">Back to the hub ›</a></p>'; |
122 | 159 | return; |
|
125 | 162 | document.getElementById('ttl').textContent = c.id + ' — bash — 80×24'; |
126 | 163 | document.title = c.title + ' — realmathmodel'; |
127 | 164 |
|
128 | | - var rows = (c.resources||[]).map(function(r){ |
129 | | - var todo = (!r.href || r.href==='#'); |
130 | | - var ext = (r.type==='external'); |
131 | | - if(todo){ |
132 | | - return '<div class="res todo">'+ |
133 | | - '<span class="kind todo">TODO</span>'+ |
134 | | - '<div class="rbody"><div class="rlabel">'+esc(r.label)+'</div>'+ |
135 | | - '<div class="rnote">'+(r.note?esc(r.note):'internal page not added yet')+'</div></div>'+ |
136 | | - '<span class="rgo">·</span></div>'; |
137 | | - } |
| 165 | + // breadcrumb + back target (parent, or hub) |
| 166 | + var parent = path.length>=2 ? path[path.length-2] : null; |
| 167 | + var backHref = parent ? ('category.html?id='+encodeURIComponent(parent.id)) : 'index.html'; |
| 168 | + var backTxt = parent ? ('‹ '+parent.title) : '‹ cd ~'; |
| 169 | + var crumb = '<a href="index.html">~</a>'; |
| 170 | + for(var i=0;i<path.length;i++){ |
| 171 | + var last = (i===path.length-1); |
| 172 | + crumb += '<span class="sep">/</span>'+(last?esc(path[i].title) |
| 173 | + : '<a href="category.html?id='+encodeURIComponent(path[i].id)+'">'+esc(path[i].title)+'</a>'); |
| 174 | + } |
| 175 | + |
| 176 | + var pwd = path.map(function(n){return n.id;}).join('/'); |
| 177 | + var header = |
| 178 | + '<a class="back" href="'+backHref+'">'+esc(backTxt)+'</a>'+ |
| 179 | + '<p class="crumb">'+crumb+'</p>'+ |
| 180 | + '<p class="prompt"><span class="u">'+esc(owner)+'</span>@<span class="p">'+esc(host)+ |
| 181 | + '</span>:<span class="d">~/'+esc(pwd)+'</span>$ '+(c.children?'ls':'open '+esc(c.id))+'</p>'+ |
| 182 | + '<div class="head"><div class="ic '+(c.accent||'amber')+'">'+esc(c.icon||'•')+'</div>'+ |
| 183 | + '<div><h1>'+esc(c.title)+'</h1></div></div>'+ |
| 184 | + (c.blurb?'<p class="sub">'+esc(c.blurb)+'</p>':''); |
| 185 | + |
| 186 | + if(c.children){ |
| 187 | + // BRANCH -> show sub-area cards |
| 188 | + var k=c.children.length; |
| 189 | + var cards = c.children.map(function(ch){ |
| 190 | + return '<a class="card" href="category.html?id='+encodeURIComponent(ch.id)+'">'+ |
| 191 | + '<div class="ic '+(ch.accent||'amber')+'">'+esc(ch.icon||'•')+'</div>'+ |
| 192 | + '<div class="cbody"><div class="ctitle">'+esc(ch.title)+(ch.tag?'<span class="tag">'+esc(ch.tag)+'</span>':'')+'</div>'+ |
| 193 | + (ch.blurb?'<div class="cblurb">'+esc(ch.blurb)+'</div>':'')+'</div>'+ |
| 194 | + '<div class="cmeta">'+countMeta(ch)+'</div><span class="arrow">›</span></a>'; |
| 195 | + }).join(''); |
| 196 | + box.innerHTML = header + |
| 197 | + '<div class="label">'+k+' area'+(k===1?'':'s')+'</div>'+ |
| 198 | + (k ? '<div class="grid">'+cards+'</div>' |
| 199 | + : '<p class="miss">No sub-areas yet — add some under <span style="color:var(--amber)">'+esc(c.id)+'</span> in <code style="color:var(--amber);font-family:var(--mono)">catalog.js</code>.</p>'); |
| 200 | + return; |
| 201 | + } |
| 202 | + |
| 203 | + // LEAF -> show resources |
| 204 | + var res=(c.resources||[]); |
| 205 | + var rows = res.map(function(r){ |
| 206 | + var todo=(!r.href||r.href==='#'), ext=(r.type==='external'); |
| 207 | + if(todo) return '<div class="res todo"><span class="kind todo">TODO</span>'+ |
| 208 | + '<div class="rbody"><div class="rlabel">'+esc(r.label)+'</div>'+ |
| 209 | + '<div class="rnote">'+(r.note?esc(r.note):'internal page not added yet')+'</div></div>'+ |
| 210 | + '<span class="rgo">·</span></div>'; |
138 | 211 | return '<a class="res" href="'+esc(r.href)+'"'+(ext?' target="_blank" rel="noopener"':'')+'>'+ |
139 | 212 | '<span class="kind '+(ext?'ext':'int')+'">'+(ext?'EXT':'INT')+'</span>'+ |
140 | 213 | '<div class="rbody"><div class="rlabel">'+esc(r.label)+'</div>'+ |
141 | 214 | (r.note?'<div class="rnote">'+esc(r.note)+'</div>':'')+'</div>'+ |
142 | 215 | '<span class="rgo">'+(ext?'↗':'›')+'</span></a>'; |
143 | 216 | }).join(''); |
144 | | - |
145 | | - var n=(c.resources||[]).length; |
146 | | - box.innerHTML = |
147 | | - '<p class="prompt"><span class="u">'+esc(owner)+'</span>@<span class="p">'+esc(host)+ |
148 | | - '</span>:<span class="d">~/study</span>$ open '+esc(c.id)+'</p>'+ |
149 | | - '<div class="head"><div class="ic '+(c.accent||'amber')+'">'+esc(c.icon||'•')+'</div>'+ |
150 | | - '<div><h1>'+esc(c.title)+'</h1></div></div>'+ |
151 | | - (c.blurb?'<p class="sub">'+esc(c.blurb)+'</p>':'')+ |
152 | | - '<div class="label">'+n+' resource'+(n===1?'':'s')+'</div>'+ |
| 217 | + box.innerHTML = header + |
| 218 | + '<div class="label">'+res.length+' resource'+(res.length===1?'':'s')+'</div>'+ |
153 | 219 | '<div class="list">'+rows+'</div>'+ |
154 | | - '<p class="note"><b>INT</b> = a page in this repo · <b>EXT</b> = outside site (new tab) · '+ |
| 220 | + '<p class="note"><b>INT</b> = page in this repo · <b>EXT</b> = outside site (new tab) · '+ |
155 | 221 | '<b>TODO</b> = add the file then set its <code>href</code> in <code>catalog.js</code>.</p>'; |
156 | 222 | })(); |
157 | 223 | </script> |
|
0 commit comments