2) 플라스크 api pythonanywhere MYSQL DB와 연결하기

Computer 관심/Flask|2021. 9. 23. 15:16
반응형

이전글에서 말했듯 그냥 SQLite 를 디비서버 대신 사용하려 했었다.

sqlite 파일이 파일루트에 생성된 것도 볼 수 있었는데

문제는 쓰기에서 파일의 변형으로 보아서인지 쓰기 동안 읽기도 불가능 한줄알았다.

(알고 보니 그게 문제는 아니였다.)

 

 

MYSQL DB로 옮겨보려고 한다.

 

 

* sqlite에서 mysql로 옮기면서 디비를 만들때 디비설정에서 여러에러 발생한다.

1) sqlite에서 string에 size를 정해줄 필요가 없었는데 mysql에서는 정해 줘야한다.

2) default에 false 대신 0를 넣어줌

3) server_default에서는 스트링만 받는다. 

4) 데이터 입력시 엑셀에 빈칸은 nan으로 되어 pandas

(nan can not be used with MySQL 에러가 발생)

5. foreign key 참조 값은 string인데 그거를 받는 필드값을 int로 설정한경우 (sqlite에서는 됬었다...)

 

등, MySQL을 설치하기 귀찮다고 로컬에서 안깔고 하니 더 고생이다.

 

이렇게 에러가 발생해서 클라이언트와 연결이 안되면 cors 에러를 보내기 때문에 엉뚱한데서 에러를 찾으려다 시간을 보낼 수가 있다.

 

 

 

일단 파이썬애니웨어에서 MySQL 디비를 만든다.

 

비밀번호를 잊어버리지 않으려고 엄청 쉽게 만들었더니 아래와 같이 나온다.

 

 

아래의 화면은 생성된 디비의 정보이다.

start a console on 저 링크를 클릭하면 콘솔로 들어가져서 여러가지 쿼리를 입력 할 수 있다.

 

 

 

SQL디비로 연결하는 기존의 코드는 이와 같다.

app = Flask(__name__)
CORS(app)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///inventory.db"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True

bash 화면에서 pymysql을 설치하고 

pip install pymysql

import를 할 필요는 없다.

 

이러한 형식을 바꾸어줄것이다.

app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://username:password@localhost/db_name'
# flask sqlalchemy를 쓸 경우 추가. https://www.pythonanywhere.com/forums/topic/11116/
# 안쓰니 서버가 멈쳐버림
app.config['SQLALCHEMY_ENGINE_OPTIONS'] = {'pool_recycle' : 280}

 

 

이런식으로 들어가게 될 것이다. 

 

app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://seansoft:bbc123456@seansoft.mysql.pythonanywhere-services.com/seansoft$default'

 

깃이나 파일을 직접 올린뒤 WEB 메뉴에서 리로드를 한다.

 

bash console에 들어가 show tables를 치니 테이블들이 생성됨을 볼 수 있다.

 

row가 잘 생성됬는지 보기 위해선 

select count(*) from 테이블이름

 

 

자료 

플라스크 sqlalchemy 연결

https://stackoverflow.com/questions/27766794/switching-from-sqlite-to-mysql-with-flask-sqlalchemy

 

 

댓글()

1) 플라스크 api 서버 pythonanywhere에 배포

Computer 관심/Flask|2021. 9. 20. 22:05
반응형

그냥 과정을 나열하면 복잡하다고 느낄 수 있기 때문에

4개의 섹션으로 나누었다. 

1. 파일준비

2. 파이썬애니웨어에 파일설치

3. 파이썬애니웨어에 앱생성

4. 세팅(앱과 파일연결)

 

자신의 컴퓨터에서 해야할 부분

1. 파일준비

1) requirements.txt생성

2) 커밋한뒤 깃허브에 푸쉬하기

 

섹션 1 파일준비 끝

 

파이썬애니웨어에서 해야할 부분

2. 파일설치

1) 콘솔에 들어가 가상환경설치 (가상환경의 이름을 myvenv로 만듬)

mkvirtualenv myvenv --python=/usr/bin/python3.8

 

2) 깃에서 클론하기 

git clone https://github.com/깃이름/프로젝트이름.git

깃허브의 아이디와 비밀번호를 입력하라고 하는데 비밀번호 대신에 엑세스토큰을 붙여 넣는다.

 

3) 가상환경으로 들어가기

workon myvenv

 

파이썬 애니웨어 FILE 메뉴에 가보면 아래처럼 폴더와 파일들이 설치된 걸 볼 수 있다.

 .virtualenvs/

프로젝트명/

 

4) 패키지 설치하기 (프로젝트로 들어가 requirements.txt를 설치)

cd 프로젝트명

pip  install -r requirements.txt

 

섹션 2 파일 설치 끝

 

 

3. 앱 생성하기

이제 이렇게 설치한 파이썬파일과 연결할 앱을 만들어 주어야 한다.

1) 웹앱 만들기

웹앱이 없다고 하는데 하나 만들어줌

2) 프레임워크 선택

프래임워크를 고르라고 하는데 이미 플라스크와 가상환경을 만들었기 때문에 매뉴얼 컨피그레이션을 선택

 

3) 설치한 파이썬 버전을 선택

 

 

이렇게하면 웹앱이 생성완료

 

4. 세팅하기 

파이썬애니웨어에 올린 파이썬 파일과 방금 생성한 앱을 연결 시켜주는 것이다.

 

1) 소스코드를 연결시키기

프로젝트명 폴더명 적어줌

2) WSGI 컨피그레이션 수정

아래 링크를 클릭해서 헬로우월드 색션을 모두 지워줌

여기 부터 

여기까지 다 지워줌 

 

---------------------------

여기는 아래처럼 수정을 할 것이다.  (main.py에서 app을 가져옴)

참조 애플리케이션 팩토리 패턴을 사용한다면 

from 디렉토리네임 import app as application

아니면 함수로 실행하는 경우 app = create_app()

(플라스크팩토리팩턴)

 

2-02 플라스크 애플리케이션 팩토리

`[완성 소스]` : [github.com/pahkey/flaskbook/tree/2-02](https://github.com/pahkey/flaskbook/tree/2-0 ...

wikidocs.net

 

https://flask.palletsprojects.com/en/2.0.x/patterns/appfactories/

 

Application Factories — Flask Documentation (2.0.x)

Application Factories If you are already using packages and blueprints for your application (Modular Applications with Blueprints) there are a couple of really nice ways to further improve the experience. A common pattern is creating the application object

flask.palletsprojects.com

https://flask-sqlalchemy.palletsprojects.com/en/2.x/contexts/

 

Introduction into Contexts — Flask-SQLAlchemy Documentation (2.x)

Introduction into Contexts If you are planning on using only one application you can largely skip this chapter. Just pass your application to the SQLAlchemy constructor and you’re usually set. However if you want to use more than one application or creat

flask-sqlalchemy.palletsprojects.com

https://www.py4u.net/discuss/201960

 

How to get Flask-SQLAlchemy to work with the Application Factory Pattern

Answer #1: At the point that code is doing db.create_all(), models haven't been imported. Importing them has the side-effect of populating some data structures that SQLAlchemy uses behind the scenes. If the db.create_all() happens before SQLAlchemy knows a

www.py4u.net

 

 

 

3) 가상환경을 연결시켜주고

 

끝 실행해봄

 

이렇게 나와서 조금 놀랐지만 / 로 향하는 리퀘스트를 만들어 놓지 않아서 그런것 이였다.

작동결과 잘됬다.

 

 

※코드를 바꿔야하는 경우.

넷틀리파이에서는 깃에 푸쉬를 하면 자동으로 바뀐 코드가 적용이 되지만 

파이썬 애니웨어는 그렇지 않다. 그래서 

 

1) 소스 수정시 깃허브에 푸쉬

2) 파이썬 애니웨어에서 git pull를 한뒤 리로드를 하면 됨.

 

 

 

디비는 그냥 sqlite3를 임시로 쓰고 있는데 파이썬애니웨어에서

따로 디비를 생성할 필요가 없었다. 그냥 파일 하나가 아래 처럼 생성이된다. (아래 보이는 inventory.db는 sqlite파일이다.)

 

SQLAlchemy가 아닌를 사용하지 않고 mysql데이터베이스를 연결 하고 싶으면 아래 블로그에 잘 나와있다. 

https://seyeon-hello.tistory.com/2

 

pythonanywhere flask 배포하기

안녕하세요. 오늘은 pythonanywhere를 이용해서 파이썬 flask 웹 프레임워크를 배포하는 과정을 설명해드리겠습니다 ~ 장고는 관련 게시물이 많은데, 플라스크는 찾기 어렵더라구요. 그래서 간단하게

seyeon-hello.tistory.com

 

 

 

다음 글은 SQLAlchemy를 사용하여 my-sql DB를 연결하는 방법에 대해 설명하려고 한다.

 

댓글()

[생각] 코딩에 대한 생각의 전환

Computer 관심/이것저것|2021. 9. 11. 12:32
반응형

프로그래머가 아닌 많은 일반인들이 프로그래밍을 배우고 있다.

심지어 5살짜리 애기도 코딩에 대해 배운다고 하는 말을 듣고 굳이 그렇게 일찍 배울 필요가 있나 싶은 생각도 들었지만 코딩이 기초학문이 되어가고 있는 것을 느낄 수 있었다. 심지어 아이들의 교육을 걱정하는 부모님까지 코딩에 대해 기본은 알고 싶다는 이야기도 들었다.

 

문득 코딩이 글쓰는 것과 비슷한 것 같다는 생각이 들었다.

글 쓰는 것은 기본적으로 모든 사람이 배우지 않는가.

그런데 코딩도 비슷한 것 같다는 것이다.

 

나는 직업이 프로그래머가 아니지만 '간단한 코드를 만든다.'

반복되는 작업을 자동으로 하는 10줄 정도의 간단한 코드이다.

다른 직원에게 설명해주고 싶지만 배우려는 의지도 없어보인다. 

그들의 생각은 '너는 프로그래머 였으니까...'

 

그런데 코딩에도 글 처럼 수준이 존재한다.

'번득이는 아이디어를 갈겨되는 한줄의 메모'

'아무렇게나 생각을 적어되는 내 블로그 수준의 글'

'전문적인 학술지의 글'

'아마추어 소설가의 글'

'작가의 글'

 

심지어 많은 사람들은 몇 년 혹은 몇 달동안 글을 적지도 않을 것이다. 

 

전문 적인 프로그래머로서의 코드는 간결하고 읽기 좋으며 구조적으로 완벽에 가까워 보일 것이지만

일반인의 코드는 그렇지 않을 수도 있으며 그럴 필요도 없다.

 

일반인이 글을 쓰며 '내 글은 완벽해야되' 라고 생각을 하면 아무 글도 쓸 수 없는 것 처럼.

일반인이 전문적인 수준의 코드를 만들어 내려고 하면 아무것도 적을 수 없다.

하지만 일반인이 쓰는 글이 가치가 없다고 여겨지지 않는 것 처럼 

일반인이 만든 코드가 가치가 없다 말 할 수도 없다. 

 

몇줄의 파이썬 코드지만 회사에서 꽤 많은 업무 시간을 줄여줄 수 있다.

돼지우리 같은 코드로 만든 회사 홈페이지가 회사에서 꽤 중요한 역할을 할 수도 있다. 

 

글을 써야 하는데 자신이 전문가가 아니라고 글을 쓰지 않겠는가.. 

 

 

코딩을 하는게 엄청나게 다른 것을 한다고 생각하는 주변사람들도 문제이다.

사무직을 다니면서 엑셀을 쓰지 않는 사람들이 얼마나 될까?

엑셀 전문가가 아니여도 엑셀을 쓴다. 

 

코드도 딱 그 정도만 되도 쓸 수 있다.

 

 

 

댓글()

스벨트킷(sveltekit) 넷틀리파이 호스팅하기

Computer 관심/Svelte|2021. 4. 29. 16:16
반응형

스벨트를 사용하면 쉽게 웹사이트를 만들수 있다.

 

호스팅은 하는법은

 

1. netlify.toml 파일을 만든뒤 다음을 입력

[build]
  command = "npm run build"
  publish = "build/"
  functions = "functions/"

 

2. 패키지 설치

npm i -D @sveltejs/adapter-netlify@next

 

 

3. svelte.config.js 파일 수정

/** @type {import('@sveltejs/kit').Config} */
import adapter from '@sveltejs/adapter-netlify'
const config = {
	kit: {
		// hydrate the <div id="svelte"> element in src/app.html
		target: '#svelte',
    adapter: adapter()
	}
};

export default config;

 

4. 깃을 사용해서 깃허브에 올림

1) git init

2) git add --all

3) git commit m"메시지"

4) git remote add origin https://github.com/계정명/프로젝트명 

5) git push origin master 

 

다른 방법

이걸 클릭해서 올림

 

5. 넷틀리파이 홈페이지에서 깃프로젝트와 연결 (간단함)

 

 

 

dev.to/danawoodman/deploying-a-sveltekit-app-to-netlify-5dc3

 

Deploying a SvelteKit app to Netlify

Want to deploy your SvelteKit app to Netlify? Well, you're in luck because it's actually quite easy!...

dev.to

 

 

 

 

 

추가 - 7월 13일 2021

 

다시 해보니 안된다. 

넷틀리파이에서 node버전을 수정해야했다. 아래 처럼 Enviroment variables에 NODE_VERSION을 16으로 추가해준다.

그뒤

 

문제에 따라서 로컬에서 빌드를 먼저 한뒤 생성된 파일들을 깃에 올린뒤 넷틀리파이에서 끌어와 호스팅 해야 할 수도 있다.

댓글()

[생각] 재사용 컴포넌트에 구현에 대한 생각

Computer 관심/이것저것|2021. 1. 6. 01:06
반응형

리액트의 프레젠테이션 컴포넌트와 컨테이너 컴포넌트를 보고

컴포넌트의 재사용에 대한 방식을 생각해 보았다. 

 

이렇게 재미있는 방식을 왜 아직도 몰랐었나 싶다.

개념이 재미있어 그림으로 그려보려고 한다.

 

 

재활용 할 수 있는 프레젠테이션 컴포넌트에 

각각 목적에 다른 데이터를 넣어주면 

용도에 맞는 컴포넌트가 만들어진다.

 

만약 컨테이너 없이 로직과 데이터를 메인에서 재사용할 컴포넌트에 넣어주게 된다면 

메인공간이 지저분해 질 것이다.

 

 

댓글()

[svelte] 스벨트 패키지 만들기

Computer 관심/Svelte|2020. 12. 23. 01:54
반응형

자신이 만든 패키지를 다른 사람과 공유할 수 있다면 만든거에 대한 보람을 느낄 수 있을 것 같다.

그리고 좋은 패키지들이 많이 생기면 스벨트에 더 많은 유저들이 관심을 가질 수 있을 것이다. 

 

그래서 패키지를 만드는 방법을 찾아봤다. 정보가 많지 않았지만 좋은 블로그 포스팅이 있어서 테스트 해본 뒤 안되는건 수정해서 작성하였다.

 

아래의 블로그를 참고 하여 작성함

dev.to/agustinl/creating-a-package-for-svelte-262n

 

 

1. 패키지 파일 생성

npm init -y

이 명령어를 사용하면 package.json파일을 생성할 수 있다.

 

 

 

2. 패키지 파일 정보 채우기

   {
      "name": "",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo "Error: no test specified" && exit 1"
      },
      "keywords": [],
      "author": "",
      "license": "ISC"
    }

생성된 package.json파일의 name, description, keywords, author, license 부분을 체운다.

 

 

 

3. 스벨트 관련 디팬던시 추가

npm install -D rollup rollup-plugin-node-resolve rollup-plugin-svelte svelte

 

패키지파일에 아래와 같이 추가가 된다.

 

    "devDependencies": {
        "rollup": "^1.28.0",
        "rollup-plugin-node-resolve": "^5.2.0",
        "rollup-plugin-svelte": "^5.1.1",
        "svelte": "^3.16.7"
    }

 

 

 

4. index.js파일 만들기

 

src폴더를 만들고 그 안에 index.js 파일을 만든다.

index.js 파일에서 사용할 컴포넌트를 export 할 것이다.

 

 

 

5. index.js에 사용할 컴포넌트 export하기

export { default as Calendar } from './Calendar.svelte';

 

즉, index.js 파일이 위치한 폴더에 Calender.svelte파일을 찾아서 익스폴트 해주는 것.

 

 

 

6. package.json파일을 이와 같이 수정해준다.

    "main": "dist/index.js",
    "module": "dist/index.mjs",
    "svelte": "src/index.js",
    "scripts": {
        "build": "rollup -c",
        "dev": "rollup -c -w"
    },

 

 

7. rollup.config.js파일 만들기

 import svelte from 'rollup-plugin-svelte';
    import resolve from 'rollup-plugin-node-resolve';

    const pkg = require('./package.json');

    export default {
        input: 'src/index.js',
        output: [
            { file: pkg.module, 'format': 'en' },
            { file: pkg.main, 'format': 'umd', name: 'Name' }
        ],
        plugins: [
            svelte(),
            resolve()
        ],
    };

 

 

 

8. 로컬에서 테스트하기

 

사용할 스벨트 프로젝트 폴더에서

npm link 만든패키지 경로 복붙

 

 

 

9. npm에 퍼블리쉬

 

위의 링크에 방법 나옴.

1. npm 로그인

npm adduser

2. 퍼블리쉬

npm publish

 

주의 패키지의 이름이 중복되면 퍼블리쉬가 안됨

 

 

이제 로컬에서 설치한 패키지를 지우고 (npm uninstall 패키지명)

npm에서 받아서 되나 테스트 해보자. (npm install 패키지명)

댓글()

[Svelte] firebase로 svelte 호스팅하기

Computer 관심/Svelte|2020. 12. 19. 00:44
반응형

netlify를 사용해서 호스팅을 할까 firebase로 호스팅 할까 생각하다.

더 익숙한 firebase로 호스팅을 해보기로 하였다.

 

 

1. firebase tools 설치 하기

npm install -g firebase-tools

 

 

2. 호스팅 관련 정보 초기화 (init) 하기

firebase init hosting

이렇게 클릭하면 질문들이 나온다.

(1) Are you ready to proceed? (진행 준비가 됬나요?) 엔터

 

(2)

use an existing project 이미 프로젝트가 있는경우

Create a new project 프로젝트를 새로 만들경우 선택

 

(3) What do you want to use as your public directory?(퍼블릭디렉토리로 사용할 것은?) 

퍼블릭폴더로 사용할 폴더명을 적음

 

(4) configure as a single page app? (싱글페이지로 세팅을 할건가요?)

Y 싱글페이지로 만들었는데 N을 선택하면 동적 라우팅??? (블로그처럼 /subject1 /subject2이렇게 만드는것) 불가

 

(5) Set up automatic builds and deploys with GitHub? (깃으로 자동빌드디플로이를 세팅할것이냐)

N 깃으로 배포할 것이면 Y

 

(6) (주의!!) file public/index.html already exists. Overwrite? (이미 public 폴더에 index.html파일이 있는데 덮어쓸꺼냐)

N 덮어쓰면 안됨

 

 

3. 디플로이 하기

firebase deploy --only hosting

 

 

데모

svelte-deploy.web.app

 

 

댓글()

자바스크립트 슬라이더 스벨트로 바꾸기(Javascript to Svelte slider)

Computer 관심/Svelte|2020. 12. 14. 23:31
반응형

스벨트로 슬라이더 컴포넌트를 만들어보면 재미있을 것 같았다. 직접 만들면 디자인이 좋지 않을 것 같아서

자바스크립트로 만들어진 슬라이더를 인터넷에서 찾아 스벨트 컴포넌트로 바꾸어 보았다.

 

www.w3schools.com/howto/howto_js_slideshow.asp

 

html

Original 

<!-- Slideshow container -->
<div class="slideshow-container">

  <!-- Full-width images with number and caption text -->
  <div class="mySlides fade">
    <div class="numbertext">1 / 3</div>
    <img src="img1.jpg" style="width:100%">
    <div class="text">Caption Text</div>
  </div>

  <div class="mySlides fade">
    <div class="numbertext">2 / 3</div>
    <img src="img2.jpg" style="width:100%">
    <div class="text">Caption Two</div>
  </div>

  <div class="mySlides fade">
    <div class="numbertext">3 / 3</div>
    <img src="img3.jpg" style="width:100%">
    <div class="text">Caption Three</div>
  </div>

  <!-- Next and previous buttons -->
  <a class="prev" onclick="plusSlides(-1)">&#10094;</a>
  <a class="next" onclick="plusSlides(1)">&#10095;</a>
</div>
<br>

<!-- The dots/circles -->
<div style="text-align:center">
  <span class="dot" onclick="currentSlide(1)"></span>
  <span class="dot" onclick="currentSlide(2)"></span>
  <span class="dot" onclick="currentSlide(3)"></span>
</div>

 

Svelte 

<!-- Slideshow container -->
<div class="slideshow-container">
  {#each slideData as slide}
  <!-- Full-width images with number and caption text -->
  <div class="fade {slide.show ? '':'mySlides'}">
    <div class="numbertext">{slide.id+1} / {slides.length}</div>
    <img src={slide.src} style="width:100%" alt="img_nature_wide">
    <div class="text">{slide.caption}</div>
  </div>
  {/each}

  <!-- Next and previous buttons -->
  <span class="prev" on:click={() => plusSlides(-1)}>&#10094;</span>
  <span class="next" on:click={() => plusSlides(+1)}>&#10095;</span>
</div>
<br>

<!-- The dots/circles -->
<div style="text-align:center">
  {#each slideData as slide}
  <span class="dot {slide.show==true?'active':''}" on:click={()=>currentSlide(slide)}></span>
  {/each}
</div>

 


Javascript

original

var slideIndex = 1;
showSlides(slideIndex);

// Next/previous controls
function plusSlides(n) {
  showSlides(slideIndex += n);
}

// Thumbnail image controls
function currentSlide(n) {
  showSlides(slideIndex = n);
}

function showSlides(n) {
  var i;
  var slides = document.getElementsByClassName("mySlides");
  var dots = document.getElementsByClassName("dot");
  if (n > slides.length) {slideIndex = 1}
  if (n < 1) {slideIndex = slides.length}
  for (i = 0; i < slides.length; i++) {
      slides[i].style.display = "none";
  }
  for (i = 0; i < dots.length; i++) {
      dots[i].className = dots[i].className.replace(" active", "");
  }
  slides[slideIndex-1].style.display = "block";
  dots[slideIndex-1].className += " active";
}

 

svelte

var slideIndex = 0;

let slideData =[{
  id:0,
  caption:'안녕하세요.',
  src:'https://www.w3schools.com/howto/img_nature_wide.jpg',
  show:false
  },{
  id:1,
  caption:'방갑습니다.',
  src:'https://www.w3schools.com/howto/img_snow_wide.jpg',
  show:false
  },{
  id:2,
  caption:'여기에요.',
  src:'https://www.w3schools.com/howto/img_lights_wide.jpg',
  show:false
  }
]

slideData[slideIndex].show = true

// Next/previous controls
function plusSlides(value) {
  let num = slideIndex + value
  slideData[slideIndex].show = false
  if (num == slides.length){
  slideIndex = 0
  } else if(num < 0){
  slideIndex = slides.length+value
  } else {
  slideIndex = num
  }
  slideData[slideIndex].show = true
}

// Thumbnail image controls
function currentSlide(obj) {
  slideData[slideIndex].show = false
  slideIndex =obj.id
  slideData[slideIndex].show = true
}

 


Style

style은 바뀐게 없음

* {box-sizing:border-box}

/* Slideshow container */
.slideshow-container {
  max-width: 1000px;
  position: relative;
  margin: auto;
}

/* Hide the images by default */
.mySlides {
  display: none;
}

/* Next & previous buttons */
.prev, .next {
  cursor: pointer;
  position: absolute;
  top: 50%;
  width: auto;
  margin-top: -22px;
  padding: 16px;
  color: white;
  font-weight: bold;
  font-size: 18px;
  transition: 0.6s ease;
  border-radius: 0 3px 3px 0;
  user-select: none;
}

/* Position the "next button" to the right */
.next {
  right: 0;
  border-radius: 3px 0 0 3px;
}

/* On hover, add a black background color with a little bit see-through */
.prev:hover, .next:hover {
  background-color: rgba(0,0,0,0.8);
}

/* Caption text */
.text {
  color: #f2f2f2;
  font-size: 15px;
  padding: 8px 12px;
  position: absolute;
  bottom: 8px;
  width: 100%;
  text-align: center;
}

/* Number text (1/3 etc) */
.numbertext {
  color: #f2f2f2;
  font-size: 12px;
  padding: 8px 12px;
  position: absolute;
  top: 0;
}

/* The dots/bullets/indicators */
.dot {
  cursor: pointer;
  height: 15px;
  width: 15px;
  margin: 0 2px;
  background-color: #bbb;
  border-radius: 50%;
  display: inline-block;
  transition: background-color 0.6s ease;
}

.active, .dot:hover {
  background-color: #717171;
}

/* Fading animation */
.fade {
  -webkit-animation-name: fade;
  -webkit-animation-duration: 1.5s;
  animation-name: fade;
  animation-duration: 1.5s;
}

@-webkit-keyframes fade {
  from {opacity: .4}
  to {opacity: 1}
}

@keyframes fade {
  from {opacity: .4}
  to {opacity: 1}
}

 

댓글()