view_common.go 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. package login
  2. import (
  3. "fmt"
  4. "net/http"
  5. . "github.com/theplant/htmlgo"
  6. )
  7. var DefaultViewCommon = &ViewCommon{
  8. WrapperClass: "flex pt-16 flex-col max-w-md mx-auto",
  9. TitleClass: "leading-tight text-3xl mt-0 mb-6",
  10. LabelClass: "block mb-2 text-sm text-gray-600 dark:text-gray-200",
  11. InputClass: "block w-full px-4 py-2 mt-2 text-gray-700 placeholder-gray-400 bg-white border border-gray-200 rounded-md dark:placeholder-gray-600 dark:bg-gray-900 dark:text-gray-300 dark:border-gray-700 focus:border-blue-400 dark:focus:border-blue-400 focus:ring-blue-400 focus:outline-none focus:ring focus:ring-opacity-40",
  12. ButtonClass: "w-full px-6 py-3 tracking-wide text-white transition-colors duration-200 transform bg-blue-500 rounded-md hover:bg-blue-400 focus:outline-none focus:bg-blue-400 focus:ring focus:ring-blue-300 focus:ring-opacity-50",
  13. }
  14. type ViewCommon struct {
  15. WrapperClass string
  16. TitleClass string
  17. LabelClass string
  18. InputClass string
  19. ButtonClass string
  20. }
  21. func (vc *ViewCommon) Notice(vh *ViewHelper, msgr *Messages, w http.ResponseWriter, r *http.Request) HTMLComponent {
  22. var nn HTMLComponent
  23. if n := vh.GetNoticeFlash(w, r); n != nil && n.Message != "" {
  24. switch n.Level {
  25. case NoticeLevel_Info:
  26. nn = vc.InfoNotice(n.Message)
  27. case NoticeLevel_Warn:
  28. nn = vc.WarnNotice(n.Message)
  29. case NoticeLevel_Error:
  30. nn = vc.ErrNotice(n.Message)
  31. }
  32. }
  33. return Components(
  34. vc.ErrNotice(vh.GetFailFlashMessage(msgr, w, r)),
  35. vc.WarnNotice(vh.GetWarnFlashMessage(msgr, w, r)),
  36. vc.InfoNotice(vh.GetInfoFlashMessage(msgr, w, r)),
  37. nn,
  38. )
  39. }
  40. func (vc *ViewCommon) ErrNotice(msg string) HTMLComponent {
  41. if msg == "" {
  42. return nil
  43. }
  44. return Div().Class("bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative text-center").
  45. Role("alert").
  46. Children(
  47. Span(msg).Class("block sm:inline"),
  48. )
  49. }
  50. func (vc *ViewCommon) WarnNotice(msg string) HTMLComponent {
  51. if msg == "" {
  52. return nil
  53. }
  54. return Div().Class("bg-orange-100 border border-orange-400 text-orange-700 px-4 py-3 rounded relative text-center").
  55. Role("alert").
  56. Children(
  57. Span(msg).Class("block sm:inline"),
  58. )
  59. }
  60. func (vc *ViewCommon) InfoNotice(msg string) HTMLComponent {
  61. if msg == "" {
  62. return nil
  63. }
  64. return Div().Class("bg-blue-100 border border-blue-400 text-blue-700 px-4 py-3 rounded relative text-center").
  65. Role("alert").
  66. Children(
  67. Span(msg).Class("block sm:inline"),
  68. )
  69. }
  70. func (vc *ViewCommon) ErrorBody(msg string) HTMLComponent {
  71. return Div(
  72. Text(msg),
  73. )
  74. }
  75. func (vc *ViewCommon) PasswordInputWithRevealFunction(
  76. name string,
  77. placeholder string,
  78. id string,
  79. val string,
  80. ) HTMLComponent {
  81. return Div(
  82. Input(name).Placeholder(placeholder).Type("password").Class(vc.InputClass).Class("pr-10").Id(id).
  83. Value(val),
  84. Div(
  85. RawHTML(fmt.Sprintf(`<svg class="h-6 text-gray-700 block" id="icon-%s-showed" fill="none" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 576 512" width="1rem">
  86. <path fill="currentColor"
  87. d="M572.52 241.4C518.29 135.59 410.93 64 288 64S57.68 135.64 3.48 241.41a32.35 32.35 0 0 0 0 29.19C57.71 376.41 165.07 448 288 448s230.32-71.64 284.52-177.41a32.35 32.35 0 0 0 0-29.19zM288 400a144 144 0 1 1 144-144 143.93 143.93 0 0 1-144 144zm0-240a95.31 95.31 0 0 0-25.31 3.79 47.85 47.85 0 0 1-66.9 66.9A95.78 95.78 0 1 0 288 160z">
  88. </path>
  89. </svg>`, id)),
  90. RawHTML(fmt.Sprintf(`<svg class="h-6 text-gray-700 hidden" id="icon-%s-hidden" fill="none" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 640 512" width="1rem">
  91. <path fill="currentColor"
  92. d="M320 400c-75.85 0-137.25-58.71-142.9-133.11L72.2 185.82c-13.79 17.3-26.48 35.59-36.72 55.59a32.35 32.35 0 0 0 0 29.19C89.71 376.41 197.07 448 320 448c26.91 0 52.87-4 77.89-10.46L346 397.39a144.13 144.13 0 0 1-26 2.61zm313.82 58.1l-110.55-85.44a331.25 331.25 0 0 0 81.25-102.07 32.35 32.35 0 0 0 0-29.19C550.29 135.59 442.93 64 320 64a308.15 308.15 0 0 0-147.32 37.7L45.46 3.37A16 16 0 0 0 23 6.18L3.37 31.45A16 16 0 0 0 6.18 53.9l588.36 454.73a16 16 0 0 0 22.46-2.81l19.64-25.27a16 16 0 0 0-2.82-22.45zm-183.72-142l-39.3-30.38A94.75 94.75 0 0 0 416 256a94.76 94.76 0 0 0-121.31-92.21A47.65 47.65 0 0 1 304 192a46.64 46.64 0 0 1-1.54 10l-73.61-56.89A142.31 142.31 0 0 1 320 112a143.92 143.92 0 0 1 144 144c0 21.63-5.29 41.79-13.9 60.11z">
  93. </path>
  94. </svg>`, id)),
  95. ).Class("absolute right-0 inset-y-0 px-2 flex items-center text-sm cursor-pointer").Id(fmt.Sprintf("btn-reveal-%s", id)),
  96. Script(fmt.Sprintf(`
  97. (function(){
  98. var passElem = document.getElementById("%s");
  99. var revealBtn = document.getElementById("btn-reveal-%s");
  100. var showedIcon = document.getElementById("icon-%s-showed");
  101. var hiddenIcon = document.getElementById("icon-%s-hidden");
  102. revealBtn.onclick = function() {
  103. if (passElem.type === "password") {
  104. passElem.type = "text";
  105. showedIcon.classList.remove("block");
  106. showedIcon.classList.add("hidden");
  107. hiddenIcon.classList.remove("hidden");
  108. hiddenIcon.classList.add("block");
  109. } else {
  110. passElem.type = "password";
  111. hiddenIcon.classList.remove("block");
  112. hiddenIcon.classList.add("hidden");
  113. showedIcon.classList.remove("hidden");
  114. showedIcon.classList.add("block");
  115. }
  116. };
  117. })();`, id, id, id, id)),
  118. ).Class("relative")
  119. }
  120. func (vc *ViewCommon) PasswordStrengthMeter(inputID string) HTMLComponent {
  121. meterID := fmt.Sprintf("%s-strength-meter", inputID)
  122. return Div(
  123. Div(
  124. Div(
  125. Div().Class("password-strength-meter-section h-2 rounded-xl transition-colors bg-gray-200"),
  126. ).Class("w-1/5 px-1"),
  127. Div(
  128. Div().Class("password-strength-meter-section h-2 rounded-xl transition-colors bg-gray-200"),
  129. ).Class("w-1/5 px-1"),
  130. Div(
  131. Div().Class("password-strength-meter-section h-2 rounded-xl transition-colors bg-gray-200"),
  132. ).Class("w-1/5 px-1"),
  133. Div(
  134. Div().Class("password-strength-meter-section h-2 rounded-xl transition-colors bg-gray-200"),
  135. ).Class("w-1/5 px-1"),
  136. Div(
  137. Div().Class("password-strength-meter-section h-2 rounded-xl transition-colors bg-gray-200"),
  138. ).Class("w-1/5 px-1"),
  139. ).Class("flex mt-2 -mx-1 hidden").Id(meterID),
  140. Script(fmt.Sprintf(`
  141. (function(){
  142. var passElem = document.getElementById("%s");
  143. var meterElem = document.getElementById("%s");
  144. var meterSectionElems = document.getElementsByClassName("password-strength-meter-section");
  145. function checkStrength(val) {
  146. if (!val) {
  147. return 0;
  148. };
  149. return zxcvbn(val).score + 1;
  150. };
  151. function updateMeter() {
  152. if (passElem.value) {
  153. meterElem.classList.remove("hidden");
  154. } else {
  155. if (!meterElem.classList.contains("hidden")) {
  156. meterElem.classList.add("hidden");
  157. }
  158. }
  159. var s = checkStrength(passElem.value);
  160. for (var i = 0; i < meterSectionElems.length; i++) {
  161. var elem = meterSectionElems[i];
  162. if (i >= s) {
  163. elem.classList.add("bg-gray-200");
  164. elem.classList.remove("bg-red-400", "bg-yellow-400", "bg-green-500");
  165. } else if (s <= 2) {
  166. elem.classList.add("bg-red-400");
  167. elem.classList.remove("bg-gray-200", "bg-yellow-400", "bg-green-500");
  168. } else if (s <= 4) {
  169. elem.classList.add("bg-yellow-400");
  170. elem.classList.remove("bg-red-400", "bg-gray-200", "bg-green-500");
  171. } else {
  172. elem.classList.add("bg-green-500");
  173. elem.classList.remove("bg-red-400", "bg-yellow-400", "bg-gray-200");
  174. }
  175. }
  176. };
  177. updateMeter();
  178. passElem.oninput = function(e) {
  179. updateMeter();
  180. };
  181. })();`, inputID, meterID)),
  182. )
  183. }