html.py 29KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. import json
  2. import time
  3. from typing import List, Dict
  4. class HTML(object):
  5. def __init__(self, path='/index.html', title=None, styles='gitstats.css', version='v0.0.1') -> None:
  6. self.path = path
  7. self.title = title
  8. self.styles = styles
  9. self.version = version
  10. def create(self, content):
  11. f = open(self.path, 'w')
  12. head = self.getHeader(title=self.title)
  13. body = self.getBody(content, title=self.title)
  14. html = self.getHTML(head, body)
  15. f.write(html)
  16. f.close()
  17. def getHTML(self, head: str, body: str) -> str:
  18. return f'''<!DOCTYPE html><html>{head}{body}</html>'''
  19. def getHeader(self, title: str = None) -> str:
  20. title = title or f'GitStats - {self.title}'
  21. config = json.load(open('tailwind.json'))
  22. return '''
  23. <head>
  24. <meta charset="UTF-8">
  25. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  26. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  27. <title>%s</title>
  28. <link rel="stylesheet" href="%s" type="text/css" />
  29. <meta name="generator" content="GitStats %s" />
  30. <script src="https://cdn.tailwindcss.com"></script>
  31. <script> tailwind.config = %s </script>
  32. </head>
  33. ''' % (title, self.styles, self.version, json.dumps(config))
  34. def getBody(self, content: List[str], title: str) -> str:
  35. sidebar = self.getSideBar()
  36. topBar = self.getTopBar(title=title)
  37. content = '\n'.join(content)
  38. return f'''
  39. <body x-data="{{ page: 'main', 'loaded': false, 'darkMode': true, 'stickyMenu': false, 'sidebarToggle': false, 'scrollTop': false }}"
  40. x-init="darkMode = JSON.parse(localStorage.getItem('darkMode')); $watch('darkMode', value => localStorage.setItem('darkMode', JSON.stringify(value)))"
  41. :class="{{'dark text-bodydark bg-boxdark-2': darkMode === true}}">
  42. <!-- ===== Preloader Start ===== -->
  43. <div x-show="loaded" x-init="window.addEventListener('DOMContentLoaded', () => {{setTimeout(() => loaded = false, 500)}})" class="fixed left-0 top-0 z-999999 flex h-screen w-screen items-center justify-center bg-white dark:bg-black" style="display: none;">
  44. <div class="h-16 w-16 animate-spin rounded-full border-4 border-solid border-primary border-t-transparent"></div>
  45. </div>
  46. <!-- ===== Preloader End ===== -->
  47. <!-- ===== Page Wrapper Start ===== -->
  48. <div class="flex h-screen overflow-hidden">
  49. {sidebar}
  50. <!-- ===== Content Area Start ===== -->
  51. <div class="relative flex flex-1 flex-col overflow-y-auto overflow-x-hidden">
  52. {topBar}
  53. <!-- Main content -->
  54. <main>
  55. <div class="mx-auto max-w-screen-2xl p-4 md:p-6 2xl:p-10">
  56. {content}
  57. </div>
  58. </main>
  59. </div>
  60. <!-- ===== Content Area End ===== -->
  61. </div>
  62. <!-- ===== Page Wrapper End ===== -->
  63. <!-- <script src="//unpkg.com/alpinejs" defer></script> -->
  64. <!-- Alpine Plugins -->
  65. <script defer src="https://cdn.jsdelivr.net/npm/@alpinejs/persist@3.13.0/dist/cdn.min.js"></script>
  66. <!-- Alpine Core -->
  67. <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.13.0/dist/cdn.min.js"></script>
  68. <script ></script>
  69. <!-- ApexCharts -->
  70. <script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
  71. </body>
  72. '''
  73. def tilesItemStat(self, title: str = '', info: str = '', icon: str = None, stat: str = None) -> str:
  74. if icon is not None:
  75. icon = f'''
  76. <div class="flex items-center justify-center mb-6 md:mb-0">
  77. <span class="inline-flex justify-center items-center w-12 h-12 rounded-full text-emerald-500 bg-gray-50 dark:bg-slate-800 md:mr-6">
  78. <svg viewBox="0 0 24 24" width="24" height="24" class="inline-block">
  79. <path fill="currentColor" d="M15 15V17H18V20H20V17H23V15H20V12H18V15M14.97 11.61C14.85 10.28 13.59 8.97 12 9C10.3 9.03 9 10.3 9 12C9 13.7 10.3 14.94 12 15C12.38 15 12.77 14.92 13.14 14.77C13.41 13.67 13.86 12.63 14.97 11.61M13 16H7C7 14.9 6.11 14 5 14V10C6.11 10 7 9.11 7 8H17C17 9.11 17.9 10 19 10V10.06C19.67 10.06 20.34 10.18 21 10.4V6H3V18H13.32C13.1 17.33 13 16.66 13 16Z"></path>
  80. </svg>
  81. </span>
  82. </div>'''
  83. if stat is not None:
  84. stat = '''
  85. <div class="text-center md:text-right space-y-2">
  86. <p class="text-sm text-gray-500">Home Loan Account</p>
  87. <div>
  88. <div class="inline-flex items-center capitalize leading-none text-xs border rounded-full py-1 px-3 bg-emerald-500 border-emerald-500 text-white">
  89. <span>deposit</span>
  90. </div>
  91. </div>
  92. </div>'''
  93. return f'''
  94. <div class="rounded-sm border border-stroke bg-white px-7.5 py-6 shadow-default dark:border-strokedark dark:bg-boxdark">
  95. <div class="flex flex-col">
  96. <div class="flex-1 p-6">
  97. <div class="justify-between items-center block md:flex">
  98. <div class="flex items-center justify-center mb-6 md:mb-0">
  99. <div class="justify-start items-center block md:flex">
  100. {icon or ''}
  101. <div class="flex items-center justify-center">
  102. <div class="text-center text-black dark:text-white space-y-1 md:text-left md:mr-6">
  103. <h4 class="text-xl">{info}</h4>
  104. <p>{title}</p>
  105. </div>
  106. </div>
  107. </div>
  108. </div>
  109. <div class="flex items-center justify-center">
  110. {stat or ''}
  111. </div>
  112. </div>
  113. </div>
  114. </div>
  115. </div>'''
  116. def cardItemStat(self, count: str = '$3.456K', title: str = 'Total views', stat: str = None, arrow: str = 'up', icon=None) -> str:
  117. stat_html = ''
  118. if stat is not None:
  119. stat_html = f'''
  120. <span class="flex items-center gap-1 text-sm font-medium text-meta-3">
  121. {stat}
  122. <svg class="fill-meta-3" width="10" height="11" viewBox="0 0 10 11" fill="none" xmlns="http://www.w3.org/2000/svg">
  123. {arrow == 'up' and '<path d="M4.35716 2.47737L0.908974 5.82987L5.0443e-07 4.94612L5 0.0848689L10 4.94612L9.09103 5.82987L5.64284 2.47737L5.64284 10.0849L4.35716 10.0849L4.35716 2.47737Z" fill=""></path>'}
  124. {arrow == 'down' and '<path d="M5.64284 7.69237L9.09102 4.33987L10 5.22362L5 10.0849L-8.98488e-07 5.22362L0.908973 4.33987L4.35716 7.69237L4.35716 0.0848701L5.64284 0.0848704L5.64284 7.69237Z" fill=""></path>'}
  125. </svg>
  126. </span>'''
  127. if icon is None:
  128. icon = '''
  129. <svg class="fill-primary dark:fill-white" width="22" height="16" viewBox="0 0 22 16" fill="none" xmlns="http://www.w3.org/2000/svg">
  130. <path d="M11 15.1156C4.19376 15.1156 0.825012 8.61876 0.687512 8.34376C0.584387 8.13751 0.584387 7.86251 0.687512 7.65626C0.825012 7.38126 4.19376 0.918762 11 0.918762C17.8063 0.918762 21.175 7.38126 21.3125 7.65626C21.4156 7.86251 21.4156 8.13751 21.3125 8.34376C21.175 8.61876 17.8063 15.1156 11 15.1156ZM2.26876 8.00001C3.02501 9.27189 5.98126 13.5688 11 13.5688C16.0188 13.5688 18.975 9.27189 19.7313 8.00001C18.975 6.72814 16.0188 2.43126 11 2.43126C5.98126 2.43126 3.02501 6.72814 2.26876 8.00001Z" fill=""></path>
  131. <path d="M11 10.9219C9.38438 10.9219 8.07812 9.61562 8.07812 8C8.07812 6.38438 9.38438 5.07812 11 5.07812C12.6156 5.07812 13.9219 6.38438 13.9219 8C13.9219 9.61562 12.6156 10.9219 11 10.9219ZM11 6.625C10.2437 6.625 9.625 7.24375 9.625 8C9.625 8.75625 10.2437 9.375 11 9.375C11.7563 9.375 12.375 8.75625 12.375 8C12.375 7.24375 11.7563 6.625 11 6.625Z" fill=""></path>
  132. </svg>'''
  133. return f'''
  134. <div class="rounded-sm border border-stroke bg-white px-7.5 py-6 shadow-default dark:border-strokedark dark:bg-boxdark">
  135. <div class="flex h-11.5 w-11.5 items-center justify-center rounded-full bg-meta-2 dark:bg-meta-4">
  136. {icon}
  137. </div>
  138. <div class="mt-4 flex items-end justify-between">
  139. <div>
  140. <h4 class="text-title-md font-bold text-black dark:text-white">{count}</h4>
  141. <span class="text-sm font-medium">{title}</span>
  142. </div>
  143. {stat_html}
  144. </div>
  145. </div>'''
  146. def getSideBar(self) -> str:
  147. menu = ''.join([f'''
  148. <li>
  149. <a href="{href}"
  150. @click="selected = (selected === '{label}' ? '':'{label}')"
  151. :class="{{ 'bg-graydark dark:bg-meta-4': (selected === '{label}') }}"
  152. class="group relative flex items-center gap-2.5 rounded-sm px-4 py-2 font-medium text-bodydark1 duration-300 ease-in-out hover:bg-graydark dark:hover:bg-meta-4"
  153. role="button">
  154. <span aria-hidden="true">
  155. <svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
  156. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" />
  157. </svg>
  158. </span>
  159. <span class="ml-2 text-sm">{label}</span>
  160. </a>
  161. </li>
  162. ''' for (label, href) in [
  163. ("General", "index.html"),
  164. ("Activity", "activity.html"),
  165. ("Authors", "authors.html"),
  166. ("Files", "files.html"),
  167. ("Lines", "lines.html"),
  168. ("Tags", "tags.html")
  169. ]])
  170. return f'''
  171. <!-- Sidebar -->
  172. <aside :class="sidebarToggle ? 'translate-x-0' : '-translate-x-full'"
  173. @click.outside="sidebarToggle = false"
  174. class="absolute left-0 top-0 z-9999 flex h-screen w-72.5 flex-col overflow-y-hidden bg-black duration-300 ease-linear dark:bg-boxdark lg:static lg:translate-x-0 -translate-x-full">
  175. <!-- SIDEBAR HEADER -->
  176. <div class="flex items-center justify-between gap-2 px-6 py-5.5 lg:py-6.5">
  177. <a href="index.html">
  178. <img src="https://demo.tailadmin.com/src/images/logo/logo.svg" alt="Logo" />
  179. </a>
  180. <button
  181. class="block lg:hidden"
  182. @click.stop="sidebarToggle = !sidebarToggle"
  183. >
  184. <svg
  185. class="fill-current"
  186. width="20"
  187. height="18"
  188. viewBox="0 0 20 18"
  189. fill="none"
  190. xmlns="http://www.w3.org/2000/svg"
  191. >
  192. <path
  193. d="M19 8.175H2.98748L9.36248 1.6875C9.69998 1.35 9.69998 0.825 9.36248 0.4875C9.02498 0.15 8.49998 0.15 8.16248 0.4875L0.399976 8.3625C0.0624756 8.7 0.0624756 9.225 0.399976 9.5625L8.16248 17.4375C8.31248 17.5875 8.53748 17.7 8.76248 17.7C8.98748 17.7 9.17498 17.625 9.36248 17.475C9.69998 17.1375 9.69998 16.6125 9.36248 16.275L3.02498 9.8625H19C19.45 9.8625 19.825 9.4875 19.825 9.0375C19.825 8.55 19.45 8.175 19 8.175Z"
  194. fill=""
  195. />
  196. </svg>
  197. </button>
  198. </div>
  199. <!-- SIDEBAR HEADER -->
  200. <div class="no-scrollbar flex flex-col overflow-y-auto duration-300 ease-linear">
  201. <!-- Sidebar links -->
  202. <nav aria-label="Main" class="mt-5 px-4 py-4 lg:mt-9 lg:px-6" x-data="{{selected: $persist('General')}}">
  203. <div>
  204. <h3 class="mb-4 ml-4 text-sm font-medium text-bodydark2">MENU</h3>
  205. <ul class="mb-6 flex flex-col gap-1.5">
  206. {menu}
  207. </ul>
  208. </div>
  209. </nav>
  210. <!-- Sidebar footer -->
  211. <div class="flex-shrink-0 px-2 py-4 space-y-2"></div>
  212. </div>
  213. </aside>
  214. '''
  215. def getTopBar(self, title: str) -> str:
  216. return f'''
  217. <!-- Navbar -->
  218. <header class="sticky top-0 z-999 flex w-full bg-white drop-shadow-1 dark:bg-boxdark dark:drop-shadow-none">
  219. <div class="flex flex-grow items-center justify-between px-4 py-4 shadow-2 md:px-6 2xl:px-11">
  220. <div class="flex items-center gap-2 sm:gap-4 lg:hidden">
  221. <!-- Hamburger Toggle BTN -->
  222. <button
  223. class="z-99999 block rounded-sm border border-stroke bg-white p-1.5 shadow-sm dark:border-strokedark dark:bg-boxdark lg:hidden"
  224. @click.stop="sidebarToggle = !sidebarToggle">
  225. <span class="relative block h-5.5 w-5.5 cursor-pointer">
  226. <span class="du-block absolute right-0 h-full w-full">
  227. <span
  228. class="relative left-0 top-0 my-1 block h-0.5 w-0 rounded-sm bg-black delay-[0] duration-200 ease-in-out dark:bg-white"
  229. :class="{{ '!w-full delay-300': !sidebarToggle }}"
  230. ></span>
  231. <span
  232. class="relative left-0 top-0 my-1 block h-0.5 w-0 rounded-sm bg-black delay-150 duration-200 ease-in-out dark:bg-white"
  233. :class="{{ '!w-full delay-400': !sidebarToggle }}"
  234. ></span>
  235. <span
  236. class="relative left-0 top-0 my-1 block h-0.5 w-0 rounded-sm bg-black delay-200 duration-200 ease-in-out dark:bg-white"
  237. :class="{{ '!w-full delay-500': !sidebarToggle }}"
  238. ></span>
  239. </span>
  240. <span class="du-block absolute right-0 h-full w-full rotate-45">
  241. <span
  242. class="absolute left-2.5 top-0 block h-full w-0.5 rounded-sm bg-black delay-300 duration-200 ease-in-out dark:bg-white"
  243. :class="{{ '!h-0 delay-[0]': !sidebarToggle }}"
  244. ></span>
  245. <span
  246. class="delay-400 absolute left-0 top-2.5 block h-0.5 w-full rounded-sm bg-black duration-200 ease-in-out dark:bg-white"
  247. :class="{{ '!h-0 dealy-200': !sidebarToggle }}"
  248. ></span>
  249. </span>
  250. </span>
  251. </button>
  252. <!-- Hamburger Toggle BTN -->
  253. <a class="block flex-shrink-0 lg:hidden" href="index.html">
  254. <img src="https://demo.tailadmin.com/src/images/logo/logo-icon.svg" alt="Logo" />
  255. </a>
  256. </div>
  257. <div class="hidden sm:block">
  258. <a href="#" class="inline-block text-2xl font-bold tracking-wider uppercase">{title}</a>
  259. </div>
  260. <div class="flex items-center gap-3 2xsm:gap-7">
  261. <ul class="flex items-center gap-2 2xsm:gap-4">
  262. <li>
  263. <!-- Dark Mode Toggler -->
  264. <label
  265. :class="darkMode ? 'bg-primary' : 'bg-stroke'"
  266. class="relative m-0 block h-7.5 w-14 rounded-full"
  267. >
  268. <input
  269. type="checkbox"
  270. :value="darkMode"
  271. @change="darkMode = !darkMode"
  272. class="absolute top-0 z-50 m-0 h-full w-full cursor-pointer opacity-0"
  273. />
  274. <span
  275. :class="darkMode && '!right-1 !translate-x-full'"
  276. class="absolute left-1 top-1/2 flex h-6 w-6 -translate-y-1/2 translate-x-0 items-center justify-center rounded-full bg-white shadow-switcher duration-75 ease-linear"
  277. >
  278. <span class="dark:hidden">
  279. <svg
  280. width="16"
  281. height="16"
  282. viewBox="0 0 16 16"
  283. fill="none"
  284. xmlns="http://www.w3.org/2000/svg"
  285. >
  286. <path
  287. d="M7.99992 12.6666C10.5772 12.6666 12.6666 10.5772 12.6666 7.99992C12.6666 5.42259 10.5772 3.33325 7.99992 3.33325C5.42259 3.33325 3.33325 5.42259 3.33325 7.99992C3.33325 10.5772 5.42259 12.6666 7.99992 12.6666Z"
  288. fill="#969AA1"
  289. />
  290. <path
  291. d="M8.00008 15.3067C7.63341 15.3067 7.33342 15.0334 7.33342 14.6667V14.6134C7.33342 14.2467 7.63341 13.9467 8.00008 13.9467C8.36675 13.9467 8.66675 14.2467 8.66675 14.6134C8.66675 14.9801 8.36675 15.3067 8.00008 15.3067ZM12.7601 13.4267C12.5867 13.4267 12.4201 13.3601 12.2867 13.2334L12.2001 13.1467C11.9401 12.8867 11.9401 12.4667 12.2001 12.2067C12.4601 11.9467 12.8801 11.9467 13.1401 12.2067L13.2267 12.2934C13.4867 12.5534 13.4867 12.9734 13.2267 13.2334C13.1001 13.3601 12.9334 13.4267 12.7601 13.4267ZM3.24008 13.4267C3.06675 13.4267 2.90008 13.3601 2.76675 13.2334C2.50675 12.9734 2.50675 12.5534 2.76675 12.2934L2.85342 12.2067C3.11342 11.9467 3.53341 11.9467 3.79341 12.2067C4.05341 12.4667 4.05341 12.8867 3.79341 13.1467L3.70675 13.2334C3.58008 13.3601 3.40675 13.4267 3.24008 13.4267ZM14.6667 8.66675H14.6134C14.2467 8.66675 13.9467 8.36675 13.9467 8.00008C13.9467 7.63341 14.2467 7.33342 14.6134 7.33342C14.9801 7.33342 15.3067 7.63341 15.3067 8.00008C15.3067 8.36675 15.0334 8.66675 14.6667 8.66675ZM1.38675 8.66675H1.33341C0.966748 8.66675 0.666748 8.36675 0.666748 8.00008C0.666748 7.63341 0.966748 7.33342 1.33341 7.33342C1.70008 7.33342 2.02675 7.63341 2.02675 8.00008C2.02675 8.36675 1.75341 8.66675 1.38675 8.66675ZM12.6734 3.99341C12.5001 3.99341 12.3334 3.92675 12.2001 3.80008C11.9401 3.54008 11.9401 3.12008 12.2001 2.86008L12.2867 2.77341C12.5467 2.51341 12.9667 2.51341 13.2267 2.77341C13.4867 3.03341 13.4867 3.45341 13.2267 3.71341L13.1401 3.80008C13.0134 3.92675 12.8467 3.99341 12.6734 3.99341ZM3.32675 3.99341C3.15341 3.99341 2.98675 3.92675 2.85342 3.80008L2.76675 3.70675C2.50675 3.44675 2.50675 3.02675 2.76675 2.76675C3.02675 2.50675 3.44675 2.50675 3.70675 2.76675L3.79341 2.85342C4.05341 3.11342 4.05341 3.53341 3.79341 3.79341C3.66675 3.92675 3.49341 3.99341 3.32675 3.99341ZM8.00008 2.02675C7.63341 2.02675 7.33342 1.75341 7.33342 1.38675V1.33341C7.33342 0.966748 7.63341 0.666748 8.00008 0.666748C8.36675 0.666748 8.66675 0.966748 8.66675 1.33341C8.66675 1.70008 8.36675 2.02675 8.00008 2.02675Z"
  292. fill="#969AA1"
  293. />
  294. </svg>
  295. </span>
  296. <span class="hidden dark:inline-block">
  297. <svg
  298. width="16"
  299. height="16"
  300. viewBox="0 0 16 16"
  301. fill="none"
  302. xmlns="http://www.w3.org/2000/svg"
  303. >
  304. <path
  305. d="M14.3533 10.62C14.2466 10.44 13.9466 10.16 13.1999 10.2933C12.7866 10.3667 12.3666 10.4 11.9466 10.38C10.3933 10.3133 8.98659 9.6 8.00659 8.5C7.13993 7.53333 6.60659 6.27333 6.59993 4.91333C6.59993 4.15333 6.74659 3.42 7.04659 2.72666C7.33993 2.05333 7.13326 1.7 6.98659 1.55333C6.83326 1.4 6.47326 1.18666 5.76659 1.48C3.03993 2.62666 1.35326 5.36 1.55326 8.28666C1.75326 11.04 3.68659 13.3933 6.24659 14.28C6.85993 14.4933 7.50659 14.62 8.17326 14.6467C8.27993 14.6533 8.38659 14.66 8.49326 14.66C10.7266 14.66 12.8199 13.6067 14.1399 11.8133C14.5866 11.1933 14.4666 10.8 14.3533 10.62Z"
  306. fill="#969AA1"
  307. />
  308. </svg>
  309. </span>
  310. </span>
  311. </label>
  312. <!-- Dark Mode Toggler -->
  313. </li>
  314. </ul>
  315. <!-- User Area -->
  316. <div class="relative" x-data="{{ dropdownOpen: false }}" @click.outside="dropdownOpen = false">
  317. <a class="flex items-center gap-4" href="#" @click.prevent="dropdownOpen = ! dropdownOpen">
  318. <span class="hidden text-right lg:block">
  319. <span class="block text-sm font-medium text-black dark:text-white">@christhoval</span>
  320. <span class="block text-xs font-medium">Tech Lead</span>
  321. </span>
  322. <span class="h-12 w-12 rounded-full">
  323. <img src="https://demo.tailadmin.com/src/images/user/user-01.png" alt="User">
  324. </span>
  325. <svg :class="dropdownOpen &amp;&amp; 'rotate-180'" class="hidden fill-current sm:block" width="12" height="8" viewBox="0 0 12 8" fill="none" xmlns="http://www.w3.org/2000/svg">
  326. <path fill-rule="evenodd" clip-rule="evenodd" d="M0.410765 0.910734C0.736202 0.585297 1.26384 0.585297 1.58928 0.910734L6.00002 5.32148L10.4108 0.910734C10.7362 0.585297 11.2638 0.585297 11.5893 0.910734C11.9147 1.23617 11.9147 1.76381 11.5893 2.08924L6.58928 7.08924C6.26384 7.41468 5.7362 7.41468 5.41077 7.08924L0.410765 2.08924C0.0853277 1.76381 0.0853277 1.23617 0.410765 0.910734Z" fill=""></path>
  327. </svg>
  328. </a>
  329. <!-- Dropdown Start -->
  330. <div x-show="dropdownOpen" class="absolute right-0 mt-5 flex w-62.5 flex-col rounded-sm border border-stroke bg-white shadow-default dark:border-strokedark dark:bg-boxdark" style="display: none;">
  331. <ul class="flex flex-col gap-5 border-b border-stroke px-6 py-7.5 dark:border-strokedark">
  332. <li>
  333. <a href="profile.html" class="flex items-center gap-3.5 text-sm font-medium duration-300 ease-in-out hover:text-primary lg:text-base">
  334. <svg class="fill-current" width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
  335. <path d="M11 9.62499C8.42188 9.62499 6.35938 7.59687 6.35938 5.12187C6.35938 2.64687 8.42188 0.618744 11 0.618744C13.5781 0.618744 15.6406 2.64687 15.6406 5.12187C15.6406 7.59687 13.5781 9.62499 11 9.62499ZM11 2.16562C9.28125 2.16562 7.90625 3.50624 7.90625 5.12187C7.90625 6.73749 9.28125 8.07812 11 8.07812C12.7188 8.07812 14.0938 6.73749 14.0938 5.12187C14.0938 3.50624 12.7188 2.16562 11 2.16562Z" fill=""></path>
  336. <path d="M17.7719 21.4156H4.2281C3.5406 21.4156 2.9906 20.8656 2.9906 20.1781V17.0844C2.9906 13.7156 5.7406 10.9656 9.10935 10.9656H12.925C16.2937 10.9656 19.0437 13.7156 19.0437 17.0844V20.1781C19.0094 20.8312 18.4594 21.4156 17.7719 21.4156ZM4.53748 19.8687H17.4969V17.0844C17.4969 14.575 15.4344 12.5125 12.925 12.5125H9.07498C6.5656 12.5125 4.5031 14.575 4.5031 17.0844V19.8687H4.53748Z" fill=""></path>
  337. </svg>
  338. My Profile
  339. </a>
  340. </li>
  341. <li>
  342. <a href="messages.html" class="flex items-center gap-3.5 text-sm font-medium duration-300 ease-in-out hover:text-primary lg:text-base">
  343. <svg class="fill-current" width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
  344. <path d="M17.6687 1.44374C17.1187 0.893744 16.4312 0.618744 15.675 0.618744H7.42498C6.25623 0.618744 5.25935 1.58124 5.25935 2.78437V4.12499H4.29685C3.88435 4.12499 3.50623 4.46874 3.50623 4.91562C3.50623 5.36249 3.84998 5.70624 4.29685 5.70624H5.25935V10.2781H4.29685C3.88435 10.2781 3.50623 10.6219 3.50623 11.0687C3.50623 11.4812 3.84998 11.8594 4.29685 11.8594H5.25935V16.4312H4.29685C3.88435 16.4312 3.50623 16.775 3.50623 17.2219C3.50623 17.6687 3.84998 18.0125 4.29685 18.0125H5.25935V19.25C5.25935 20.4187 6.22185 21.4156 7.42498 21.4156H15.675C17.2218 21.4156 18.4937 20.1437 18.5281 18.5969V3.47187C18.4937 2.68124 18.2187 1.95937 17.6687 1.44374ZM16.9469 18.5625C16.9469 19.2844 16.3625 19.8344 15.6406 19.8344H7.3906C7.04685 19.8344 6.77185 19.5594 6.77185 19.2156V17.875H8.6281C9.0406 17.875 9.41873 17.5312 9.41873 17.0844C9.41873 16.6375 9.07498 16.2937 8.6281 16.2937H6.77185V11.7906H8.6281C9.0406 11.7906 9.41873 11.4469 9.41873 11C9.41873 10.5875 9.07498 10.2094 8.6281 10.2094H6.77185V5.63749H8.6281C9.0406 5.63749 9.41873 5.29374 9.41873 4.84687C9.41873 4.39999 9.07498 4.05624 8.6281 4.05624H6.77185V2.74999C6.77185 2.40624 7.04685 2.13124 7.3906 2.13124H15.6406C15.9844 2.13124 16.2937 2.26874 16.5687 2.50937C16.8094 2.74999 16.9469 3.09374 16.9469 3.43749V18.5625Z" fill=""></path>
  345. </svg>
  346. My Contacts
  347. </a>
  348. </li>
  349. <li>
  350. <a href="settings.html" class="flex items-center gap-3.5 text-sm font-medium duration-300 ease-in-out hover:text-primary lg:text-base">
  351. <svg class="fill-current" width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
  352. <path d="M20.8656 8.86874C20.5219 8.49062 20.0406 8.28437 19.525 8.28437H19.4219C19.25 8.28437 19.1125 8.18124 19.0781 8.04374C19.0437 7.90624 18.975 7.80312 18.9406 7.66562C18.8719 7.52812 18.9406 7.39062 19.0437 7.28749L19.1125 7.21874C19.4906 6.87499 19.6969 6.39374 19.6969 5.87812C19.6969 5.36249 19.525 4.88124 19.1469 4.50312L17.8062 3.12812C17.0844 2.37187 15.8469 2.33749 15.0906 3.09374L14.9875 3.16249C14.8844 3.26562 14.7125 3.29999 14.5406 3.23124C14.4031 3.16249 14.2656 3.09374 14.0937 3.05937C13.9219 2.99062 13.8187 2.85312 13.8187 2.71562V2.54374C13.8187 1.47812 12.9594 0.618744 11.8937 0.618744H9.96875C9.45312 0.618744 8.97187 0.824994 8.62812 1.16874C8.25 1.54687 8.07812 2.02812 8.07812 2.50937V2.64687C8.07812 2.78437 7.975 2.92187 7.8375 2.99062C7.76875 3.02499 7.73437 3.02499 7.66562 3.05937C7.52812 3.12812 7.35625 3.09374 7.25312 2.99062L7.18437 2.88749C6.84062 2.50937 6.35937 2.30312 5.84375 2.30312C5.32812 2.30312 4.84687 2.47499 4.46875 2.85312L3.09375 4.19374C2.3375 4.91562 2.30312 6.15312 3.05937 6.90937L3.12812 7.01249C3.23125 7.11562 3.26562 7.28749 3.19687 7.39062C3.12812 7.52812 3.09375 7.63124 3.025 7.76874C2.95625 7.90624 2.85312 7.97499 2.68125 7.97499H2.57812C2.0625 7.97499 1.58125 8.14687 1.20312 8.52499C0.824996 8.86874 0.618746 9.34999 0.618746 9.86562L0.584371 11.7906C0.549996 12.8562 1.40937 13.7156 2.475 13.75H2.57812C2.75 13.75 2.8875 13.8531 2.92187 13.9906C2.99062 14.0937 3.05937 14.1969 3.09375 14.3344C3.12812 14.4719 3.09375 14.6094 2.99062 14.7125L2.92187 14.7812C2.54375 15.125 2.3375 15.6062 2.3375 16.1219C2.3375 16.6375 2.50937 17.1187 2.8875 17.4969L4.22812 18.8719C4.95 19.6281 6.1875 19.6625 6.94375 18.9062L7.04687 18.8375C7.15 18.7344 7.32187 18.7 7.49375 18.7687C7.63125 18.8375 7.76875 18.9062 7.94062 18.9406C8.1125 19.0094 8.21562 19.1469 8.21562 19.2844V19.4219C8.21562 20.4875 9.075 21.3469 10.1406 21.3469H12.0656C13.1312 21.3469 13.9906 20.4875 13.9906 19.4219V19.2844C13.9906 19.1469 14.0937 19.0094 14.2312 18.9406C14.3 18.9062 14.3344 18.9062 14.4031 18.8719C14.575 18.8031 14.7125 18.8375 14.8156 18.9406L14.8844 19.0437C15.2281 19.4219 15.7094 19.6281 16.225 19.6281C16.7406 19.6281 17.2219 19.4562 17.6 19.0781L18.975 17.7375C19.7312 17.0156 19.7656 15.7781 19.0094 15.0219L18.9406 14.9187C18.8375 14.8156 18.8031 14.6437 18.8719 14.5406C18.9406 14.4031 18.975 14.3 19.0437 14.1625C19.1125 14.025 19.25 13.9562 19.3875 13.9562H19.4906H19.525C20.5562 13.9562 21.4156 13.1312 21.45 12.0656L21.4844 10.1406C21.4156 9.72812 21.2094 9.21249 20.8656 8.86874ZM19.8344 12.1C19.8344 12.3062 19.6625 12.4781 19.4562 12.4781H19.3531H19.3187C18.5281 12.4781 17.8062 12.9594 17.5312 13.6469C17.4969 13.75 17.4281 13.8531 17.3937 13.9562C17.0844 14.6437 17.2219 15.5031 17.7719 16.0531L17.8406 16.1562C17.9781 16.2937 17.9781 16.5344 17.8406 16.6719L16.4656 18.0125C16.3625 18.1156 16.2594 18.1156 16.1906 18.1156C16.1219 18.1156 16.0187 18.1156 15.9156 18.0125L15.8469 17.9094C15.2969 17.325 14.4719 17.1531 13.7156 17.4969L13.5781 17.5656C12.8219 17.875 12.3406 18.5625 12.3406 19.3531V19.4906C12.3406 19.6969 12.1687 19.8687 11.9625 19.8687H10.0375C9.83125 19.8687 9.65937 19.6969 9.65937 19.4906V19.3531C9.65937 18.5625 9.17812 17.8406 8.42187 17.5656C8.31875 17.5312 8.18125 17.4625 8.07812 17.4281C7.80312 17.2906 7.52812 17.2562 7.25312 17.2562C6.77187 17.2562 6.29062 17.4281 5.9125 17.8062L5.84375 17.8406C5.70625 17.9781 5.46562 17.9781 5.32812 17.8406L3.9875 16.4656C3.88437 16.3625 3.88437 16.2594 3.88437 16.1906C3.88437 16.1219 3.88437 16.0187 3.9875 15.9156L4.05625 15.8469C4.64062 15.2969 4.8125 14.4375 4.50312 13.75C4.46875 13.6469 4.43437 13.5437 4.36562 13.4406C4.09062 12.7187 3.40312 12.2031 2.6125 12.2031H2.50937C2.30312 12.2031 2.13125 12.0312 2.13125 11.825L2.16562 9.89999C2.16562 9.76249 2.23437 9.69374 2.26875 9.62499C2.30312 9.59062 2.40625 9.52187 2.54375 9.52187H2.64687C3.4375 9.55624 4.15937 9.07499 4.46875 8.35312C4.50312 8.24999 4.57187 8.14687 4.60625 8.04374C4.91562 7.35624 4.77812 6.49687 4.22812 5.94687L4.15937 5.84374C4.02187 5.70624 4.02187 5.46562 4.15937 5.32812L5.53437 3.98749C5.6375 3.88437 5.74062 3.88437 5.80937 3.88437C5.87812 3.88437 5.98125 3.88437 6.08437 3.98749L6.15312 4.09062C6.70312 4.67499 7.52812 4.84687 8.28437 4.53749L8.42187 4.46874C9.17812 4.15937 9.65937 3.47187 9.65937 2.68124V2.54374C9.65937 2.40624 9.72812 2.33749 9.7625 2.26874C9.79687 2.19999 9.9 2.16562 10.0375 2.16562H11.9625C12.1687 2.16562 12.3406 2.33749 12.3406 2.54374V2.68124C12.3406 3.47187 12.8219 4.19374 13.5781 4.46874C13.6812 4.50312 13.8187 4.57187 13.9219 4.60624C14.6437 4.94999 15.5031 4.81249 16.0875 4.26249L16.1906 4.19374C16.3281 4.05624 16.5687 4.05624 16.7062 4.19374L18.0469 5.56874C18.15 5.67187 18.15 5.77499 18.15 5.84374C18.15 5.91249 18.1156 6.01562 18.0469 6.11874L17.9781 6.18749C17.3594 6.70312 17.1875 7.56249 17.4625 8.24999C17.4969 8.35312 17.5312 8.45624 17.6 8.55937C17.875 9.28124 18.5625 9.79687 19.3531 9.79687H19.4562C19.5937 9.79687 19.6625 9.86562 19.7312 9.89999C19.8 9.93437 19.8344 10.0375 19.8344 10.175V12.1Z" fill=""></path>
  353. <path d="M11 6.32498C8.42189 6.32498 6.32501 8.42186 6.32501 11C6.32501 13.5781 8.42189 15.675 11 15.675C13.5781 15.675 15.675 13.5781 15.675 11C15.675 8.42186 13.5781 6.32498 11 6.32498ZM11 14.1281C9.28126 14.1281 7.87189 12.7187 7.87189 11C7.87189 9.28123 9.28126 7.87186 11 7.87186C12.7188 7.87186 14.1281 9.28123 14.1281 11C14.1281 12.7187 12.7188 14.1281 11 14.1281Z" fill=""></path>
  354. </svg>
  355. Account Settings
  356. </a>
  357. </li>
  358. </ul>
  359. <button class="flex items-center gap-3.5 px-6 py-4 text-sm font-medium duration-300 ease-in-out hover:text-primary lg:text-base">
  360. <svg class="fill-current" width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
  361. <path d="M15.5375 0.618744H11.6531C10.7594 0.618744 10.0031 1.37499 10.0031 2.26874V4.64062C10.0031 5.05312 10.3469 5.39687 10.7594 5.39687C11.1719 5.39687 11.55 5.05312 11.55 4.64062V2.23437C11.55 2.16562 11.5844 2.13124 11.6531 2.13124H15.5375C16.3625 2.13124 17.0156 2.78437 17.0156 3.60937V18.3562C17.0156 19.1812 16.3625 19.8344 15.5375 19.8344H11.6531C11.5844 19.8344 11.55 19.8 11.55 19.7312V17.3594C11.55 16.9469 11.2062 16.6031 10.7594 16.6031C10.3125 16.6031 10.0031 16.9469 10.0031 17.3594V19.7312C10.0031 20.625 10.7594 21.3812 11.6531 21.3812H15.5375C17.2219 21.3812 18.5625 20.0062 18.5625 18.3562V3.64374C18.5625 1.95937 17.1875 0.618744 15.5375 0.618744Z" fill=""></path>
  362. <path d="M6.05001 11.7563H12.2031C12.6156 11.7563 12.9594 11.4125 12.9594 11C12.9594 10.5875 12.6156 10.2438 12.2031 10.2438H6.08439L8.21564 8.07813C8.52501 7.76875 8.52501 7.2875 8.21564 6.97812C7.90626 6.66875 7.42501 6.66875 7.11564 6.97812L3.67814 10.4844C3.36876 10.7938 3.36876 11.275 3.67814 11.5844L7.11564 15.0906C7.25314 15.2281 7.45939 15.3312 7.66564 15.3312C7.87189 15.3312 8.04376 15.2625 8.21564 15.125C8.52501 14.8156 8.52501 14.3344 8.21564 14.025L6.05001 11.7563Z" fill=""></path>
  363. </svg>
  364. Log Out
  365. </button>
  366. </div>
  367. <!-- Dropdown End -->
  368. </div>
  369. </div>
  370. <!-- User Area -->
  371. </div>
  372. </header>'''
  373. def addChart(self, config: Dict, name: str = None, title: str = 'Chart', className: str=None):
  374. if name is None:
  375. name = f'chart_{int(time.time())}'
  376. return self.addCard([f'<div id="{name}" class="-ml-5"></div>'], title=title, className=className, extra=f'''
  377. <script>
  378. document.addEventListener("DOMContentLoaded", () => {{
  379. const chartSelector = document.querySelectorAll("#{name}");
  380. if (chartSelector.length) {{
  381. const {name} = new ApexCharts(
  382. document.querySelector("#{name}"),
  383. {json.dumps(config)}
  384. );
  385. {name}.render();
  386. }}
  387. }})
  388. </script>''')
  389. def addCard(self, content, title: str = 'Chart', className: str=None, extra: str=None):
  390. content = '\n'.join(content)
  391. return f'''
  392. <div
  393. class="col-span-12 rounded-sm border border-stroke bg-white px-5 pb-5 pt-7.5 shadow-default dark:border-strokedark dark:bg-boxdark sm:px-7.5 {className or ""}">
  394. <div>
  395. <h3 class="text-xl font-bold text-black dark:text-white">
  396. {title}
  397. </h3>
  398. </div>
  399. <div>{content}</div>
  400. {extra or ""}
  401. </div>'''