view_common.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. package login
  2. import (
  3. "fmt"
  4. . "github.com/theplant/htmlgo"
  5. )
  6. var DefaultViewCommon = &ViewCommon{
  7. WrapperClass: "flex pt-16 flex-col max-w-md mx-auto",
  8. TitleClass: "leading-tight text-3xl mt-0 mb-6",
  9. LabelClass: "block mb-2 text-sm text-gray-600 dark:text-gray-200",
  10. 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",
  11. 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",
  12. }
  13. type ViewCommon struct {
  14. WrapperClass string
  15. TitleClass string
  16. LabelClass string
  17. InputClass string
  18. ButtonClass string
  19. }
  20. func (vc *ViewCommon) ErrNotice(msg string) HTMLComponent {
  21. if msg == "" {
  22. return nil
  23. }
  24. return Div().Class("bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative text-center").
  25. Role("alert").
  26. Children(
  27. Span(msg).Class("block sm:inline"),
  28. )
  29. }
  30. func (vc *ViewCommon) WarnNotice(msg string) HTMLComponent {
  31. if msg == "" {
  32. return nil
  33. }
  34. return Div().Class("bg-orange-100 border border-orange-400 text-orange-700 px-4 py-3 rounded relative text-center").
  35. Role("alert").
  36. Children(
  37. Span(msg).Class("block sm:inline"),
  38. )
  39. }
  40. func (vc *ViewCommon) InfoNotice(msg string) HTMLComponent {
  41. if msg == "" {
  42. return nil
  43. }
  44. return Div().Class("bg-blue-100 border border-blue-400 text-blue-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) ErrorBody(msg string) HTMLComponent {
  51. return Div(
  52. Text(msg),
  53. )
  54. }
  55. func (vc *ViewCommon) PasswordInputWithRevealFunction(
  56. name string,
  57. placeholder string,
  58. id string,
  59. val string,
  60. ) HTMLComponent {
  61. return Div(
  62. Input(name).Placeholder(placeholder).Type("password").Class(vc.InputClass).Class("pr-10").Id(id).
  63. Value(val),
  64. Div(
  65. 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">
  66. <path fill="currentColor"
  67. 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">
  68. </path>
  69. </svg>`, id)),
  70. 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">
  71. <path fill="currentColor"
  72. 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">
  73. </path>
  74. </svg>`, id)),
  75. ).Class("absolute right-0 inset-y-0 px-2 flex items-center text-sm cursor-pointer").Id(fmt.Sprintf("btn-reveal-%s", id)),
  76. Script(fmt.Sprintf(`
  77. (function(){
  78. var passElem = document.getElementById("%s");
  79. var revealBtn = document.getElementById("btn-reveal-%s");
  80. var showedIcon = document.getElementById("icon-%s-showed");
  81. var hiddenIcon = document.getElementById("icon-%s-hidden");
  82. revealBtn.onclick = function() {
  83. if (passElem.type === "password") {
  84. passElem.type = "text";
  85. showedIcon.classList.remove("block");
  86. showedIcon.classList.add("hidden");
  87. hiddenIcon.classList.remove("hidden");
  88. hiddenIcon.classList.add("block");
  89. } else {
  90. passElem.type = "password";
  91. hiddenIcon.classList.remove("block");
  92. hiddenIcon.classList.add("hidden");
  93. showedIcon.classList.remove("hidden");
  94. showedIcon.classList.add("block");
  95. }
  96. };
  97. })();`, id, id, id, id)),
  98. ).Class("relative")
  99. }
  100. func (vc *ViewCommon) PasswordStrengthMeter(inputID string) HTMLComponent {
  101. meterID := fmt.Sprintf("%s-strength-meter", inputID)
  102. return Div(
  103. Div(
  104. Div(
  105. Div().Class("password-strength-meter-section h-2 rounded-xl transition-colors bg-gray-200"),
  106. ).Class("w-1/5 px-1"),
  107. Div(
  108. Div().Class("password-strength-meter-section h-2 rounded-xl transition-colors bg-gray-200"),
  109. ).Class("w-1/5 px-1"),
  110. Div(
  111. Div().Class("password-strength-meter-section h-2 rounded-xl transition-colors bg-gray-200"),
  112. ).Class("w-1/5 px-1"),
  113. Div(
  114. Div().Class("password-strength-meter-section h-2 rounded-xl transition-colors bg-gray-200"),
  115. ).Class("w-1/5 px-1"),
  116. Div(
  117. Div().Class("password-strength-meter-section h-2 rounded-xl transition-colors bg-gray-200"),
  118. ).Class("w-1/5 px-1"),
  119. ).Class("flex mt-2 -mx-1 hidden").Id(meterID),
  120. Script(fmt.Sprintf(`
  121. (function(){
  122. var passElem = document.getElementById("%s");
  123. var meterElem = document.getElementById("%s");
  124. var meterSectionElems = document.getElementsByClassName("password-strength-meter-section");
  125. function checkStrength(val) {
  126. if (!val) {
  127. return 0;
  128. };
  129. return zxcvbn(val).score + 1;
  130. };
  131. function updateMeter() {
  132. if (passElem.value) {
  133. meterElem.classList.remove("hidden");
  134. } else {
  135. if (!meterElem.classList.contains("hidden")) {
  136. meterElem.classList.add("hidden");
  137. }
  138. }
  139. var s = checkStrength(passElem.value);
  140. for (var i = 0; i < meterSectionElems.length; i++) {
  141. var elem = meterSectionElems[i];
  142. if (i >= s) {
  143. elem.classList.add("bg-gray-200");
  144. elem.classList.remove("bg-red-400", "bg-yellow-400", "bg-green-500");
  145. } else if (s <= 2) {
  146. elem.classList.add("bg-red-400");
  147. elem.classList.remove("bg-gray-200", "bg-yellow-400", "bg-green-500");
  148. } else if (s <= 4) {
  149. elem.classList.add("bg-yellow-400");
  150. elem.classList.remove("bg-red-400", "bg-gray-200", "bg-green-500");
  151. } else {
  152. elem.classList.add("bg-green-500");
  153. elem.classList.remove("bg-red-400", "bg-yellow-400", "bg-gray-200");
  154. }
  155. }
  156. };
  157. updateMeter();
  158. passElem.oninput = function(e) {
  159. updateMeter();
  160. };
  161. })();`, inputID, meterID)),
  162. )
  163. }