https://www.youtube.com/watch?v=i0FN-OwJ7QI&list=PLv2d7VI9OotQ1F92Jp9Ce7ovHEsuRQB3Y&index=5 

 

HTML (Hypertext Markup Language)

 

웹 상에서 보여지도록 디자인 된 Markup 언어 (구조화 된 언어) 표준화 된 언어를 사용하고 있다. 

 

 

웹 상에서 HTML을 개발할 수 있는 사이트

 

https://jsbin.com/?html,output 

 

JS Bin

Sample of the bin:

jsbin.com

 

 

기본 구조

<!DOCTYPE html> <!-- 도큐먼트 타입은 HTML이다. -->
<html>
<head>  <!-- 구글에서 검색할 때, 나오는 메타데이터만 정의되어 있음. -->
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>	 <!-- 사용자에게 보여지는 내용. -->

</body>
</html>

 

 

W3C라는 단체에서 HTML에 관련된 내용을 정의함. 관련 HTML 태그들은

https://developer.mozilla.org/ko/

 

MDN Web Docs

The MDN Web Docs site provides information about Open Web technologies including HTML, CSS, and APIs for both Web sites and progressive web apps.

developer.mozilla.org

에서 확인할 수가 있다. 

 

HTML은 쓰면 안되는 Tag들이 존재한다. 이를 확인하고 싶으면

https://validator.w3.org/

 

The W3C Markup Validation Service

Validate by File Upload Note: file upload may not work with Internet Explorer on some versions of Windows XP Service Pack 2, see our information page on the W3C QA Website.

validator.w3.org

에서 확인이 가능하다. 

 

 

웹사이트를 보는 방법

 

웹사이트는 모든 박스들이 모여서 만들어져 있다. 

 

 

const baseURL = process.env.BASE_URL || 'http://localhost:8000/api';
export default {
  srcDir: 'client', //폴더 구조 정의 client의 폴더에 page, assets, middleware등이 있음.
  target: 'server', // 'server': For server side rendering 'static': For static sites

  generate: {
    fallback: true // 404 오류가 발생했을 때, 페이지 이동
  },

  // Global page headers: https://go.nuxtjs.dev/config-head
  head: {
    title: 'ezst-frontend',
    htmlAttrs: {
      lang: 'en'
    },
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      { hid: 'description', name: 'description', content: '' },
      { name: 'format-detection', content: 'telephone=no' }
    ],
    link: [
      { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
    ],
    script: [ //추가 cdn 정의 jquery, brython runner, fontawesome
      { type: 'text/javascript', src: '/vendor/jquery/jquery-3.6.0.min.js'},
      { type: 'text/javascript', src: '/vendor/flipster/jquery.flipster.min.js' },
      { type: 'text/javascript', src: 'https://cdn.jsdelivr.net/gh/pythonpad/brython-runner/lib/brython-runner.bundle.js'},
      { type: 'text/javascript', src: 'https://kit.fontawesome.com/13c40d56ec.js', crossorigin:'anonymous'},
    ]
  },

  // Global CSS: https://go.nuxtjs.dev/config-css
  css: [
    '~/assets/fonts/main.css',
    '~/assets/styles/main.scss',

    '~/static/vendor/flipster/jquery.flipster.min.css'
  ],

  // Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
  plugins: [
    { src: '~/plugins/globals.js'},
    { src: '~/plugins/flipster.js'},
    { src: '~/plugins/vue-codemirror', ssr: false },
    { src: '~/plugins/persistedState.js'}, // 새로고침 해도 state 유지 (cookie로 저장) (vercel 오류 발생)
    { src: '~/plugins/vue-plyr', mode: 'client' },
    { src: '~/plugins/iamport.js', ssr: false, injectAs: 'IMP' },
  ],

  // Auto import components: https://go.nuxtjs.dev/config-components
  components: true,

  // Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules
  buildModules: [ //env 파일 사용
    '@nuxtjs/dotenv'
  ],

  // Modules: https://go.nuxtjs.dev/config-modules
  modules: [
    // https://go.nuxtjs.dev/buefy
    'nuxt-buefy',
    '@nuxtjs/axios',
    '@nuxtjs/auth-next',
  ],

  axios: {
    baseURL: baseURL
  },

  auth: {
    plugins: [ '~/plugins/auth.js' ],
    redirect: {
      home: false,
      callback: '/login',
      logout: '/'
    },
    strategies: {
      google: {
        clientId: process.env.GOOGLE_CLIENT_ID,
        codeChallengeMethod: '',
        responseType: 'code',
        endpoints: {
          token: `${baseURL}/social-login/google/`,
          userInfo: `${baseURL}/user/`,
          logout: false
        },
      },
      naver: {
        scheme: 'oauth2',
        clientId: process.env.NAVER_CLIENT_ID,
        codeChallengeMethod: '',
        responseType: 'code',
        // grantType: 'authorization_code',
        endpoints: {
          authorization: 'https://nid.naver.com/oauth2.0/authorize',
          token: `${baseURL}/social-login/naver/`,
          userInfo: `${baseURL}/user/`,
        },
        token: {
          property: 'access_token',
          type: 'Bearer',
          maxAge: 18000
        },
      },
    }
  },
  // Build Configuration: https://go.nuxtjs.dev/config-build
  build: {
    extend(config) {
      config.resolve.alias['vue'] = 'vue/dist/vue.common'
    }
  },
  publicRuntimeConfig: {
    baseUrl: baseURL,
  },
  env: {
    serverUrl: process.env.SERVER_URL || 'http://localhost:8000',
  },
}

'Front-End > Vue & Nuxt' 카테고리의 다른 글

Nuxt 라이브러리 적용  (0) 2022.02.15
Vercel 배포  (0) 2022.02.10
Hide Navbar on Scroll Down in Vue  (0) 2022.01.05
Nuxt.js Async, Fetch  (0) 2022.01.05
Nuxt.js 동작 정리  (0) 2021.12.28

ModelAdmin에서 검색을 하는 방법이 있다. 

Django 에서는 기본적으로 DjangoORMSearchHandler 을 제공한다.  https://docs.djangoproject.com/en/4.0/ref/contrib/admin/#django.contrib.admin.ModelAdmin.search_fields

 

The Django admin site | Django documentation | Django

Django The web framework for perfectionists with deadlines. Overview Download Documentation News Community Code Issues About ♥ Donate

docs.djangoproject.com

모델의 CharField, TextField, RichTextField or StreamField만 검색을 제공하고 foreignkey의 속성을 검색하고 싶으면 

foreignkey__atrribute로 검색하면 된다. 그리고 wagtail에서는 ','을 붙여줘야한다. 

class UserCourseAdmin(ModelAdmin):
    model = UserCourse
    menu_label = '사용자 신청 강의 관리'  # ditch this to use verbose_name_plural from model
    menu_icon = 'list-ol'  # change as required
    list_display = ('user_email', 'course',)
    search_fields = ['user__email',]
    #search_handler_class = WagtailBackendSearchHandler

list_display에는 @property를 사용할 수 있으므로 저렇게 추가적인 외래키의 내용이 필요하다면 정의해주자.

 

 

 

 

Wagtail에서는 WagtailBackendSearchHandler를 제공하는데 문제는 모델의 필드들만 검색이 가능하다. 

search_handler_class = WagtailBackendSearchHandler

https://docs.wagtail.io/en/stable/reference/contrib/modeladmin/indexview.html#modeladmin-search-fields

'Back-End > Wagtail, Django' 카테고리의 다른 글

Wagtail 프로젝트 배포  (0) 2021.12.20
Wagtail Changing the Admin Display Title  (0) 2021.12.03
Wagtail Routable  (0) 2021.12.03
Wagtail StreamField Options  (0) 2021.12.02
Wagtail Custom Page Properties  (0) 2021.12.02

https://www.accordbox.com/blog/how-export-restore-wagtail-site/

 

# postgres
python -Xutf8 manage.py dumpdata --natural-foreign --indent 2 \
    -e contenttypes -e auth.permission -e postgres_search.indexentry \
    -e wagtailcore.groupcollectionpermission \
    -e wagtailcore.grouppagepermission -e wagtailimages.rendition \
    -e sessions > data.json
    
# sqlite
python -Xutf8 manage.py dumpdata --natural-foreign --indent 2 -e contenttypes -e auth.permission -e wagtailsearch.indexentry -e wagtailcore.groupcollectionpermission -e wagtailcore.grouppagepermission -e wagtailimages.rendition -e sessions -e wagtailcore.pagerevision > data.json

python -Xutf8 manage.py dumpdata --indent 2 > data.json

 

import os

from django.conf import settings
from django.core.files.storage import default_storage, FileSystemStorage
from django.core.management.base import BaseCommand
from django.core.management import call_command

from wagtail.core.models import Site, Page


class Command(BaseCommand):
    def _copy_files(self, local_storage, path):
        """
        Recursively copy files from local_storage to default_storage. Used
        to automatically bootstrap the media directory (both locally and on
        cloud providers) with the images linked from the initial data (and
        included in MEDIA_ROOT).
        """
        directories, file_names = local_storage.listdir(path)
        for directory in directories:
            self._copy_files(local_storage, path + directory + '/')
        for file_name in file_names:
            with local_storage.open(path + file_name) as file_:
                default_storage.save(path + file_name, file_)

    def handle(self, **options):
        fixtures_dir = os.path.join(settings.PROJECT_DIR, 'fixtures')
        print(os.path.join(fixtures_dir, 'ezstbackend.json'))
        fixture_file = os.path.join(fixtures_dir, 'ezstbackend.json')

        print("Copying media files to configured storage...")
        local_storage = FileSystemStorage(os.path.join(fixtures_dir, 'media'))
        self._copy_files(local_storage, '')  # file storage paths are relative

        # Wagtail creates default Site and Page instances during install, but we already have
        # them in the data load. Remove the auto-generated ones.
        if Site.objects.filter(hostname='localhost').exists():
            Site.objects.get(hostname='localhost').delete()
        if Page.objects.filter(title='Welcome to your new Wagtail site!').exists():
            Page.objects.get(title='Welcome to your new Wagtail site!').delete()

        call_command('loaddata', fixture_file, verbosity=0)

        print("Awesome. Your data is loaded! The bakery's doors are almost ready to open...")

 

python manage.py load_initial_data

python manage.py loaddata data.json

'Back-End > Wagtail, Django 배포' 카테고리의 다른 글

Wagtail Heroku Deploy  (0) 2022.03.01
Wagtail RichText API  (0) 2022.01.07
2. Gunicorn, Nginx 적용  (0) 2021.12.23
1. PostgreSQL 적용  (0) 2021.12.22
3. Docker(Django, Wagtail)  (0) 2021.12.22

**참고 사이트**
https://docs.wagtail.io/en/stable/extending/rich_text_internals.html#rich-text-internals
https://github.com/wagtail/wagtail/issues/2695

**Issue**
RichEditor에서 Image나 file을 사용할 때 Wagtail 자체에서 embed tag로 변환해서 Database에 저장합니다. 

 

<embed embedtype="image" id="10" alt="A pied wagtail" format="left" />


Wagtail Template에서 |richtext가 바로 위 embed태그를 parse해주는 Template태그입니다. 다만 Api 전달할 때에는 그대로 embed 태그로 오기 때문에 이를 변환해서 Api에 사용할 수 있는 방법이 필요합니다. (이는 FrontEnd에서 v-html로 바로 변환해서 사용 해야 하기 때문에 그렇습니다.)

**해결**
그래서 전달되는 RichText의 Image를 원하는 형식에 맞게 바꾸고 이를 변환해서 API에 전달하는 방식에 대해서 고민하고 property를 사용해서 해결했습니다. 

 

handlers.py

from wagtail.core.rich_text import EmbedHandler
from wagtail.images.models import Image


class ImageHandler(EmbedHandler):
    identifier = 'image'

    @classmethod
    def expand_db_attributes(cls, attrs):
        image = Image.objects.get(pk=attrs['id'])
        image_url = image.file.name
        image_endpoint = "http://127.0.0.1:8000/media/" + image_url
        response_format = '<img class="richtext-%s" src="%s" alt="%s" />'
        return response_format % (
            attrs['format'],
            image_endpoint,
            attrs['alt'])

 

 

wagtail_hooks.py

from .handlers import ImageHandler

@hooks.register("register_rich_text_features", order=10)
def register_embed_handler(features):
    features.register_embed_type(ImageHandler)

 

 

models.py

from wagtail.core.rich_text import expand_db_html

@property
  def intro_api(self):
  	return expand_db_html(self.intro)

 

 

schema.py

intro_api: str

 

 

되는 코드인데 안된다고 생각되었을 경우 다른 곳에서 원인을 찾아보자!!

'Back-End > Wagtail, Django 배포' 카테고리의 다른 글

Wagtail Heroku Deploy  (0) 2022.03.01
DumpData  (0) 2022.01.08
2. Gunicorn, Nginx 적용  (0) 2021.12.23
1. PostgreSQL 적용  (0) 2021.12.22
3. Docker(Django, Wagtail)  (0) 2021.12.22

https://medium.com/@Taha_Shashtari/hide-navbar-on-scroll-down-in-vue-fb85acbdddfe

 

Hide Navbar on Scroll Down in Vue

Content focused sites usually improve the user experience by reducing the distraction when it’s possible. And one way to achieve this is…

medium.com

 

1. 

<template>
  <div class="app">
    <div
      class="navbar"
      :class="{ 'navbar--hidden': !showNavbar }"
    ></div>
  </div>
</template>

Navbar는 간단하게 showNavbar가 false일 때, 사라질 것이다. 아직 관련 기능을 구현하지 않았다. 

 

 

2.

<style>
* {
  box-sizing: border-box;
}
body {
  padding: 0;
  margin: 0;
}
.app {
  width: 100vw;
  height: 500vh;
  background: hsl(200, 50%, 90%);
}
.navbar {
  height: 60px;
  width: 100vw;
  background: hsl(200, 50%, 50%);
  position: fixed;
  box-shadow: 0 2px 15px rgba(71, 120, 120, 0.5);
  transform: translate3d(0, 0, 0);
  transition: 0.1s all ease-out;
}
.navbar.navbar--hidden {
  box-shadow: none;
  transform: translate3d(0, -100%, 0);
}
</style>

translate3d() :

translate3d() 메소드는 현재 위치에서 해당 요소를 주어진 x축과 y축, z축의 거리만큼 이동시킨다.

주어진 거리가 양수이면 해당 축의 양의 방향으로, 음수이면 해당 축의 음의 방향으로 이동시킨다.

http://tcpschool.com/css/css3_transform_3Dtransform

 

 

3. 

<script>
export default {
  data () {
    return {
      showNavbar: true,
      lastScrollPosition: 0
    }
  }
}
</script>

 

 

4. 

mounted () {
  window.addEventListener('scroll', this.onScroll)
},
beforeDestroy () {
  window.removeEventListener('scroll', this.onScroll)
}

 

 

5. 

methods: {
  onScroll () {
    const currentScrollPosition = window.pageYOffset || document.documentElement.scrollTop
    if (currentScrollPosition < 0) {
      return
    }
    // Stop executing this function if the difference between
    // current scroll position and last scroll position is less than some offset
    if (Math.abs(currentScrollPosition - this.lastScrollPosition) < 60) {
      return
    }
    this.showNavbar = currentScrollPosition < this.lastScrollPosition
    this.lastScrollPosition = currentScrollPosition
  }
}

 

'Front-End > Vue & Nuxt' 카테고리의 다른 글

Vercel 배포  (0) 2022.02.10
Nuxt-2 ezst nuxt.config.js  (0) 2022.01.30
Nuxt.js Async, Fetch  (0) 2022.01.05
Nuxt.js 동작 정리  (0) 2021.12.28
Nuxt-1  (0) 2021.12.26

+ Recent posts