InstallOptions.vue 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. <script lang="ts">
  2. import { InstallOptions } from "../../../_data/options";
  3. import { LanguagesOptions } from "../../../_data/languages";
  4. import { ref } from "vue";
  5. const slot = ref(null);
  6. export default {
  7. props: {
  8. languages: {
  9. type: Array<LanguagesOptions>,
  10. required: true,
  11. selected: "en",
  12. },
  13. items: {
  14. type: Array<InstallOptions>,
  15. required: true,
  16. },
  17. },
  18. data() {
  19. return {
  20. pageloader: false,
  21. hestia_wget:
  22. "wget https://raw.githubusercontent.com/hestiacp/hestiacp/release/install/hst-install.sh",
  23. hestia_install: "sudo bash hst-install.sh",
  24. installStr: "",
  25. };
  26. },
  27. methods: {
  28. getOptionString(item: InstallOptions): string {
  29. if (item.textField) {
  30. return item.selected ? `${item.param} '${item.text}'` : "";
  31. }
  32. if (item.selectField) {
  33. return item.selected ? `${item.param} '${item.text}'` : "";
  34. }
  35. return item.param.includes("force") && item.selected
  36. ? item.param
  37. : `${item.param}${item.selected ? " yes" : " no"}`;
  38. },
  39. generateString() {
  40. const installStr = this.items.map(this.getOptionString).filter(Boolean);
  41. this.installStr = `${this.hestia_install} ${installStr.join(" ")}`;
  42. (this.$refs.dialog as HTMLDialogElement).showModal();
  43. },
  44. closeDialog(e) {
  45. if (e.target === this.$refs.dialogClose || e.target === this.$refs.dialog) {
  46. (this.$refs.dialog as HTMLDialogElement).close();
  47. }
  48. },
  49. toggleOption(e) {
  50. if (e.target.checked) {
  51. let conflicts = e.target.getAttribute("conflicts");
  52. if (conflicts) {
  53. if (document.getElementById(conflicts).checked) {
  54. document.getElementById(conflicts).click();
  55. }
  56. }
  57. let depends = e.target.getAttribute("depends");
  58. if (depends) {
  59. if (!document.getElementById(depends).checked) {
  60. document.getElementById(depends).click();
  61. }
  62. }
  63. }
  64. },
  65. copyToClipboard(text: string, button: HTMLButtonElement) {
  66. navigator.clipboard.writeText(text).then(
  67. () => {
  68. button.textContent = "Copied!";
  69. setTimeout(() => {
  70. button.textContent = "Copy";
  71. }, 1000);
  72. },
  73. (err) => {
  74. console.error("Could not copy to clipboard:", err);
  75. }
  76. );
  77. },
  78. },
  79. };
  80. </script>
  81. <template>
  82. <div class="container">
  83. <div class="grid">
  84. <div class="form-group" v-for="item in items">
  85. <div class="form-check u-mb10">
  86. <input
  87. @change="toggleOption"
  88. type="checkbox"
  89. class="form-check-input"
  90. v-model="item.selected"
  91. :value="item.value"
  92. :id="item.id"
  93. :conflicts="item.conflicts"
  94. :depends="item.depends"
  95. />
  96. <label :for="item.id">{{ item.id }}</label>
  97. </div>
  98. <template v-if="item.textField || item.selectField">
  99. <label class="form-label" :for="'input-' + item.id">{{ item.desc }}</label>
  100. </template>
  101. <template v-else>
  102. <p>{{ item.desc }}</p>
  103. </template>
  104. <div v-if="item.textField">
  105. <input
  106. type="text"
  107. class="form-control"
  108. v-model="item.text"
  109. :id="'input-' + item.id"
  110. :type="'+item.type+'"
  111. />
  112. </div>
  113. <div v-if="item.selectField">
  114. <select class="form-select" v-model="item.text" :id="'input-' + item.id">
  115. <option v-for="language in languages" :value="language.value" :key="language.value">
  116. {{ language.text }}
  117. </option>
  118. </select>
  119. </div>
  120. </div>
  121. </div>
  122. <div class="u-text-center u-mb10">
  123. <button @click="generateString" class="form-submit" type="button">Submit</button>
  124. </div>
  125. <dialog ref="dialog" class="modal" @click="closeDialog">
  126. <button class="modal-close" @click="closeDialog" type="button" ref="dialogClose">
  127. Close
  128. </button>
  129. <div ref="dialogContent" class="modal-content">
  130. <h1 class="modal-heading">Installation instructions</h1>
  131. <p class="u-mb10">
  132. Log in to your server as root, either directly or via SSH:
  133. <code>ssh [email protected]</code> and download the installation script:
  134. </p>
  135. <div class="u-pos-relative">
  136. <input
  137. type="text"
  138. class="form-control u-monospace u-mb10"
  139. v-model="hestia_wget"
  140. readonly
  141. />
  142. <button
  143. class="button-positioned"
  144. @click="copyToClipboard(hestia_wget, $event.target)"
  145. type="button"
  146. title="Copy to Clipboard"
  147. >
  148. Copy
  149. </button>
  150. </div>
  151. <p class="u-mb10">Then run the following command:</p>
  152. <div class="u-pos-relative">
  153. <textarea class="form-control u-min-height100" v-model="installStr" readonly />
  154. <button
  155. class="button-positioned"
  156. @click="copyToClipboard(installStr, $event.target)"
  157. type="button"
  158. title="Copy to Clipboard"
  159. >
  160. Copy
  161. </button>
  162. </div>
  163. </div>
  164. </dialog>
  165. </div>
  166. </template>
  167. <style scoped>
  168. .container {
  169. margin: 0px auto;
  170. max-width: 1152px;
  171. }
  172. .grid {
  173. display: grid;
  174. grid-gap: 20px;
  175. margin-top: 30px;
  176. margin-bottom: 30px;
  177. @media (min-width: 640px) {
  178. grid-template-columns: 1fr 1fr;
  179. }
  180. @media (min-width: 960px) {
  181. grid-template-columns: 1fr 1fr 1fr;
  182. }
  183. }
  184. .form-group {
  185. font-size: 0.9em;
  186. border-radius: 10px;
  187. padding: 15px 20px;
  188. background-color: var(--vp-c-bg-alt);
  189. }
  190. .form-label {
  191. display: inline-block;
  192. margin-left: 2px;
  193. padding-bottom: 5px;
  194. text-transform: capitalize;
  195. }
  196. .form-control {
  197. font-size: 0.9em;
  198. border: 1px solid var(--vp-c-border);
  199. border-radius: 4px;
  200. background-color: var(--vp-c-bg);
  201. width: 100%;
  202. padding: 5px 10px;
  203. &:hover {
  204. border-color: var(--vp-c-border-hover);
  205. }
  206. &:focus {
  207. border-color: var(--vp-c-brand);
  208. }
  209. }
  210. .form-select {
  211. appearance: auto;
  212. font-size: 0.9em;
  213. border: 1px solid var(--vp-c-border);
  214. border-radius: 4px;
  215. background-color: var(--vp-c-bg);
  216. padding: 5px 10px;
  217. width: 100%;
  218. &:hover {
  219. border-color: var(--vp-c-border-hover);
  220. }
  221. &:focus {
  222. border-color: var(--vp-c-brand);
  223. }
  224. }
  225. .form-check {
  226. position: relative;
  227. padding-left: 20px;
  228. margin-left: 3px;
  229. min-height: 24px;
  230. & label {
  231. font-weight: 600;
  232. }
  233. }
  234. .form-check-input {
  235. position: absolute;
  236. margin-top: 5px;
  237. margin-left: -20px;
  238. }
  239. .form-submit {
  240. border: 1px solid transparent;
  241. display: inline-block;
  242. font-weight: 600;
  243. transition: color 0.25s, border-color 0.25s, background-color 0.25s;
  244. border-radius: 20px;
  245. font-size: 16px;
  246. padding: 10px 20px;
  247. background-color: var(--vp-button-brand-bg);
  248. border-color: var(--vp-button-brand-border);
  249. color: var(--vp-button-brand-text);
  250. &:hover {
  251. background-color: var(--vp-button-brand-hover-bg);
  252. border-color: var(--vp-button-brand-hover-border);
  253. color: var(--vp-button-brand-hover-text);
  254. }
  255. &:active {
  256. background-color: var(--vp-button-brand-active-bg);
  257. border-color: var(--vp-button-brand-active-border);
  258. color: var(--vp-button-brand-active-text);
  259. }
  260. }
  261. .button-positioned {
  262. position: absolute;
  263. right: 1px;
  264. top: 1px;
  265. border-top-right-radius: 3px;
  266. border-bottom-right-radius: 3px;
  267. color: var(--vp-c-brand);
  268. font-weight: 600;
  269. padding: 6px 10px;
  270. background-color: var(--vp-c-bg);
  271. }
  272. .modal {
  273. position: fixed;
  274. border-radius: 10px;
  275. border: 1px solid var(--vp-c-border);
  276. box-shadow: 0 8px 40px 0 rgb(0 0 0 / 35%);
  277. padding: 0;
  278. &::backdrop {
  279. background-color: rgb(0 0 0 / 50%);
  280. }
  281. }
  282. .modal-close {
  283. position: absolute;
  284. top: 10px;
  285. right: 15px;
  286. font-weight: 600;
  287. color: var(--vp-c-brand);
  288. }
  289. .modal-content {
  290. padding: 30px;
  291. }
  292. .modal-heading {
  293. font-weight: 600;
  294. font-size: 1.3em;
  295. text-align: center;
  296. margin-bottom: 15px;
  297. }
  298. code {
  299. background-color: var(--vp-c-bg-alt);
  300. border-radius: 3px;
  301. padding: 2px 5px;
  302. }
  303. .u-mb10 {
  304. margin-bottom: 10px !important;
  305. }
  306. .u-min-height100 {
  307. min-height: 100px;
  308. }
  309. .u-text-center {
  310. text-align: center !important;
  311. }
  312. .u-monospace {
  313. font-family: monospace !important;
  314. }
  315. .u-pos-relative {
  316. position: relative !important;
  317. }
  318. </style>