Header.vue 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. <script setup lang="ts">
  2. import { downloadProject } from './download/download'
  3. import { ref } from 'vue'
  4. import Sun from './icons/Sun.vue'
  5. import Moon from './icons/Moon.vue'
  6. import Share from './icons/Share.vue'
  7. import Download from './icons/Download.vue'
  8. import GitHub from './icons/GitHub.vue'
  9. import Reload from './icons/Reload.vue'
  10. import type { ReplStore } from '@vue/repl'
  11. import VersionSelect from './VersionSelect.vue'
  12. const props = defineProps<{
  13. store: ReplStore
  14. prod: boolean
  15. ssr: boolean
  16. }>()
  17. const emit = defineEmits([
  18. 'toggle-theme',
  19. 'toggle-ssr',
  20. 'toggle-prod',
  21. 'reload-page',
  22. ])
  23. const { store } = props
  24. const currentCommit = __COMMIT__
  25. const vueVersion = ref(`@${currentCommit}`)
  26. const vueURL = store.getImportMap().imports.vue
  27. if (vueURL && !vueURL.startsWith(location.origin)) {
  28. const versionMatch = vueURL.match(/runtime-dom@([^/]+)/)
  29. if (versionMatch) vueVersion.value = versionMatch[1]
  30. }
  31. async function setVueVersion(v: string) {
  32. vueVersion.value = `loading...`
  33. await store.setVueVersion(v)
  34. vueVersion.value = v
  35. }
  36. function resetVueVersion() {
  37. store.resetVueVersion()
  38. vueVersion.value = `@${currentCommit}`
  39. }
  40. async function copyLink(e: MouseEvent) {
  41. if (e.metaKey) {
  42. // hidden logic for going to local debug from play.vuejs.org
  43. window.location.href = 'http://localhost:5173/' + window.location.hash
  44. return
  45. }
  46. await navigator.clipboard.writeText(location.href)
  47. alert('Sharable URL has been copied to clipboard.')
  48. }
  49. function toggleDark() {
  50. const cls = document.documentElement.classList
  51. cls.toggle('dark')
  52. localStorage.setItem(
  53. 'vue-sfc-playground-prefer-dark',
  54. String(cls.contains('dark')),
  55. )
  56. emit('toggle-theme', cls.contains('dark'))
  57. }
  58. </script>
  59. <template>
  60. <nav>
  61. <h1>
  62. <img alt="logo" src="/logo.svg" />
  63. <span>Vue SFC Playground</span>
  64. </h1>
  65. <div class="links">
  66. <VersionSelect
  67. v-model="store.state.typescriptVersion"
  68. pkg="typescript"
  69. label="TypeScript Version"
  70. />
  71. <VersionSelect
  72. :model-value="vueVersion"
  73. @update:model-value="setVueVersion"
  74. pkg="vue"
  75. label="Vue Version"
  76. >
  77. <li>
  78. <a @click="resetVueVersion">This Commit ({{ currentCommit }})</a>
  79. </li>
  80. <li>
  81. <a
  82. href="https://app.netlify.com/sites/vue-sfc-playground/deploys"
  83. target="_blank"
  84. >Commits History</a
  85. >
  86. </li>
  87. </VersionSelect>
  88. <button
  89. title="Toggle development production mode"
  90. class="toggle-prod"
  91. :class="{ prod }"
  92. @click="$emit('toggle-prod')"
  93. >
  94. <span>{{ prod ? 'PROD' : 'DEV' }}</span>
  95. </button>
  96. <button
  97. title="Toggle server rendering mode"
  98. class="toggle-ssr"
  99. :class="{ enabled: ssr }"
  100. @click="$emit('toggle-ssr')"
  101. >
  102. <span>{{ ssr ? 'SSR ON' : 'SSR OFF' }}</span>
  103. </button>
  104. <button title="Toggle dark mode" class="toggle-dark" @click="toggleDark">
  105. <Sun class="light" />
  106. <Moon class="dark" />
  107. </button>
  108. <button title="Copy sharable URL" class="share" @click="copyLink">
  109. <Share />
  110. </button>
  111. <button title="Reload page" class="reload" @click="$emit('reload-page')">
  112. <Reload />
  113. </button>
  114. <button
  115. title="Download project files"
  116. class="download"
  117. @click="downloadProject(store)"
  118. >
  119. <Download />
  120. </button>
  121. <a
  122. href="https://github.com/vuejs/core/tree/main/packages/sfc-playground"
  123. target="_blank"
  124. title="View on GitHub"
  125. class="github"
  126. >
  127. <GitHub />
  128. </a>
  129. </div>
  130. </nav>
  131. </template>
  132. <style>
  133. nav {
  134. --bg: #fff;
  135. --bg-light: #fff;
  136. --border: #ddd;
  137. --btn: #666;
  138. --highlight: #333;
  139. --green: #3ca877;
  140. --purple: #904cbc;
  141. --btn-bg: #eee;
  142. color: var(--base);
  143. height: var(--nav-height);
  144. box-sizing: border-box;
  145. padding: 0 1em;
  146. background-color: var(--bg);
  147. box-shadow: 0 0 4px rgba(0, 0, 0, 0.33);
  148. position: relative;
  149. z-index: 999;
  150. display: flex;
  151. justify-content: space-between;
  152. }
  153. .dark nav {
  154. --base: #ddd;
  155. --bg: #1a1a1a;
  156. --bg-light: #242424;
  157. --border: #383838;
  158. --highlight: #fff;
  159. --btn-bg: #333;
  160. box-shadow: none;
  161. border-bottom: 1px solid var(--border);
  162. }
  163. h1 {
  164. font-weight: 500;
  165. display: inline-flex;
  166. place-items: center;
  167. }
  168. h1 img {
  169. height: 24px;
  170. margin-right: 10px;
  171. }
  172. @media (max-width: 560px) {
  173. h1 span {
  174. font-size: 0.9em;
  175. }
  176. }
  177. @media (max-width: 520px) {
  178. h1 span {
  179. display: none;
  180. }
  181. }
  182. .links {
  183. display: flex;
  184. }
  185. .toggle-prod span,
  186. .toggle-ssr span {
  187. font-size: 12px;
  188. border-radius: 4px;
  189. padding: 4px 6px;
  190. }
  191. .toggle-prod span {
  192. background: var(--green);
  193. color: #fff;
  194. }
  195. .toggle-prod.prod span {
  196. background: var(--purple);
  197. }
  198. .toggle-ssr span {
  199. background-color: var(--btn-bg);
  200. }
  201. .toggle-ssr.enabled span {
  202. color: #fff;
  203. background-color: var(--green);
  204. }
  205. .toggle-dark svg {
  206. width: 18px;
  207. height: 18px;
  208. }
  209. .toggle-dark .dark,
  210. .dark .toggle-dark .light {
  211. display: none;
  212. }
  213. .dark .toggle-dark .dark {
  214. display: inline-block;
  215. }
  216. .links button,
  217. .links .github {
  218. padding: 1px 6px;
  219. color: var(--btn);
  220. }
  221. .links button:hover,
  222. .links .github:hover {
  223. color: var(--highlight);
  224. }
  225. .version:hover .active-version::after {
  226. border-top-color: var(--btn);
  227. }
  228. .dark .version:hover .active-version::after {
  229. border-top-color: var(--highlight);
  230. }
  231. .versions {
  232. display: none;
  233. position: absolute;
  234. left: 0;
  235. top: 40px;
  236. background-color: var(--bg-light);
  237. border: 1px solid var(--border);
  238. border-radius: 4px;
  239. list-style-type: none;
  240. padding: 8px;
  241. margin: 0;
  242. width: 200px;
  243. max-height: calc(100vh - 70px);
  244. overflow: scroll;
  245. }
  246. .versions a {
  247. display: block;
  248. padding: 6px 12px;
  249. text-decoration: none;
  250. cursor: pointer;
  251. color: var(--base);
  252. }
  253. .versions a:hover {
  254. color: var(--green);
  255. }
  256. .versions.expanded {
  257. display: block;
  258. }
  259. .links > * {
  260. display: flex;
  261. align-items: center;
  262. }
  263. .links > * + * {
  264. margin-left: 4px;
  265. }
  266. </style>