From 8bfa7731951d4ef83272e28298683d91f129eb8e Mon Sep 17 00:00:00 2001 From: Steve Nyemba Date: Tue, 2 Jan 2024 17:15:10 -0600 Subject: [PATCH] bug fixes and minor updates --- cms/__init__.py | 88 ++++++++++++++++++++++++--------- index.py | 109 +++++++++++++++++++++++++---------------- static/css/default.css | 3 +- static/img/logo.png | Bin 9947 -> 19732 bytes static/img/logo.svg | 5 +- static/js/menu.js | 1 - templates/404.html | 2 +- templates/header.html | 1 + templates/index.html | 5 +- templates/menu.html | 4 +- templates/pane.html | 1 + 11 files changed, 148 insertions(+), 71 deletions(-) diff --git a/cms/__init__.py b/cms/__init__.py index e009f81..32b6458 100644 --- a/cms/__init__.py +++ b/cms/__init__.py @@ -6,43 +6,61 @@ import copy from jinja2 import Environment, BaseLoader, FileSystemLoader import importlib import importlib.util +from cms import disk, cloud +# import cloud class components : + # @staticmethod + # def folders (_path): + # """ + # This function reads the content of a folder (no depth, it must be simple) + # """ + # _content = os.listdir(_path) + # return [_name for _name in _content if os.path.isdir(os.sep.join([_path,_name])) if not _name.startswith('_')] + # @staticmethod + # def content (_folder) : + # if os.path.exists(_folder) : + # # return [{'text':_name.split('.')[0].replace('_', ' ').replace('-',' ').strip(),'uri': os.sep.join([_folder,_name])} for _name in os.listdir(_folder) if not _name.startswith('_') and os.path.isfile( os.sep.join([_folder,_name]))] + # return [{'text':_name.split('.')[0].replace('_', ' ').replace('-',' ').strip(),'uri': os.sep.join([_folder,_name])} for _name in os.listdir(_folder) if not _name.startswith('_') and os.path.isfile( os.sep.join([_folder,_name]))] + # else: + # return [] @staticmethod - def folders (_path): - _content = os.listdir(_path) - - return [_name for _name in _content if os.path.isdir(os.sep.join([_path,_name])) if not _name.startswith('_')] - @staticmethod - def content (_folder) : - if os.path.exists(_folder) : - # return [{'text':_name.split('.')[0].replace('_', ' ').replace('-',' ').strip(),'uri': os.sep.join([_folder,_name])} for _name in os.listdir(_folder) if not _name.startswith('_') and os.path.isfile( os.sep.join([_folder,_name]))] - return [{'text':_name.split('.')[0].replace('_', ' ').replace('-',' ').strip(),'uri': os.sep.join([_folder,_name])} for _name in os.listdir(_folder) if not _name.startswith('_') and os.path.isfile( os.sep.join([_folder,_name]))] - else: - return [] - @staticmethod - def menu(_path,_config): + def menu(_config): """ This function will read menu and sub-menu items from disk structure, The files are loaded will """ - _items = components.folders(_path) + # _items = components.folders(_path) - _layout = copy.deepcopy(_config['layout']) - _overwrite = _layout['overwrite'] if 'overwrite' in _layout else {} + # _layout = copy.deepcopy(_config['layout']) + # _overwrite = _layout['overwrite'] if 'overwrite' in _layout else {} # # content of each menu item - _subItems = [ components.content (os.sep.join([_path,_name]))for _name in _items ] - if 'map' in _layout : - _items = [_name if _name not in _layout['map'] else _layout['map'][_name] for _name in _items] + # _subItems = [ components.content (os.sep.join([_path,_name]))for _name in _items ] + # if 'map' in _layout : + # _items = [_name if _name not in _layout['map'] else _layout['map'][_name] for _name in _items] - _object = dict(zip(_items,_subItems)) + # _object = dict(zip(_items,_subItems)) + + if 'source' in _config['system'] and _config['system']['source']['id'] == 'cloud' : + _sourceHandler = cloud + else: + _sourceHandler = disk + _object = _sourceHandler.build(_config) + # _object = disk.build(_path,_config) if type(_path) == str else cloud.build(_path,_config) + _layout = copy.deepcopy(_config['layout']) + _overwrite = _layout['overwrite'] if 'overwrite' in _layout else {} + + # + # @TODO: Find a way to translate rename/replace keys of the _object (menu) here + # #-- applying overwrites to the menu items for _name in _object : _submenu = _object[_name] _index = 0 for _item in _submenu : - text = _item['text'] + text = _item['text'].strip() + if text in _overwrite : if 'uri' in _item and 'url' in 'url' in _overwrite[text] : del _item['uri'] @@ -52,13 +70,21 @@ class components : _submenu[_index] = _item _index += 1 return _object + @staticmethod - def html(uri,id,_args={}) : + def html(uri,id,_args={},_system={}) : """ This function reads a given uri and returns the appropriate html document, and applies environment context """ - _html = (open(uri)).read() + + if 'source' in _system and _system['source']['id'] == 'cloud': + + _html = cloud.html(uri,_args) + + else: + _html = disk.html(uri) + # _html = (open(uri)).read() #return ' '.join(['
'.replace(':id',id),_html,'
']) @@ -111,10 +137,15 @@ class components : return getattr(module,_name) if hasattr(module,_name) else None @staticmethod def plugins(_config) : + """ + This function looks for plugins in the folder on disk (no cloud support) and attempts to load them + """ PATH= os.sep.join([_config['layout']['root'],'_plugins']) _map = {} if not os.path.exists(PATH) : return _map + if 'plugins' not in _config : + _config['plugins'] = {} _conf = _config['plugins'] for _key in _conf : @@ -125,6 +156,17 @@ class components : if _pointer : _uri = "/".join(["api",_key,_name]) _map[_uri] = _pointer + # + # Let us load the default plugins + + if 'source' in _config['system'] and _config['system']['source']['id'] == 'cloud' : + _plugins = cloud.plugins() + else: + _plugins = disk.plugins() + # + # If there are any plugins found, we should load them and use them + if _plugins : + _map = dict(_map,**_plugins) return _map @staticmethod def context(_config): diff --git a/index.py b/index.py index 05a6249..96d3083 100644 --- a/index.py +++ b/index.py @@ -16,8 +16,8 @@ import base64 from jinja2 import Environment, BaseLoader - _app = Flask(__name__) + @_app.route('/favicon.ico') def favicon(): global _config @@ -28,16 +28,19 @@ def favicon(): @_app.route("/") def _index (): global _config - _args = {'system':_config['system']} + _args = {} if 'plugins' in _config : - _args['routes']=_config['plugins'] + _args['routes']=['plugins'] + _system = copy.deepcopy(_config['system']) try: _args['layout'] = _config['layout'] # _args = dict(_args,**_config['layout']) # _args = copy.copy(_config) + uri = os.sep.join([_config['layout']['root'], _config['layout']['index']]) - _html = cms.components.html(uri,'index',_args) + _html = cms.components.html(uri,'index',_args,_system) + _args['index'] = _html # e = Environment(loader=BaseLoader()).from_string(_html) # e = cms.components.context(_config).from_string(_html) @@ -49,30 +52,39 @@ def _index (): _index_page = "404.html" _args['uri'] = request.base_url pass + if 'source' in _system : + del _system['source'] + _args['system'] = _system return render_template(_index_page,**_args) -@_app.route('/id/') -def people(uid): - """ - This function will implement hardened links that can directly "do something" - """ - global _config - return "0",200 +# @_app.route('/id/') +# def people(uid): +# """ +# This function will implement hardened links that can directly "do something" +# """ +# global _config +# return "0",200 @_app.route('/dialog') def _dialog (): global _config + _uri = os.sep.join([_config['layout']['root'],request.headers['uri']]) + # _uri = request.headers['uri'] _id = request.headers['dom'] # _data = cms.components.data(_config) - _args = {'system':_config['system']} + _args = {} #{'system':_config['system']} _args['title'] = _id if 'plugins' in _config : _args['routes'] = _config['plugins'] - _html = cms.components.html(_uri,_id,_args) + _system = copy.deepcopy(_config['system']) + + _html = cms.components.html(_uri,_id,_config,_system) e = Environment(loader=BaseLoader()).from_string(_html) - + if 'source' in _system : + del _system['source'] + _args['system'] = _system _args['html'] = _html _html = ''.join(["
",str( e.render(**_args)),'
']) @@ -94,13 +106,18 @@ def _getproxy(module,name) : global _config uri = '/'.join(['api',module,name]) + _args = dict(request.args,**{}) + _args['config'] = _config if uri not in _config['plugins'] : _data = {} _code = 404 else: pointer = _config['plugins'][uri] - _data = pointer () - _code = 200 + if _args : + _data = pointer (**_args) + else: + _data = pointer() + _code = 200 if _data else 500 return _data,_code @@ -137,14 +154,18 @@ def cms_page(): global _config _uri = os.sep.join([_config['layout']['root'],request.headers['uri']]) _id = request.headers['dom'] - _args = {'system':_config['system']} + _args = {'layout':_config['layout']} if 'plugins' in _config: _args['routes'] = _config['plugins'] - - _html = cms.components.html(_uri,_id,_args) + _system = copy.deepcopy(_config['system']) + + + _html = cms.components.html(_uri,_id,_args,_system) e = Environment(loader=BaseLoader()).from_string(_html) # _data = {} #cms.components.data(_config) - + if 'source' in _system : + del _system['source'] + _args['system'] = _system _html = e.render(**_args) return _html,200 @@ -187,32 +208,38 @@ if __name__ == '__main__' : _path = SYS_ARGS['config'] if 'config' in SYS_ARGS else 'config.json' if os.path.exists(_path): _config = json.loads((open (_path)).read()) - _root = _config['layout']['root'] - _config['layout']['menu'] = cms.components.menu(_root,_config) - if 'map' in _config['layout'] and 'order' in _config['layout'] and 'menu' in _config['layout']['order'] : - """ - We are insuring that the order of the menu items can be manually configured and have proper representation without quircks associated with folder name convention - """ - _map = _config['layout']['map'] - labels = [_name if _name not in _map else _map[_name] for _name in _config['layout']['order']['menu']] - labels = [_name for _name in labels if _name in _config['layout']['menu']] - _config['layout']['order']['menu'] = labels - - else: - _config['layout']['order']['menu'] = list(_config['layout']['menu'].keys()) - - # _config['data'] = cms.components.data(_config) + if 'theme' not in _config['system'] : + _config['system']['theme'] = 'magazine.css' # + # root can be either on disk or in the cloud ... + # root: "" reading from disk + # root: {uid,token,folder} + # + + _root = _config['layout']['root'] + _menu = cms.components.menu(_config) + if 'order' in _config['layout'] and 'menu' in _config['layout']['order']: + _sortedmenu = {} + for _name in _config['layout']['order']['menu'] : + _sortedmenu[_name] = _menu[_name] + _menu = _sortedmenu + _config['layout']['menu'] = _menu #cms.components.menu(_config) + # if 'data' in _config : + # _config['data'] = cms.components.data(_config['data']) + # + _map = cms.components.plugins(_config) + _config['plugins'] = _map # Let us load the plugins if any are available - if 'plugins' in _config : - _map = cms.components.plugins(_config) - if _map : - _config['plugins'] = _map + # if 'plugins' in _config : + # _map = cms.components.plugins(_config) + # if _map : + # _config['plugins'] = _map # # register the functions with Jinja2 - cms.components.context(_config) + # cms.components.context(_config) + _args = _config['system']['app'] _app.run(**_args) else: print (__doc__) - print () + print () diff --git a/static/css/default.css b/static/css/default.css index 576cb57..5208706 100644 --- a/static/css/default.css +++ b/static/css/default.css @@ -115,11 +115,12 @@ body { .main .content { padding:8px; - border-radius: 10px; + /* box-shadow: 0px 6px 10px rgba(0, 0, 0, 0.25); */ /* transition: all 0.2s; */ } +.main .content img {width:78%} .index { height:100%; diff --git a/static/img/logo.png b/static/img/logo.png index eb64b3a0c2684fd4497b564eb4421a45ac6036bc..c483238b444159d876238a324c4ebd154b48cec4 100644 GIT binary patch literal 19732 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 F{{p#?yI=qS literal 9947 zcmeHt2~bl@w{C|)aKt$xDjZQ!L4qPUFodH5Dk#o~0$~tP5s1uF5>S~zRFpx4fC$Ju zC^IAof&xO|pb*A@%tHuM5)zWV-{$=9zjdo#y{h-B?tOLtS2tD3?yO$D`dhuacduT( zLatoaU%zJO8UVoh3+K;W13&~RiU7$~$Yas-Cm(sN#-BHF0buQxl`jgseYXPuIdI|J zpEo?;G5fs2ZARkggAMnNU3`CkukMA{m*PS;@4p7c8XgPXt9y0(r4J#6_n{q6kFJVz zs17e^w#`3k5suDZzp5nJ;r@1OQCn4qByJjaW|EMXJDHkkUpA&(?&#s=@5A4nJD|U*jjFC6urQ9!#b@>gseq zUff@xCIkPdpC*}C6nw93OKTP_P zXEYVBt!NFIIRJd2M|9hT{;=?Cz9& zfz(crIbM8;-LOr6Cw!VinVHmVH6}H_SqAtAvUkjuc~2`oeY0jUb!kyPg;aNL$MlV9 zQE|W2eWZFpm-QBsDrXO_Rf%yIHs($3ERfm+qTd@ieuubR&M%@WN1NQK#L(c7u@vP6 zb0WC?Oh7pq$#N2=(|rh+7sjFK#;i_HBP?*O{bgTBKEjA09OMwG!Aw)2Ot5}SqjII-liezHDnGhtM=LM}l!cd_mFE4irmj1tgxZ36loOOLb-boA zr8)mWQrk;-N`P&GNijYqWs1?PEa7EK6drEjXVRrM%GsQFlpS>QTYT~@`+yLBYQi3e z0NKx?gPCgVzo;$t9X5j_?&0rt`@ngsu>Cw$9rm#zv#xQP6N=shi0eSa+7%hPvgT0% z#*xR*$os$neDk<{C)zaCT6SFO>b&RAi)Yo~i)*XvycR@H7_Jm_T{!p5Z9YZk&ac z#%i6pw3;uf&0d(F9(UUr>x{FNXQnE>9kv&fO$D7@9+`2BDQ$ikM$Nd$W3kv_Fs6JD zh-B@7bLdhVpgpG$XW)E4rK5PsIg+!k3&HZSCGF1Tc#qEE!ueQt=Q@n?lVp z``A9#SQWq5zMgJcyLOukoPM%6^#wDOU3gxm_wor?uanx+mmY7vAvWEHz}BeP18@uz zk~~LL^n63$mOdPW_RY%kL9f#G`MBH!Kat&|G}awpe)W5RANNty^KV28kWor-smf1% zE3?zVU0KO=y3?zV@BI-oQ1i8{5#wD+B=A^Pw=>u9f(I&!JM^s(FgJ#cNN8zLCLp51 zgr{*Dw*;MWj4?S5*E*xr-hfa#g&Gj`1C4Vb>^g`;`ZD(^N0*Smt9xcWR7XnS^@xU* z;tS9OqCrj@8bo`+-pC{il#PMB;&@aG#XdGF(r1^(it(S10Bs>yj+Ru zOYxJ~2w^q2_JZ+ONp@X%tc;j&9PgDpFR(9k&!<)Ah)e}W}spA;_~w14MrTE75!m+ZReFs=M}#iib*)%%#M?&riBrEfH=jYstju$vP1Kp?$A<0`m4hRw z@FPK;u17>9O{msr-_dcJs#|Yv>Uv6yZ}jY&$NHin==dk=wX|h|vBc zq(Bu8*XGc9WiZ1qk?IoB_6kjvhqrz<=-a$F8ewh8YTMElv#rj{0nWhN?8U5oB(3CB zpj~b^c%sW|?z|UnEKFJCUDOAWff)yOtJ19UjT_$@!zypZQ9DSpu_NRsom}#|nEkVc zI>e`mg-}`fY-CNKAVYCnrG$+eRnez*9vr!-slTC zSXnJuz*`pT8!Uk}nNztA?0hJR%TJ&7XWFH}N{74ErV8=ipO<05BaNZ6UZu9o2 zP|t?n<5yIDJ&PF7Sjw2_!04q!$f!?hLr3l08l^vedwJnlxOK4=4lW*y(RY|%S!+s@ zlwq-2$NuX3p4q>6tZ)KkaET_NL(HPn*9Mo~lFib`>3n^|SUkj`y)XPsf&!z=N^2hw zr~2d2ZSFm6W&pv{b8Zvf*Yh#?T5MsWlwXiX47dM!=7TYdBYcs)xe5B0&%q`)(gY)Z z0hEP9)bp&evk@&#>AEY6ncaV~Lo!F)bVn?##bZnzA+7CPK)qm;9p)e{DPIc45eS@J zmlT2W_dHSqD-0V$x;)RNjiC*3vV$3m0+TS!+oR4Y#e%#BxLd#qAy5nwK+@Q1aBaQc z+FUcTo3=m+H>+W!URy9|ds6e~x_F7VgTGQDS`rpAXX9O=TeT9)lYeh5MMAed(nJF& zZvmeEViu8Gx%*{_B=AlIa%|wo-3!LOL;wnWTD?Nj0o9L0{1O$wMxYY^cXwjo$ASOn zEZa5%a?dsRX;#O*_-V1#J;Zw|eA?cRZ+(qDv_Lo3)uSFtmI9_1 zU4j7c8K{cYkEd;TXE47!JB&&TfAAsH1U71VGxsAl-3d;$r3^w=JueTqkT zgj7Is+ZIdwlEsdb71(#XPW{E>vfpCuT=lb2q4!BG|7RR{y|P<7wx!iY|qlgSfZ_NYmu95Z{?pQ{Vq0;N6FAkZ33fXt%-o;-sEOE*_B@NHP}wSYYRUZ*2Ww>qJf)&EF~_qNK)y zbG*hTtMM+RN*HbSrV}oTRbo*a857AW!dc_wfLi#WKy2^_io&&NO*E zYxweI-0m!QmuA%|%_VK)g&1ao7MWF9rNZfI)pFY9^h`>Rp95P_N^|VDWC<{P05&Uqfqv@T!&n|F36F3ET>hi=FByFC1pR-=c&kk z&sI4;x!=D_OlRx$p5kW#W4NZ7wm7X?dpH;;%UxkmZ82Q8Ek_wt{RqcpU)9N-J_=AoPfqH1>?ap4Vv zWZ^0>TvWA&h`t~A$noH=y4R_J1TmeA1CeCOF$QY`ahuCbe^1pVe8_}se~&pN`BxIFx@O}kJXI)e+glTv$6#;HmA{WZ)Tj;#8QwtmRW9Jl+vyxayYr(os- zD&8-6AtUy}po#R9LU0k3@Q>Ue$_#3yn{7P^E*|rmwea%bDmFTtcox!bo}N=EOh0kc zA_UV?n9v!Nt-f8TR90#n(>evAqZmrxcZ-Va%sq@)0XT%2RgN{EyDwN6)*6wmTu9hW z4yROCShCx;wb7!u(YOmF_GZE)+-H9B9p3;Yl7x?Patx-FR*a_EpO(F`b=fe^;W`}o z9y8DAiV2xTC!G1BI&+P0|HqM>CAEoEqgb zM1@+qUDMq=4xM?pa$^YB7_WfrJ>!K9gD>$=^h3ss$CsJ1s)c#IY1OoCmm?R0G7(a8 zV)sJ8_*m0j_k@RfxSzVb?v@+4RU1J-+#RYq^j^7j_z&6bH^gNkv1r0o^jN6MG2&^y zbo-h}PHP>B*EH;*OudPrH7zX3XZeWEC23CGAU~OQ|XRV7Ay)x`l8iyT_ATD zbtO21;4_37-)xx3KIDItd8$mA|3vu?v`&9n;^yL~%UxkXK3q1umPmSvI5lR+iX1O3 zj+kBqyEHcnv#%EqE=i?e#*dXMT9`&oPcS=SmzbQ!GxB9?QQ|s(q?r>=@tu`xe?Din z(N5ds$?_bLwt-(hNu-e78fSXCmT6$PB|Md57zGY~{TW8n!?mP}Ri{O)aP!2S3u0WP zpRZ@@Vy9k@49A*hok|jRlJ>s-GbC@1~MHhqN-eHzl=APtqZ#BlW{0bqaev2sdIP!Zs=v5dwv9$!B(WvqE}@dk67!t0MXhib-jW(~oN0>` zfv%5HyzLfUE}KCYyb92+ZHZkzM#$g3FRE3tKx#2{sVN*B{81)B*-W^Ae!!1Ycuzi> zGdtd5q>KAYw~^((V>$eK=Z`x`jA$;#^(E0+smKEii|JUVnNKo3L<}9~`lk;s%_ZBk zA+^t?n14^wm|`x+4T#E%=m6KYVG04MyE-3p;y@5#f z@yy<)jQbVO74;mo2+f1XkQMFCw(-lzNrduV8B38A_=Ui!NdRUhl8n>b|!j z9d;2(x)POs*`r?>?PKZDURL3>dW)J-)2)VquG&9HRNv`AH>il`B+Orky6HNV*6+RDf}8PL z{yNy|=xmX1mneSHqqEu4O6k{H+f3%ySxTbU_JIOQ{8>cO`I$y1I38Kg(WbqTQrf!+UYP!EgWuy4+GwxBrUFXD%qfT0>IYqmG(=r_ z-gf7t2iGnIGpj4)z^#Ni+Dn6-GO{z3ZpzSRTxpDychH4jY_db3RBkBsD|%>-aEQtw z`GbSa!~I%=g62*=-0<2v5V_(H!wnnsuxI-j{ZUgXn7M#P)-tyLc`O~-R(u|>W}pXD zWu}sEg^>d1R{LGM1TO`QH~IEEmZvRD1QyVqmn}C8>Zf29czk|`V(naVU)u_8@_DMq zp962~HQBH_>Pl|5bXp8{D=C9ki@b8bVNZ;v#@P%`XnE-3CKn2XU$fe15j^SLPJuFv zaO%&o$-Lu_xcj1D+R3Dm9KzqQ$3U4niSXn+SYMZ6c+)cr7%5Hm1FSpUc z0;G331R6O8Q+vnulDhVCyl#epVC#FI=gHeo3ct>)Ty;tQaZUX+v3w!AoW2&ic5AoE zCgHo=?*#9wjk5D*noztxi0DeE6(SAAOW~OC!1HYYz?%CTrS6n-i{IEyCj=Ur!wZcrfPqd ztIg2@avQNKA1{*8FG!wkL=XPdDa0{c>Ta3rl^+c)H%5tBLEE z=-u9)L$~EWAI7ixr2r1w&9@G!2){qAqblJMCzZb(8PM?MdYi23h=%%4G%=qQ7Jz}A z94k&&J{~SmIjz1`c=S5u$kS$g&**Q=#>$76wkK-0j#sK3|qO9{2c>iwQVUZduxmvro|dbrGC3l{=gdY0>ZyCRF33h{%A8k1(! zfZ25Qj#`(Xoe5J&(6c^OAKYNv-kzrJu&!Nk57T!i_{>ruZ_0aZe*=TW7q-%Ka-!e$|>e;QGy_81$P`jJ_Vp zygd%Cx#Qfeq!a(KA&l7lGFbu1?Pp(qFtI-eCoa2mEZ;Fv<#ROy=Ux_!+mS;DRnN9j z84L2jR@xpGZD%lyE=&%YEV8`TrPRu|(X{tx1detke?m&z6fVCDhJ=Z-D3vg9Fa{*8 z6Y+bG1URZSSA#}5aPTeSF8ql4KPQj-gO8D&J#g!~>#uC1N2Nyjx3>$YufLikfQKnV zNQb-aQb^P>eXtTi`8!$8Mi(-$APa(;A zn-OLG=!`M?e7s{Fq`g?)_DQ~tN-OxKXWvGZ`n3<(K31rPTKa0O5Z(k06vrd_`ZVio zp34dq<5utwo=rdmv5gLR{U?z03)=!dNdgq2sN9N`#H#C7`_$^kg z^iS?%2rK@vh{g8*$*m)eu$G=&vG_l@{}yce4#cLK*gu=&$i}`_tDi!!RpnmI(ucLb zMU($r0kkmoNb~q7y+zhpwg1@p{O@CY`!|B9r|C638SG_DDU+K5dzHsRgH?l+BeEYP zlo;%caZ;kP?U0VDU`9q-YhdB-qU@yUAoA!K<57tAH+69yC({j?N1b>Riq zqfh0V^XCs%S+wiO&y&-)BH1pU=zoS(lSD+4-V~{SBUymzy3dn2Cy?u0Cj7e-xgP}s zn+r#?`lS4_d5;z)Rsqu+S^d7q4RLE`$)1%fQNJ*In;aXY{?1efU1}XDeLWgsCgm5x z|4IshSE?V_HZx|tfuT(oHgtvGU`PB?QLcoJobUM(jVsza#SIoW09 zB2pVcEK?ys3BC+UH*N%(hwO=I`5-pClcdEL6$7>pB1)hKmZ%p-S^b)umj4t1PWG%( z|1&Wp?Jew4v=#OWun2tgn^Pky*HlRDX?zP~_)o>b86O2W+dL1hLg?g>?6PAV(N*9M zua1=Wx=^t2;P_5zoAPtAKB*PFD7}@#j!zZWS&_%5Bk3R4IvVd}T{MGu$K#txgLeQ3 zPN{kd-^(}gn$DS2NPD+bP=_u*a^41Sk|e%(jC zpxw*iX(&sI`8m6~J6ivy>X||41EigMIsQOrO*d7D-RQ%DyVk8+CvaX~+bz3%1ti53 z6?P=z4+;Y4KJf1Lhec5RxsKCYmhm77T|{cr)=*Ptmsqiux$iQ%e`0@N41)>hLF@Ix zQP-5VrEdjX!F~lQwi;=I7Um;ODvJcjH9e8sE|^e7*`>(t1WJ}nv(p{s5WJ6LPVRKo zR?F|7jwE=3d_49RS<*Y0_w4m(e4QN|zqx@%lg zI0^?7lfV_r9Pb6Hk!`agk`9yGQg(;Q8rDUyqLMOGe-$LQ7C=y#(C4Hw+1V!z~E7Sz#wPBj|-RDcM} zfI_CuY+8;-0o{kJa&oape>-yoc0#g#8V#duNDtm0eeAVtk@!%y_5QTeX5f0(Cq3e` zM^6-Uw}%O3%8J#~Nc&3vnl}>kEB8Z1kHnHMgp%Yn2Xr5}YqAizl5r##!}`$Tm{}6I zV5as`jcotxj)$B3?JRay0XO5nO4e2VjxF{OHr=4y_GZdO7C=51bT6OFJ!A3Ye*g}! B{qO() diff --git a/static/img/logo.svg b/static/img/logo.svg index 06b19c8..b6db745 100644 --- a/static/img/logo.svg +++ b/static/img/logo.svg @@ -1 +1,4 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/static/js/menu.js b/static/js/menu.js index fd8c553..faa61a0 100644 --- a/static/js/menu.js +++ b/static/js/menu.js @@ -67,7 +67,6 @@ menu.apply_link =function(_args){ if (_args.url){ jx.modal.show(_args.url) }else{ - // _html = jx.dom.get.value(_args.text) // console.log(_html) // jx.modal.show(_html) diff --git a/templates/404.html b/templates/404.html index 0856321..e70ca45 100644 --- a/templates/404.html +++ b/templates/404.html @@ -56,7 +56,7 @@ Vanderbilt University Medical Center {%include "header.html" %}
-
+

404

diff --git a/templates/header.html b/templates/header.html index 94c1329..5958df1 100644 --- a/templates/header.html +++ b/templates/header.html @@ -1,5 +1,6 @@ {% if layout.header.logo == True %} + {% endif %}
{{layout.header.title}}
diff --git a/templates/index.html b/templates/index.html index 8769e8d..e1aef67 100644 --- a/templates/index.html +++ b/templates/index.html @@ -23,8 +23,9 @@ Vanderbilt University Medical Center - - + + + diff --git a/templates/menu.html b/templates/menu.html index 569f34d..e9dcfaa 100644 --- a/templates/menu.html +++ b/templates/menu.html @@ -15,7 +15,9 @@
{%endif%} - {{_item.text}}
+ {{_item.text}} + +
{%endfor%}
diff --git a/templates/pane.html b/templates/pane.html index f579d8b..37357a1 100644 --- a/templates/pane.html +++ b/templates/pane.html @@ -3,3 +3,4 @@ Hard code whatever you want here @TODO: Perhaps have code to add things here onload --> +