nuxt / content

The file-based CMS for your Nuxt application, powered by Markdown and Vue components.
https://content.nuxt.com
MIT License
3.15k stars 630 forks source link

Should creating a new project result in styleless page? #2261

Open codenomnom opened 1 year ago

codenomnom commented 1 year ago

Environment


Reproduction

Created a new project with the very basic command described in the docs: npx nuxi@latest init content-app -t content. Then just entered the folder and started the server using npm run dev.

Describe the bug

The page initially loads normally, showing the regular nuxt "loading" page - the big logo, mouse moving around creating fancy effect πŸ˜„

Then, shortly after I see Nitro built in 1892 ms, the page seems to be completely stripped out of style:

image

Is this what I really want to see? I'd bet there should be some basic styling, right? Restarting the server does nothing.

I've also tried creating a basic Nuxt app, without content, and it's working properly, showing "Welcome to Nuxt".

Additional context

Here's is the result of the source, during loading and afterwards:

loading:

<!DOCTYPE html><html><head><title>Starting nuxt... | Nuxt</title><meta charset="utf-8"><meta content="width=device-width,initial-scale=1,minimum-scale=1" name="viewport"><style>.nuxt-loader-bar{background:repeating-linear-gradient(to right, #36E4DA 0%, #1DE0B1 25%, #00DC82 50%, #1DE0B1 75%, #36E4DA 100%);height:100px;background-size:200% auto;background-position:0 0;animation:gradient 2s infinite;animation-fill-mode:forwards;animation-timing-function:linear;position:fixed;bottom:0;left:0;right:0;height:5px}.visual-effects .nuxt-loader-bar{height:100px;bottom:-50px;left:-50px;right:-50px;filter:blur(100px)}.visual-effects .mouse-gradient{background:repeating-linear-gradient(to right, #00DC82 0%, #1DE0B1 50%, #36E4DA 100%);filter:blur(100px);opacity:0.5}#animation-toggle{position:fixed;padding:10px;top:0;right:0;transition:opacity 0.4s ease-in;opacity:0}#animation-toggle:hover{opacity:0.8}@keyframes gradient{0%{background-position:0 0}100%{background-position:-200% 0}}@media (prefers-color-scheme: dark){html,body{color:white;color-scheme:dark}.nuxt-loader-bar{opacity:0.5}}*,:before,:after{-webkit-box-sizing:border-box;box-sizing:border-box;border-width:0;border-style:solid;border-color:#e0e0e0}*{--tw-ring-inset:var(--tw-empty, );--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(14, 165, 233, .5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000}:root{-moz-tab-size:4;-o-tab-size:4;tab-size:4}a{color:inherit;text-decoration:inherit}body{margin:0;font-family:inherit;line-height:inherit}button{font-family:inherit;font-size:100%;line-height:1.15;margin:0;text-transform:none;background-color:transparent;background-image:none;padding:0;line-height:inherit;color:inherit}button{-webkit-appearance:button}button{cursor:pointer}html{-webkit-text-size-adjust:100%;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";line-height:1.5}svg{display:block;vertical-align:middle}.bg-white{--tw-bg-opacity:1;background-color:rgba(255,255,255,var(--tw-bg-opacity))}.rounded-full{border-radius:9999px}.flex{display:-webkit-box;display:-ms-flexbox;display:-webkit-flex;display:flex}.flex-col{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;-webkit-flex-direction:column;flex-direction:column}.items-center{-webkit-box-align:center;-ms-flex-align:center;-webkit-align-items:center;align-items:center}.justify-center{-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center}.h-\[200px\]{height:200px}.min-h-screen{min-height:100vh}.overflow-hidden{overflow:hidden}.absolute{position:absolute}.relative{position:relative}.top-0{top:0}.text-center{text-align:center}.w-\[200px\]{width:200px}.z-20{z-index:20}.transition-opacity{-webkit-transition-property:opacity;-o-transition-property:opacity;transition-property:opacity;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);-o-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);-webkit-transition-duration:.15s;-o-transition-duration:.15s;transition-duration:.15s}@media (prefers-color-scheme: dark){.dark\:bg-black{--tw-bg-opacity:1;background-color:rgba(0,0,0,var(--tw-bg-opacity))}}</style><script>(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const e of document.querySelectorAll('link[rel="modulepreload"]'))i(e);new MutationObserver(e=>{for(const r of e)if(r.type==="childList")for(const o of r.addedNodes)o.tagName==="LINK"&&o.rel==="modulepreload"&&i(o)}).observe(document,{childList:!0,subtree:!0});function s(e){const r={};return e.integrity&&(r.integrity=e.integrity),e.referrerPolicy&&(r.referrerPolicy=e.referrerPolicy),e.crossOrigin==="use-credentials"?r.credentials="include":e.crossOrigin==="anonymous"?r.credentials="omit":r.credentials="same-origin",r}function i(e){if(e.ep)return;e.ep=!0;const r=s(e);fetch(e.href,r)}})();</script></head><body class="visual-effects relative overflow-hidden min-h-screen bg-white dark:bg-black flex flex-col justify-center items-center text-center"><div id="mouseLight" class="absolute top-0 rounded-full mouse-gradient transition-opacity h-[200px] w-[200px]"></div><a href="https://nuxt.com" target="_blank" rel="noopener" class="nuxt-logo z-20"><svg id="nuxtImg" xmlns="http://www.w3.org/2000/svg" width="214" height="53" fill="none" viewBox="0 0 800 200"><path fill="#00DC82" d="M168.303 200h111.522c3.543 0 7.022-.924 10.09-2.679A20.086 20.086 0 0 0 297.3 190a19.855 19.855 0 0 0 2.7-10.001 19.858 19.858 0 0 0-2.709-9.998L222.396 41.429a20.09 20.09 0 0 0-7.384-7.32 20.313 20.313 0 0 0-10.088-2.679c-3.541 0-7.02.925-10.087 2.68a20.082 20.082 0 0 0-7.384 7.32l-19.15 32.896L130.86 9.998a20.086 20.086 0 0 0-7.387-7.32A20.322 20.322 0 0 0 113.384 0c-3.542 0-7.022.924-10.09 2.679a20.091 20.091 0 0 0-7.387 7.319L2.709 170A19.853 19.853 0 0 0 0 179.999c-.002 3.511.93 6.96 2.7 10.001a20.091 20.091 0 0 0 7.385 7.321A20.322 20.322 0 0 0 20.175 200h70.004c27.737 0 48.192-12.075 62.266-35.633l34.171-58.652 18.303-31.389 54.93 94.285h-73.233L168.303 200Zm-79.265-31.421-48.854-.011 73.232-125.706 36.541 62.853-24.466 42.01c-9.347 15.285-19.965 20.854-36.453 20.854Z"></path><path fill="currentColor" d="M377 200a4 4 0 0 0 4-4v-93s5.244 8.286 15 25l38.707 66.961c1.789 3.119 5.084 5.039 8.649 5.039H470V50h-27a4 4 0 0 0-4 4v94l-17-30-36.588-62.98c-1.792-3.108-5.081-5.02-8.639-5.02H350v150h27ZM676.203 143.857 710.551 92h-25.73a9.972 9.972 0 0 0-8.333 4.522L660.757 120.5l-15.731-23.978A9.972 9.972 0 0 0 636.693 92h-25.527l34.348 51.643L608.524 200h24.966a9.969 9.969 0 0 0 8.29-4.458l19.18-28.756 18.981 28.72a9.968 9.968 0 0 0 8.313 4.494h24.736l-36.787-56.143ZM724.598 92h19.714V60.071h28.251V92H800v24.857h-27.437V159.5c0 10.5 5.284 15.429 14.43 15.429H800V200h-16.869c-23.576 0-38.819-14.143-38.819-39.214v-43.929h-19.714V92ZM590 92h-15c-3.489 0-6.218.145-8.5 2.523-2.282 2.246-2.5 3.63-2.5 7.066v52.486c0 8.058-.376 12.962-4 16.925-3.624 3.831-8.619 5-16 5-7.247 0-12.376-1.169-16-5-3.624-3.963-4-8.867-4-16.925v-52.486c0-3.435-.218-4.82-2.5-7.066C519.218 92.145 516.489 92 513 92h-15v62.422c0 14.004 3.892 25.101 11.676 33.292C517.594 195.905 529.103 200 544 200c14.897 0 26.204-4.095 34.123-12.286 7.918-8.191 11.877-19.288 11.877-33.292V92Z"></path></svg> </a><button id="animation-toggle">Animation Enabled</button><div class="nuxt-loader-bar"></div><script>const ANIMATION_KEY = 'nuxt-loading-enable-animation'
      const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent)

      let isLowPerformance = checkIsLowPerformance()
      let enableAnimation = localStorage.getItem(ANIMATION_KEY) === 'false'
         ? false
         : localStorage.getItem(ANIMATION_KEY) === 'true'
          ? true
          : !isLowPerformance

      const mouseLight = window.document.getElementById('mouseLight')
      const nuxtImg = window.document.getElementById('nuxtImg')
      const animationToggle = window.document.getElementById('animation-toggle')
      const body = window.document.body
      let bodyRect

      function checkIsLowPerformance() {
        return window.matchMedia('(prefers-reduced-motion: reduce)').matches
         || navigator.hardwareConcurrency < 2
         || navigator.deviceMemory < 1
         // Safari has some performance issue on the blur filter. Remove this when it's fixed.
         || isSafari
      }
      function calculateDistance(elem, mouseX, mouseY) {
        return Math.floor(Math.sqrt(Math.pow(mouseX - (elem.x + (elem.width / 2)), 2) + Math.pow(mouseY - (elem.top + (elem.height / 2)), 2)));
      }
      function onFocusOut() {
        if (!enableAnimation) {
          return
        }
        mouseLight.style.opacity = 0
        nuxtImg.style.opacity = 0.7
      }
      function onMouseMove(e) {
        if (!enableAnimation) {
          return
        }
        const pointerRect = nuxtImg.getBoundingClientRect()
        if (!bodyRect) {
          bodyRect = body.getBoundingClientRect()
        }
        const distance = calculateDistance(pointerRect, e.pageX, e.pageY)
        const size = Math.max((1000 - distance) / 2 / 100, 1)

        mouseLight.style.top = `${e.clientY - bodyRect.y - mouseLight.clientHeight / 2}px`
        mouseLight.style.left = `${e.clientX - mouseLight.clientWidth / 2}px`
        mouseLight.style.width = mouseLight.style.height = `${Math.max(Math.round(size * 100), 300)}px`
        mouseLight.style.filter = `blur(${Math.min(Math.max(size * 50, 100), 160)}px)`
        mouseLight.style.opacity = Math.min(Math.max(size / 4, 0.6), 1)

        const dx = e.pageX - pointerRect.left
        const dy = e.pageY - pointerRect.top
        const logoGradient = `radial-gradient(circle at ${dx}px ${dy}px, black 75%, transparent 100%)`
        nuxtImg.style['-webkit-mask-image'] = logoGradient
        nuxtImg.style['mask-image'] = logoGradient
        nuxtImg.style.opacity = Math.min(Math.max(size / 4, 0.7), 1)
      }

      function toggleAnimation(value = !enableAnimation) {
        enableAnimation = value
        document.body.classList.toggle('visual-effects', enableAnimation)
        if (value) {
          onFocusOut()
          animationToggle.innerText = 'Animation Enabled'
        }
        else {
          mouseLight.style.opacity = 0
          nuxtImg.style.opacity = 1
          nuxtImg.style['mask-image'] = ''
          nuxtImg.style['-webkit-mask-image'] = ''
          animationToggle.innerText = 'Animation Disabled'
        }
        localStorage.setItem(ANIMATION_KEY, enableAnimation ? 'true' : 'false')
      }

      animationToggle.addEventListener('click', () => toggleAnimation(), { passive: true})
      body.addEventListener('mousemove', onMouseMove, { passive: true })
      body.addEventListener('mouseleave', onFocusOut, { passive: true })

      toggleAnimation(enableAnimation)

      if (typeof window.fetch === 'undefined') {
        setTimeout(() => window.location.reload(), 1000)
      } else {
        const check = async () => {
          try {
            const body = await window
              .fetch(window.location.href)
              .then(r => r.text())
            if (!body.includes('__NUXT_LOADING__')) {
              return window
                .location
                .reload()
            }
          } catch  {}
          setTimeout(check, 1000)
        }
        check()
      }</script></body></html>

after:

<!DOCTYPE html>
<html >
<head><meta charset="utf-8">
<title>Nuxt Content</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta property="og:title" content="Nuxt Content">
<meta name="description" content="This page corresponds to the / route of your website. You can delete it or create another file in the content/ directory.">
<meta property="og:description" content="This page corresponds to the / route of your website. You can delete it or create another file in the content/ directory.">
<link rel="modulepreload" as="script" crossorigin="" href="/_nuxt/C:/content-app/node_modules/nuxt/dist/app/entry.js">
<script type="module" src="/_nuxt/@vite/client" crossorigin=""></script>
<script type="module" src="/_nuxt/C:/content-app/node_modules/nuxt/dist/app/entry.js" crossorigin=""></script></head>
<body ><div id="__nuxt"><div><main><!--[--><div data-content-id="content:index.md"><h1 id="nuxt-content"><!--[-->Nuxt Content<!--]--></h1><p><!--[-->This page corresponds to the <code><!--[-->/<!--]--></code> route of your website. You can delete it or create another file in the <code><!--[-->content/<!--]--></code> directory.<!--]--></p><p><!--[-->Try to navigate to <a href="/about" class=""><!--[-->/about<!--]--></a>. These 2 pages are rendered by the <code><!--[-->pages/[...slug].vue<!--]--></code> component.<!--]--></p><hr><p><!--[-->Look at the <a href="https://content.nuxtjs.org/" rel="nofollow"><!--[-->Content documentation<!--]--></a> to learn more.<!--]--></p></div><!--]--></main></div></div><script type="application/json" id="__NUXT_DATA__" data-ssr="true">[["Reactive",1],{"data":2,"state":87,"_errors":88,"serverRendered":90,"path":4},{"content-query-1DxZ1vYQk5":3},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":5,"_empty":6,"title":7,"description":8,"body":9,"_type":82,"_id":83,"_source":84,"_file":85,"_extension":86},"/","",false,"Nuxt Content","This page corresponds to the / route of your website. You can delete it or create another file in the content/ directory.",{"type":10,"children":11,"toc":79},"root",[12,20,40,60,64],{"type":13,"tag":14,"props":15,"children":17},"element","h1",{"id":16},"nuxt-content",[18],{"type":19,"value":7},"text",{"type":13,"tag":21,"props":22,"children":23},"p",{},[24,26,31,33,38],{"type":19,"value":25},"This page corresponds to the ",{"type":13,"tag":27,"props":28,"children":29},"code-inline",{},[30],{"type":19,"value":4},{"type":19,"value":32}," route of your website. You can delete it or create another file in the ",{"type":13,"tag":27,"props":34,"children":35},{},[36],{"type":19,"value":37},"content/",{"type":19,"value":39}," directory.",{"type":13,"tag":21,"props":41,"children":42},{},[43,45,51,53,58],{"type":19,"value":44},"Try to navigate to ",{"type":13,"tag":46,"props":47,"children":49},"a",{"href":48},"/about",[50],{"type":19,"value":48},{"type":19,"value":52},". These 2 pages are rendered by the ",{"type":13,"tag":27,"props":54,"children":55},{},[56],{"type":19,"value":57},"pages/[...slug].vue",{"type":19,"value":59}," component.",{"type":13,"tag":61,"props":62,"children":63},"hr",{},[],{"type":13,"tag":21,"props":65,"children":66},{},[67,69,77],{"type":19,"value":68},"Look at the ",{"type":13,"tag":46,"props":70,"children":74},{"href":71,"rel":72},"https://content.nuxtjs.org/",[73],"nofollow",[75],{"type":19,"value":76},"Content documentation",{"type":19,"value":78}," to learn more.",{"title":5,"searchDepth":80,"depth":80,"links":81},2,[],"markdown","content:index.md","content","index.md","md",{},{"content-query-1DxZ1vYQk5":89},null,true]</script>
<script>window.__NUXT__={};window.__NUXT__.config={public:{content:{locales:[],defaultLocale:"",integrity:"",experimental:{stripQueryParameters:false,clientDB:false},respectPathCase:false,api:{baseURL:"/api/_content"},navigation:{fields:[]},tags:{p:"prose-p",a:"prose-a",blockquote:"prose-blockquote","code-inline":"prose-code-inline",code:"prose-code",em:"prose-em",h1:"prose-h1",h2:"prose-h2",h3:"prose-h3",h4:"prose-h4",h5:"prose-h5",h6:"prose-h6",hr:"prose-hr",img:"prose-img",ul:"prose-ul",ol:"prose-ol",li:"prose-li",strong:"prose-strong",table:"prose-table",thead:"prose-thead",tbody:"prose-tbody",td:"prose-td",th:"prose-th",tr:"prose-tr"},highlight:false,wsUrl:"ws://localhost:4000/",documentDriven:false,host:"",trailingSlash:false,anchorLinks:{depth:4,exclude:[1]}}},app:{baseURL:"/",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script></body>
</html>

Logs

No response

nobkd commented 1 year ago

This is expected and also goes for a default Nuxt only project. If you want a prestyled project for documentation sites you can use for example Docus or other projects from @nuxt-themes

codenomnom commented 1 year ago

This is what a default Nuxt-only project looks like:

image

Why would the content bootstrap have absolutely no styling whatsoever? πŸ€”

nobkd commented 1 year ago

... That's just the <NuxtWelcome> component. Otherwise, that project would look unstyled too.


Your main idea here is, that you think, that the onboarding should have a styled component to introduce one to the project, instead of a plain appearance?

codenomnom commented 1 year ago

I got it. Thanks for the information.

That being said, would it be great if there's such a component for Content as well? I mean... it looks terrible πŸ˜… If it self-contains everything it needs, it would be easier not to use it and move on...

farnabaz commented 1 year ago

@codenomnom Feel free to drop a PR in https://github.com/nuxt/starter/tree/content to improve starter UI Contribution is more than welcome πŸ™‚

Hebilicious commented 1 year ago

A neat way to do it would be to extend NuxtWelcome to accept variants <NuxtWelcome variant="nuxt-content" /> It's not very straightforward though as this is done there https://github.com/nuxt/assets/blob/main/packages/templates/templates/welcome/index.html

It might easier to do a NuxtContentWelcome that is inspired by the other design.

github-actions[bot] commented 1 week ago

This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 30 days.