瀏覽代碼

feat: 基本单词显示功能

SongZihuan 3 年之前
父節點
當前提交
c9e77cfeaf
共有 19 個文件被更改,包括 479 次插入3207 次删除
  1. 1 1
      app/__init__.py
  2. 60 0
      app/app.py
  3. 80 5
      app/home.py
  4. 15 0
      app/test.py
  5. 72 0
      app/user.py
  6. 0 20
      app/view.py
  7. 13 2
      configure/__init__.py
  8. 38 6
      core/db.py
  9. 0 1
      core/user.py
  10. 3 2
      core/word.py
  11. 1 1
      main.py
  12. 0 3156
      resource/English-Word.txt
  13. 二進制
      resource/template/base.db
  14. 0 0
      resource/template/high_school.db
  15. 0 0
      static/base.css
  16. 39 0
      templates/base.html
  17. 78 13
      templates/index.html
  18. 9 0
      templates/not_word.html
  19. 70 0
      templates/test.html

+ 1 - 1
app/__init__.py

@@ -1 +1 @@
-from . import view
+from .app import *

+ 60 - 0
app/app.py

@@ -0,0 +1,60 @@
+from flask import Flask
+from flask.logging import default_handler
+from flask_login import LoginManager
+import configure
+from . import home
+from . import test
+from . import user
+import logging.handlers
+import logging
+import os
+import sys
+
+
+class HEnglishFlask(Flask):
+    def __init__(self, import_name, **kwargs):
+        super().__init__(import_name, **kwargs)
+
+        self.logger: logging.Logger
+        self.logger.removeHandler(default_handler)
+        self.logger.propagate = False
+        self.logger.setLevel({"DEBUG": logging.DEBUG,
+                              "INFO": logging.INFO,
+                              "WARNING": logging.WARNING,
+                              "ERROR": logging.ERROR}.get(configure.conf["LOG_LEVEL"], logging.INFO))
+        if len(configure.conf["LOG_HOME"]):
+            handle = logging.handlers.TimedRotatingFileHandler(
+                os.path.join(configure.conf["LOG_HOME"], f"flask-{os.getpid()}.log"))
+            handle.setFormatter(logging.Formatter("%(levelname)s:%(name)s:%(asctime)s "
+                                                  "(%(filename)s:%(lineno)d %(funcName)s) "
+                                                  "%(process)d %(thread)d "
+                                                  "%(message)s"))
+            self.logger.addHandler(handle)
+        if configure.conf["LOG_STDERR"]:
+            handle = logging.StreamHandler(sys.stderr)
+            handle.setFormatter(logging.Formatter("%(levelname)s:%(name)s:%(asctime)s "
+                                                  "(%(filename)s:%(lineno)d %(funcName)s) "
+                                                  "%(process)d %(thread)d "
+                                                  "%(message)s"))
+            self.logger.addHandler(handle)
+
+        self.update_config()
+        self.login_manager = LoginManager()
+        self.login_manager.init_app(self)
+        self.login_manager.anonymous_user = user.AnonymousUser  # 设置未登录的匿名对象
+
+        @self.context_processor
+        def inject_base():
+            return {"title": self.config["TITLE"],
+                    "about": self.config["ABOUT"]}
+
+        @self.login_manager.user_loader
+        def user_loader(name: str):
+            return user.load_user(name, None)
+
+        self.register_blueprint(home.home, url_prefix="/")
+        self.register_blueprint(test.test, url_prefix="/test")
+
+    def update_config(self):
+        self.config.update(configure.conf)
+        self.logger.info("Update config")

+ 80 - 5
app/home.py

@@ -1,10 +1,85 @@
-import flask.blueprints
-import flask
+from flask import blueprints, url_for, request, redirect, render_template, flash, current_app, abort
+from flask_login import login_user, current_user
+from flask_wtf import FlaskForm
+from wtforms import StringField, PasswordField, BooleanField, SubmitField, ValidationError
+from wtforms.validators import DataRequired, Length, EqualTo
+from .user import load_user, create_user, check_template
 
 
 
 
-home = flask.blueprints.Blueprint("home", __name__)
+class LoginForm(FlaskForm):
+    name = StringField("User name", validators=[DataRequired(), Length(1, 32)])
+    passwd = PasswordField("Passwd", validators=[DataRequired(), Length(4, 32)])
+    remember = BooleanField("Remember me")
+    submit = SubmitField("Login")
 
 
 
 
-@home.route("/")
+class RegisterForm(FlaskForm):
+    name = StringField("User name", validators=[DataRequired(), Length(1, 32)])
+    template = StringField("Template name", validators=[Length(0, 32)])
+    passwd = PasswordField("Passwd", validators=[DataRequired(),
+                                                 EqualTo("passwd_again", message="两次输入密码不相同"),
+                                                 Length(4, 32)])
+    passwd_again = PasswordField("Passwd again", validators=[DataRequired()])
+    submit = SubmitField("register")
+
+    def validate_name(self, field):
+        if load_user(field.data, None) is not None:
+            raise ValidationError("User is already exist")
+
+    def validate_template(self, field):
+        if not check_template(field.data):
+            raise ValidationError("Template not exist")
+
+
+home = blueprints.Blueprint("home", __name__)
+
+
+@home.route("/", methods=["GET"])
 def index():
 def index():
-    return flask.render_template("index.html")
+    if not current_user.is_anonymous:
+        return redirect(url_for("test.question"))
+    return render_template("index.html", login_form=LoginForm(), register_form=RegisterForm())
+
+
+@home.route("/login", methods=["POST"])
+def login():
+    if not current_user.is_anonymous:
+        current_app.logger.debug(f"re-login and abort(304)")
+        abort(304)
+
+    login_form = LoginForm()
+    if login_form.validate_on_submit():
+        user = load_user(login_form.name.data, login_form.passwd.data)
+        if user is not None:
+            login_user(user, login_form.remember.data)
+            next_page = request.args.get("next")
+            if next_page is None or not next_page.startswith('/'):
+                next_page = url_for('home.index')
+            flash("Login success")
+            current_app.logger.info(f"{login_form.name.data} login success")
+            return redirect(next_page)
+        flash("Login fail")
+        current_app.logger.debug(f"{login_form.name.data} login fail")
+    return redirect(url_for("home.index"))
+
+
+@home.route("/register", methods=["POST"])
+def register():
+    if not current_user.is_anonymous:
+        current_app.logger.debug(f"re-login and register(304)")
+        abort(304)
+
+    register_form = RegisterForm()
+    if register_form.validate_on_submit():
+        template = register_form.template.data
+        if len(template) == 0:
+            template = "base"
+        flat, user = create_user(template, register_form.name.data, register_form.passwd.data)
+        if user is not None:
+            current_app.logger.debug(f"{register_form.name.data} with {register_form.template.data} register success")
+            flash("Register success")
+        else:
+            current_app.logger.debug(
+                f"{register_form.name.data} with {register_form.template.data} register fail [{flat}]")
+            flash("Register fail")
+    return redirect(url_for("home.index"))

+ 15 - 0
app/test.py

@@ -0,0 +1,15 @@
+from flask import blueprints, render_template
+from flask_login import current_user, login_required
+from .user import UserWordDataBase
+
+test = blueprints.Blueprint("test", __name__)
+
+
+@test.route("/")
+@login_required
+def question():
+    user: UserWordDataBase = current_user
+    word = user.rand_word()
+    if word is None:
+        return render_template("not_word.html")
+    return render_template("test.html", word=word, len=len)  # 需要使用len函数

+ 72 - 0
app/user.py

@@ -0,0 +1,72 @@
+from core.db import WordDatabase
+from werkzeug.security import generate_password_hash, check_password_hash
+import os
+from configure import conf
+from flask_login import UserMixin, AnonymousUserMixin
+import shutil
+
+
+class AnonymousUser(AnonymousUserMixin):
+    ...
+
+
+class UserWordDataBase(WordDatabase, UserMixin):
+    def __init__(self, user: str, path: str):
+        super().__init__(user, path)
+        self.done(f'''
+                CREATE TABLE IF NOT EXISTS User (
+                    id INTEGER PRIMARY KEY AUTOINCREMENT,  -- 记录ID
+                    passwd TEXT NOT NULL  -- 密码hash
+                )''')
+        self.insert(table="User", columns=["passwd"], values=f"'{generate_password_hash('88888888')}'")  # 默认密码
+        self.user = user
+
+    def get_id(self):
+        return self.user
+
+    def check_passwd(self, passwd: str) -> bool:
+        res = self.search(table="User", columns=["passwd"], limit=1, order_by=[("ID", "ASC")])
+        if len(res) == 0:
+            return False
+        return check_password_hash(res[0][0], passwd)
+
+    def set_passwd(self, passwd: str, record_id: int = 1):
+        self.update(table="User", kw={"passwd": f"'{generate_password_hash(passwd)}'"}, where=f"id = {record_id}")
+
+    def delete_user(self):
+        self.delete_self()
+
+
+def check_base_db():
+    if os.path.exists(os.path.join(conf["DB_TEMPLATE"], "base.db")):
+        return
+    WordDatabase("base", conf["DB_TEMPLATE"])
+
+
+def check_template(template: str) -> bool:
+    check_base_db()
+    return os.path.exists(os.path.join(conf["DB_TEMPLATE"], f"{template}.db"))
+
+
+def create_user(template: str, name: str, passwd: str):
+    check_base_db()
+    if not os.path.exists(os.path.join(conf["DB_TEMPLATE"], f"{template}.db")):
+        return 0, None
+    if os.path.exists(os.path.join(conf["DB_PATH"], f"{name}.db")):
+        return -1, None
+
+    shutil.copy(os.path.join(conf["DB_TEMPLATE"], f"{template}.db"), os.path.join(conf["DB_PATH"], f"{name}.db"))
+    user = UserWordDataBase(name, conf["DB_PATH"])
+    if len(passwd) > 0:
+        user.set_passwd(passwd)
+    return 1, user
+
+
+def load_user(name: str, passwd: str | None):
+    if not os.path.exists(os.path.join(conf["DB_PATH"], f"{name}.db")):
+        return None
+    user = UserWordDataBase(name, conf["DB_PATH"])
+    if passwd is None or user.check_passwd(passwd):
+        return user
+    return None
+

+ 0 - 20
app/view.py

@@ -1,20 +0,0 @@
-from flask import Flask
-import configure
-from . import home
-
-
-class HEnglishFlask(Flask):
-    def __init__(self, import_name, **kwargs):
-        super().__init__(import_name, **kwargs)
-        self.update_config()
-
-        @self.context_processor
-        def inject_base():
-            return {"title": self.config["TITLE"],
-                    "about": self.config["ABOUT"]}
-
-        self.register_blueprint(home.home, url_prefix="/")
-
-    def update_config(self):
-        self.config.update(configure.conf)
-        self.logger.info("Update config")

+ 13 - 2
configure/__init__.py

@@ -1,9 +1,16 @@
 import json
 import json
+import os
 
 
+root = os.path.abspath(os.path.join(__file__, '..', '..'))
 conf = {
 conf = {
-    "SECRET_KET": "HEnglish",
+    "SECRET_KEY": "HEnglish",
     "TITLE": "HEnglish :D",
     "TITLE": "HEnglish :D",
-    "ABOUT": "An useful English learning website for personal."
+    "ABOUT": "An useful English learning website for personal.",
+    "DB_TEMPLATE": f"{os.path.join(root, 'resource', 'template')}",
+    "DB_PATH": f"{os.path.join(root, 'var', 'db')}",
+    "LOG_HOME": f"{os.path.join(root, 'var', 'log')}",
+    "LOG_STDERR": True,
+    "LOG_LEVEL": "DEBUG",
 }
 }
 
 
 
 
@@ -12,3 +19,7 @@ def configure(file_path: str, encoding: str = "utf-8"):
         json_str = f.read()
         json_str = f.read()
         _conf: dict = json.loads(json_str)
         _conf: dict = json.loads(json_str)
         conf.update(_conf)
         conf.update(_conf)
+
+    os.makedirs(conf["DB_TEMPLATE"], exist_ok=True)
+    os.makedirs(conf["DB_PATH"], exist_ok=True)
+    os.makedirs(conf["LOG_HOME"], exist_ok=True)

+ 38 - 6
core/db.py

@@ -2,19 +2,27 @@ import sqlite3
 from typing import Optional, Union, List, Tuple, Dict
 from typing import Optional, Union, List, Tuple, Dict
 import logging
 import logging
 import pandas
 import pandas
-import word
+from . import word
 import re
 import re
 import os
 import os
+import random
+import configure
 
 
 
 
 class DataBase:
 class DataBase:
-    __logger = logging.getLogger("database")
-    __logger.propagate = False
+    __logger = logging.getLogger("main.database")
+    __logger.setLevel({"DEBUG": logging.DEBUG,
+                       "INFO": logging.INFO,
+                       "WARNING": logging.WARNING,
+                       "ERROR": logging.ERROR}.get(configure.conf["LOG_LEVEL"], logging.INFO))
 
 
     def __init__(self, name, path: str = ""):
     def __init__(self, name, path: str = ""):
         self._db_name = os.path.join(path, f"{name}.db")
         self._db_name = os.path.join(path, f"{name}.db")
         self.__logger.info(f"Mark {self._db_name}")
         self.__logger.info(f"Mark {self._db_name}")
 
 
+    def delete_self(self):
+        os.remove(self._db_name)
+
     def search(self, columns: List[str], table: str,
     def search(self, columns: List[str], table: str,
                where: Union[str, List[str]] = None,
                where: Union[str, List[str]] = None,
                limit: Optional[int] = None,
                limit: Optional[int] = None,
@@ -117,10 +125,10 @@ class DataBase:
 
 
 class WordDatabase(DataBase):
 class WordDatabase(DataBase):
     word_pattern = re.compile("([a-zA-Z\']+)")  # 匹配英语单词
     word_pattern = re.compile("([a-zA-Z\']+)")  # 匹配英语单词
-    __logger = logging.getLogger("database.dict")
+    __logger = logging.getLogger("main.database.dict")
 
 
-    def __init__(self, dict_name: str = "global"):
-        super(WordDatabase, self).__init__(dict_name + "-dict")
+    def __init__(self, dict_name, path: str = ""):
+        super(WordDatabase, self).__init__(dict_name, path)
         self.dict_name = dict_name
         self.dict_name = dict_name
         self.done(f'''
         self.done(f'''
         CREATE TABLE IF NOT EXISTS Word (
         CREATE TABLE IF NOT EXISTS Word (
@@ -274,3 +282,27 @@ class WordDatabase(DataBase):
         self.__logger.debug(f"delete all word")
         self.__logger.debug(f"delete all word")
         cur = self.delete(table="Word")
         cur = self.delete(table="Word")
         return cur[1].rowcount
         return cur[1].rowcount
+
+    def rand_word(self):
+        r = random.randint(0, 16)
+        if r < 5:
+            box = 2
+        elif r < 9:
+            box = 3
+        elif r < 12:
+            box = 4
+        elif r < 14:
+            box = 5
+        else:
+            box = 6
+        # box 的概率比分别为:5:4:3:2:1
+
+        count = 0
+        while count == 0:
+            if box == 1:
+                return None
+            box -= 1
+            count = self.search(columns=["COUNT(ID)"], table="Word", where=f"box={box}")[0][0]
+        get = self.search(columns=["word"], table="Word", limit=1, offset=random.randint(0, count))[0][0]
+        self.__logger.debug(f"Rand word {self.dict_name} from box: {box} count: {count} get: {get}")
+        return self.find_word(get)

+ 0 - 1
core/user.py

@@ -1 +0,0 @@
-from . import db

+ 3 - 2
core/word.py

@@ -127,8 +127,6 @@ class Response:
 
 
 
 
 class Word:
 class Word:
-    __logger.propagate = False
-
     class Comment:
     class Comment:
         def __init__(self, part: str, english: str, chinese: str):
         def __init__(self, part: str, english: str, chinese: str):
             self.part = part   # 词性
             self.part = part   # 词性
@@ -137,6 +135,9 @@ class Word:
             self.eg = []
             self.eg = []
 
 
         def add_eg(self, eg: str):
         def add_eg(self, eg: str):
+            eg = eg.strip()
+            if eg == "##":
+                return
             self.eg.append(eg)
             self.eg.append(eg)
 
 
         def __str__(self):
         def __str__(self):

+ 1 - 1
main.py

@@ -1,5 +1,5 @@
 import configure
 import configure
 import app as App
 import app as App
 
 
-app = App.view.HEnglishFlask(__name__)
+app = App.HEnglishFlask(__name__)
 
 

+ 0 - 3156
resource/English-Word.txt

@@ -1,3156 +0,0 @@
-addict
-accent
-accept
-addition
-access
-address
-adjust
-accident
-accommodation
-administration
-accompany
-admire
-accord
-to
-admit
-account
-adopt
-adorable
-accurate
-accuse
-adult
-ache
-advance
-achieve
-advantage
-achievement
-adventure
-acid
-advertise
-acknowledge
-advertisement
-ad
-acquire
-advice
-across
-advise
-act
-advocate
-action
-affair
-active
-affect
-activity
-afford
-actor
-afraid
-actress
-africa
-actually
-african
-adapt
-after
-after-
-afternoon
-adaptation
-afterwards
-add
-again
-against
-age
--age
-always
-agency
-agenda
-amateur
-ago
-amazing
-agree
-ambition
-agreement
-ambitious
-agriculture
-ambulance
-ahead
-america
-aid
-american
-aim
-among
-air
-amount
-amuse
-airline
-airport
-analyse
-analyze
-alarm
-ancestor
-alcohol
-ancient
-alive
-and
-anger
-all
-all-
-allow
-angle
-almost
-angry
-alone
-animal
-along
-alongside
-announce
-aloud
-annoy
-already
-annual
-also
-another
-alternative
-answer
-although
-ant
--ant
-antique
-anticipate
-april
-arch
-arch-
-anxiety
-architect
-anxious
-area
-any
-anybody
-argue
-anyhow
-arm
-arise
-anyone
-army
-anything
-around
-anyway
-arrangement
-anywhere
-arrest
-arrive
-apartment
-arrow
-apologize
-art
-apparently
-article
-appeal
-artificial
-appear
-artist
-appetite
-applaud
-as
-ashamed
-apple
-asia
-applicant
-asian
-application
-apply
-aside
-ask
-appointment
-asleep
-appreciate
-approach
-aspect
-appropriate
-assess
-approve
-assign
-assistant
-available
-association
-average
-assume
-avoid
-assumption
-awake
-astonish
-award
-astronaut
-aware
-astronomer
-at
-away
-awesome
-athlete
-awful
-atmosphere
-awkward
-attach
-b
-b.
-attack
-baby
-attain
-attempt
-back
-background
-attend
-attention
-backward
-attitude
-bacon
-attract
-bad
-audience
-badminton
-august
-bag
-aunt
-bakery
-australia
-balance
-australian
-ball
-author
-ballet
-authority
-balloon
-automatic
-bamboo
-autonomous
-ban
-banana
-autumn
-band
-bank
-beautiful
-bar
-the bar
-beauty
-barbecue
-because
-barely
-become
-bark
-bed
-barrier
-bedroom
-base
-beef
-baseball
-beer
-before
-basic
-begin
-basis
-basin
-behalf
-behave
-basket
-behaviour
-basketball
-behind
-bat
-bath
-being
-belief
-bathroom
-believe
-battery
-bell
-battle
-belong
-bay
-below
-bc
-belt
-beach
-be
-am
-a.m.
-are
-is
-bend
-beneath
-bean
-benefit
-curd
-tofu
-beside
-bear
-best
-beard
-bet
-beat
-better
-between
-board
-beyond
-big
-boat
-body
-bill
-the bill
-bike
-bicycle
-boil
-bomb
-billion
-d, d
-bond
-bird
-biology
-bone
-birth
-bonus
-book
-birthday
-boost
-biscuit
-boot
-bit
-border
-bite
-bored
-bitter
-boring
-black
-born
--born
-blackboard
-borrow
-blame
-boss
-blank
-botanical
-blanket
-both
-bleed
-bother
-bless
-bottle
-blind
-bottom
-block
-bounce
-bound
--bound
-blood
-boundary
-blouse
-bow
-blow
-bowl
-blue
-bowling
-box
-buffet
-boxing
-build
-boy
-building
-brain
-bunch
-branch
-burn
-brave
-bury
-bread
-bus
-break
-business
-breakfast
-busy
-breath
-breast
-but
-butcher
-breathe
-butter
-brick
-button
-bride
-bridegroom
-buy
-bridge
-by
-bright
-c.
-c++
-brilliant
-cabbage
-bring
-café
-britain
-cafeteria
-british
-broad
-cake
-cage
-broadcast
-calculate
-brochure
-calendar
-brother
-brown
-call
-calligraphy
-brush
-calm
-budget
-the budget
-calorie
-camel
-camera
-camp
-carrot
-campaign
-carry
-campus
-can
-carve
-canada
-case
-canadian
-cash
-cancel
-canal
-cast
-castle
-cancer
-cat
-candidate
-catch
-candle
-category
-candy
-canteen
-cause
-cap
-cave
-capable
--capable
-cease
-ceiling
-capacity
-celebrate
-capital
-capsule
-celebrity
-captain
-cell
-cent
-centimetre
-car
-carbon
-central
-card
-centre
-center
-care
-century
-career
-certain
-careful
-certainly
-careless
-certificate
-chain
-chair
-chairwoman
-chicken
-chew
-chalk
-challenge
-child
-pl.
-champion
-chance
-china
-change
-channel
-chinese
-chaos
-chocolate
-chapter
-choice
-character
-choke
-characteristic
-charity
-charge
-chorus
-christmas
-chopstick
-chart
-chat
-church
-cheap
-cinema
-cigarette
-s
-'s
--s
--s'
--'s
-cheat
-check
-circle
-cheek
-circuit
-circumstance
-cheer
-cheese
-circus
-chef
-cite
-citizen
-chemical
-city
-chemist
-civil
-chemistry
-civilian
-chess
-civilization
-coast
-claim
-clap
-coat
-coffee
-clarify
-class
-coin
-cold
-classic
-classmate
-collapse
-classroom
-collar
-collect
-clean
-collection
-clear
-college
-colour
-color
-clerk
-clever
-column
-combine
-click
-client
-come
-comedy
-climate
-climb
-comfort
-clinic
-comfortable
-comic
-clone
-comment
-close
-commercial
-commit
-cloth
-clothes
-commitment
-cloud
-committee
-cloudy
-common
-club
-communicate
-clue
-communication
-coach
-coal
-community
-company
-confirm
-compare
-comparison
-confucianism
-compete
-confucius
-competence
-confused
-competition
-congratulation
-complain
-connect
-complete
-complex
-conservation
-complicated
-consider
-component
-compose
-consistent
-composition
-constant
-comprehension
-constitution
-comprehensive
-construction
-comprise
-consultant
-computer
-consultation
-concentrate
-consume
-concept
-consumption
-concern
-contact
-concert
-contain
-conclude
-contemporary
-conclusion
-content
-concrete
-contest
-condition
-context
-conduct
-continent
-the continent
-conference
-continue
-confidence
-contract
-contradictory
-country
-contrary
-countryside
-county
-contrast
-contribution
-couple
-courage
-control
-convenient
-course
-court
-conventional
-cousin
-conversation
-cover
-convince
-cook
-coverage
-cookie
-cow
-crash
-cool
-crayon
-cooperate
-copy
-crazy
-cream
-core
-corn
-create
-comer
-creative
-creature
-corporate
-correct
-credit
-crew
-correspond
-cost
-crime
-crisis
-costume
-cottage
-criterion
-critical
-cotton
-cough
-criticize
-could
-crop
-council
-cross
-cross-
-crowd
-crucial
-date
-cry
-daughter
-cuisine
-day
-culture
-dead
-deadline
-cup
-cupboard
-deaf
-cure
-deal
-dear
-curious
-death
-current
-debate
-curtain
-debt
-custom
-custom-
-decade
-customer
-december
-cut
-decent
-cute
-decide
-cycle
-decision
-declare
-d.
-'d
-decline
-daily
-decorate
-damage
-decrease
-damp
-deep
-dance
-deer
-danger
-defeat
-dangerous
-defence
-defense
-dare
-defend
-dark
-definitely
-data
-definition
-degree
--degree
-database
-delay
-delete
-detective
-determine
-delicate
-develop
-delicious
-development
-device
-deliver
-demand
-demonstrate
-diagram
-dentist
-dialogue
-dialog box
-deny
-diamond
-department
-diary
-departure
-dictionary
-depend
-die
-depress
-diet
-depth
-differ
-describe
-difference
-description
-different
-desert
-difficult
-deserve
-difficulty
-design
-dig
-desire
-digest
-digital
-desk
-desperate
-dignity
-despite
-dimension
-dessert
-dine
-destination
-dinner
-destroy
-dinosaur
-detail
-direct
-detect
-direction
-director
-diverse
-directory
-divide
-dirty
-division
-disabled
-disability
-dizzy
-disappointed
-document
-disaster
-dog
-discipline
-dollar
-discount
-dolphin
-discover
-domain
-discovery
-domestic
-discrimination
-dominate
-discuss
-donate
-discussion
-door
-disease
-dormitory
-dish
-double
-disk
-disc
-doubt
-dismiss
-down
-down-
-display
-download
-distance
-downstairs
-distant
-downtown
-distinct
-dozen
-distinguish
-draft
-distribution
-drag
-district
-dragon
-disturb
-drama
-dive
-dramatic
-draw
-drawer
-earn
-dream
-earth
-earthquake
-dress
-drill
-ease
-drink
-east
-drive
-eastern
-driver
-easy
-eat
-drop
-drought
-ecology
-drug
-economic
-edge
-dry
-editor
-duck
-education
-due
-educator
-dumpling
-effect
-duration
-efficient
-during
-effort
-dust
-egg
-duty
-eight
-dynamic
-eighteen
-dynasty
-eighth
-eighty
-e, e
-either
-each
-elder
-eager
-elderly
-eagle
-election
-ear
-electricity
-early
-electronic
-treatment
-typhoon
-typical
-tree
-trial
-trend
-u, u
-ugly
-trick
-the uk
-trip
-trouble
-ultimately
-trousers
-umbrella
-truck
-uncle
-true
-under
-under-
-trunk
-underground
-trust
-understand
-truth
-uniform
-try
-unique
-t, t
-shirt
-unit
-universe
-tube
-tuesday
-university
-tune
-unless
-turkey
-until
-till
-turn
-unusual
-twelfth
-twelve
-update
-twentieth
-upon
-twenty
-twice
-twin
-upper
-upset
-urban
-two
-type
-urge
-urgent
-us
-the us
-village
-violence
-use
-violin
-used
-virtual
-useful
-virtue
-usual
-virus
-usually
-visible
-vision
-v
-visit
-vacation
-visitor
-valley
-visual
-valuable
-vital
-value
-vivid
-variation
-vocabulary
-variety
-voice
-various
-volcano
-volleyball
-vary
-vase
-volume
-vast
-volunteer
-vegetable
-vote
-vehicle
-venue
-w, w
-version
-wage
-very
-waist
-victim
-wait
-victory
-wake
-video
-walk
-view
-wall
-elegant
-enjoy
-element
-enormous
-elephant
-enough
-eleven
-ensure
-else
-enter
-elsewhere
-enterprise
-email
-entertainment
-embarrassed
-enthusiastic
-emerge
-entirely
-emergency
-entitle
-emotion
-entrance
-emperor
-emphasis
-entry
-envelope
-employ
-environment
-empty
-envy
-encounter
-episode
-equal
-encourage
-equator
-end
-equipment
-enemy
-energetic
-eraser
-error
-engage
-engagé
-engine
-erupt
-escape
-engineer
-especially
-england
-essay
-english
-essential
-enhance
-establish
-estate
-excuse
-estimate
-exercise
-europe
-exhibition
-european
-exist
-evaluate
-eve
-exit
-expand
-even
-expansion
-event
-evening
-expect
-expectation
-eventually
-expense
-ever
-expensive
-every
-experience
-everybody
-experiment
-everyday
-expert
-everyone
-explain
-everything
-explode
-everywhere
-explore
-evidence
-export
-expose
-exposé
-exactly
-exam
-examination
-exposure
-examine
-express
-extend
-example
-extension
-excellent
-except
-extent
-exceptional
-external
-exchange
-extinction
-extra
-extra-
-extraordinary
-excited
-exciting
-extremely
-fast
-eye
-fat
-f, f
-father
-dad
-fault
-fabric
-favour
-favor
-face
-favourite
-favorite
-facilitate
-fear
-facility
-feature
-fact
-february
-factor
-fee
-factory
-feed
-fail
-feel
-failure
-feeling
-fair
-fellow
-faith
-female
-fall
-fence
-false
-festival
-familiar
-fetch
-family
-fever
-famous
-few
-fan
-fibre
-fiber
-fancy
-fiction
-fantastic
-field
--field
-fantasy
-far
-fifth
-farm
-fifty
-farmer
-fight
-fashion
-figure
-file
-fill
-flour
-flow
-film
-flower
-finally
-finance
-flu
-fluent
-financial
-find
-fly
-focus
-finding
-foggy
-fine
-fold
--fold
-finger
-folk
-finish
-follow
-fire
-fond
-firm
-food
-first
-foot
-feet
-fish
-football
-fisherman
-for
-fist
-force
-fit
-forecast
-five
-forehead
-fix
-foreign
-forest
-flag
-flash
-forever
-forget
-flat
-flavour
-flavor
-forgive
-flexible
-fork
-form
-flight
-formal
-flood
-format
-floor
-former
--former
-from
-fortunately
-front
-forty
-frontier
-forward
-frost
-found
-fruit
-foundation
-fry
-fountain
-fuel
-four
-full
-fourteen
-fun
-fourth
-function
-fox
-fund
-france
-fundamental
-frank
-funny
-free
--free
-furniture
-freedom
-further
-freeze
-future
-french
-g
-frequency
-frequently
-gain
-fresh
-fresh-
-gallery
-friction
-game
-friday
-gap
-fridge
-refrigerator
-garbage
-friend
-garden
-friendly
--friendly
-garlic
-friendship
-gas
-frightened
-frog
-gate
--gate
-gather
-gender
-general
-gold
-golf
-generate
-generation
-good
-goodbye
-bye
-generous
-genius
-government
-gentle
-gentleman
-grab
-grade
-gradually
-genuine
-geography
-graduate
-grain
-geometry
-german
-grammar
-germany
-gramme
-gram
-grand
-get
-gift
-granddaughter
-gifted
-grandfather
-grandpa
-giraffe
-grandmother
-grandma
-girl
-grandparent
-give
-grandson
-glad
-grape
-grasp
-glass
-global
-grass
-globe
-grateful
-gravity
-glove
-great
-great-
-glue
-greedy
-go
-goal
-green
-goat
-greenhouse
-greet
-hand
-grey
-handbag
-grocery
-handkerchief
-ground
-handle
-group
-handsome
-grow
-handwriting
-guarantee
-hang
-guard
-the guard
-happen
-guess
-happy
-guest
-hard
-guidance
-hardly
-guide
-harm
-guideline
-harmful
-guilty
-harmonious
-guitar
-harmony
-gun
-guy
-harvest
-hat
-gym
-hatch
-gymnastics
-hate
-have
-has
-h, h
-he
-habit
-head
--head
-habitat
-headache
-hair
-health
-half
-healthy
-hall
-hear
-ham
-heart
-hamburger
-heat
-heavy
-height
-hold
-hello
-hole
-holiday
-help
-home
-helpful
-hometown
-hen
-homework
-hence
-honest
-her
-herb
-honey
-honour
-honor
-here
-hope
-hero
-horrible
-horse
-herself
-hospital
-hesitate
-host
-hot
-hide
-hotel
-high
-hour
-highlight
-house
-hike
-hill
-him
-housing
-himself
-how
-hire
-however
-hug
-his
-huge
-historic
-human
-history
-hit
-humble
-humorous
-hobby
-hundred
-impact
-imply
-hungry
--hungry
-hunt
-import
-hurricane
-important
-impossible
-hurry
-hurt
-impress
-husband
-impression
-hydrogen
-improve
-in
-in.
-in-
--in
-inch
-incident
-ice
-include
-income
-idea
-increase
-ideal
-incredible
-identical
-indeed
-identify
-independent
-identity
-india
-idiom
-indian
-indicate
-ignore
-individual
-ill
-ill-
-i'll
-industry
-illegal
-infection
-illness
-infer
-illustrate
-influence
-image
-influential
-imagine
-information
-immediately
-initial
-initiative
-interest
-injury
-interesting
-inner
-innocent
-internal
-international
-innovation
-the internet
-input
-inquire
-interpret
-insect
-interrupt
-non-intervention
-inside
-interview
-insight
-into
-introduce
-insist
-inspection
-introduction
-inspire
-invent
-instance
-invention
-instant
-investigate
-instead
-investment
-institute
-invite
-institution
-involve
-iron
-instruction
-instrument
-island
-insurance
-issue
-integrate
-it
-it-
-integrity
-item
-its
-it's
-intelligent
-itself
-intend
-intense
-intention
-interaction
-jacket
-jam
-k, k
-january
-japan
-kangaroo
-japanese
-keep
-jazz
-key
-kettle
-jaw
-jeans
-keyboard
-job
-kick
-jog
-kid
-join
-kill
-joint
-kilo
-kilo-
-joke
-kilogram
-journal
-kilometre
-journalist
-kind
-kindergarten
-joy
-king
-judge
-kingdom
-juice
-kiss
-july
-kit
-jump
-kitchen
-june
-kite
-jungle
-knee
-junior
-knife
-just
-knock
-justice
-know
-justify
-knowledge
-l
-leadership
-lab
-lab.
-laboratory
-leaf
-league
-label
-labour
-labor
-leak
-learn
-lack
-least
-lady
-leather
-lake
-leave
-lamb
-lecture
-lamp
-left
-land
-leg
-landscape
-legal
-language
-leisure
-lantern
-lemon
-lap
-lend
-length
--length
-laptop
-large
-less
--less
-last
-lesson
-late
-let
--let
-letter
-later
-level
-launch
-liberation
-liberty
-law
-lawyer
-librarian
-library
-lay
-license
-lazy
-lie
-lead
-life
-leader
-lift
-lonely
-light
-long
-long.
-like
--like
-look
-likely
-limit
-lose
-loose
-limited
-loss
-line
-lot
-link
-loud
-lion
-love
-liquid
-lovely
-list
-low
-listen
-lower
-literally
-luck
-literary
-lucky
-literature
-lunar
-litter
-lunch
-little
-lung
-live
-luxury
-lively
-living
-m
-'m
-load
--load
-machine
-loan
-mad
--mad
-local
-madam
-location
-magazine
-lock
-magic
-log
-mail
-logical
-main
-london
-maintain
-major
-may
-majority
-maybe
-make
-me
-male
-meal
-man
--man
-men
-manage
-meaning
-manager
-mankind
-means
-measure
-meat
-manner
-many
-mechanic
-map
-medal
-marathon
-medical
-march
-medicine
-medium
-media
-mark
-meet
-market
-meeting
-marriage
-member
-marry
-membership
-mass
-memorial
-massive
-memory
-master
-mental
-mention
-match
-material
-menu
-mercy
-maths
-mathematics
-merely
-matter
-mature
-merry
-maximum
-mess
-message
-metal
-mistake
-method
-mix
-metre
-meter
-mixture
-microscope
-mobile
-phone
-mode
-middle
-midnight
-model
-might
-modern
-mild
-moment
-mile
-monday
-military
-money
-milk
-monitor
-millimetre
-monkey
-million
-month
-mind
-monthly
-mine
-mineral
-mood
-moon
-minimum
-moral
-minister
-more
-minor
-moreover
-minority
-morning
-minute
-mosquito
-mirror
-most
--most
-miss
-mostly
-mother
-mum
-missile
-motion
-missing
-motivate
-mission
-mist
-motive
-motor
-mount
-national
-mountain
-mouse
-mice
-nationality
-native
-mouth
-natural
-move
-nature
-movement
-movie
-navy
-near
-near-
-mr
-nearby
-mrs
-nearly
-ms
-much
-neat
-necessary
-mud
-neck
-need
-multiple
-needle
-murder
-negative
-muscle
-negotiate
-museum
-mushroom
-neighbour
-music
-neighbourhood
-musician
-neither
-must
-must-
-nephew
-my
-nervous
-nest
-myself
-net
-the net
-.net
-network
-n
-'n'
-nail
-never
-nevertheless
-name
-new
-new-
-narrow
-news
-nation
-novel
-newspaper
-next
-novelist
-nice
-november
-niece
-now
-night
-nowadays
-nine
-nowhere
-nineteen
-nuclear
-ninety
-number
-ninth
-nurse
-no
-no.
-nut
-noble
-nutrition
-nobody
-nod
-noise
-object
-noisy
-objective
-none
-observe
-noodle
-obtain
-noon
-obviously
-nor
-occasion
-occupation
-north
-occupy
-northern
-occur
-nose
-ocean
-note
-october
-notebook
-odd
--odd
-nothing
-of
-notice
-off
-normal
-offer
-orange
-office
-officer
-orbit
-official
-order
-ordinary
-often
-organ
-oil
-organic
-ok
-non-governmental organization
-organization
-old
-the olympics
-origin
-original
-on
-other
-once
-otherwise
-one
-onion
-ought to
-our
-online
-ours
-only
-ourselves
-onto
-out
-out-
-open
-outcome
-outgoing
-opera
-operation
-outline
-operator
-output
-opinion
-outside
-opponent
-outstanding
-opportunity
-over
-over-
-overall
-oppose
-overcome
-opposite
-optimistic
-overseas
-owe
-option
-own
-or
-oxygen
-party
-p
-p.
-pass
-passage
-pace
-pacific
-passenger
-passion
-the passion
-pack
--pack
-package
-passive
-page
-passport
-past
-pain
-paint
-patent
-path
-pair
-palace
-the palace
-patience
-pale
-patient
-pan
-pan-
-pattern
-pancake
-pay
-panda
-pe
-physical
-panel
-peace
-panic
-peak
-paper
-pear
-paragraph
-pen
-parcel
-pencil
-pardon
-people
-park
-parent
-pepper
-parking
-per
-perceive
-part
-percent
-participate
-percentage
-particular
-perfect
-performance
-perhaps
-pill
-pilot
-period
-permanent
-pink
-pioneer
-permit
-person
--person
-pipe
-personal
-pity
-personality
-place
-persuade
-plain
-plan
-pessimistic
-plane
-pet
-planet
-petrol
-plant
-plastic
-phase
-phenomenon
-plate
-philosophy
-platform
-play
-photo
-photo-
-photograph
-player
-photographer
-playground
-phrase
-pleasant
-physician
-please
-physics
-pleasure
-piano
-plenty
-pick
-plug
-picnic
-plus
-picture
-pocket
-pie
-poem
-piece
--piece
-pig
-poet
-poetry
-post
-post-
-postcard
-point
-poster
-poison
-postman
-pole
-polar
-postpone
-police
-potato
-policeman
-policewoman
-potential
-policy
-polish
-pound
-polite
-pour
-power
-political
-practical
-politician
-practice
-politics
-praise
-pollute
-pond
-pollution
-pray
-precious
-pool
-precisely
-predict
-poor
-prefer
-popular
-pop
-pop.
-preference
-population
-pork
-prejudice
-port
-premier
-prepare
-pose
-present
-position
-presentation
-positive
-possession
-president
-preserve
-possible
-press
-pressure
-programme
-program
-progress
-pretty
-prohibit
-prevent
-project
-previous
-promise
-price
-promote
-pride
-pronounce
-primary
-pronunciation
-primitive
-principle
-proof
--proof
-proper
-print
-property
-prior
-priority
-proposal
-prison
-prospect
-protect
-private
-prize
-protein
-protest
-probably
-proud
-prove
-problem
-provide
-procedure
-province
-proceed
-process
-psychology
-pub
-produce
-product
-public
-profession
-publish
-professional
-pudding
-pull
-professor
-profile
-punish
-profit
-pupil
-purchase
-radio
-pure
-radium
-purple
-railway
-purpose
-rain
-purse
-pursue
-rainbow
-rainy
-push
-raise
-put
-random
-q, q
-range
-rank
-qualification
-rapid
-qualify
-quality
-rare
-rate
--rate
-quantity
-rather
-quarter
-rating
-queen
-raw
-question
-quick
-reach
-ray
-quit
-quiet
-react
-reaction
-quite
-read
-quote
-ready
-real
-realize
-rabbit
-realistic
-race
-reality
-racial
-really
-radiation
-reason
-recall
-regular
-receipt
-receive
-reject
-relate
-recently
-relationship
-receptionist
-recipe
-relative
-relax
-recite
-relay
-recognize
-release
-recognition
-relevant
-recommend
-reliable
-record
-relief
-recording
-recover
-remain
-recreation
-remarkable
-recycle
-remember
-remind
-red
-remote
-reduce
-remove
-rent
-reference
-repair
-reflect
-repeat
-replace
-reform
-reply
-refresh
-report
-refuse
-represent
-regard
-representative
-regardless
-region
-reputation
-register
-regret
-request
-rhyme
-require
-rice
-rescue
-rich
--rich
-research
-riddle
-reserve
-ride
-resident
-right
-resign
-resistance
-the resistance
-ring
-rigid
-resolution
-resolve
-ripe
-rise
-resource
-risk
-respect
-river
-respective
-road
-respond
-response
-roast
-robot
-responsibility
-rock
-responsible
-rocket
-rest
-role
-restaurant
-roll
-restore
-romantic
-restrict
-result
-room
-roof
-retire
-return
-rope
-root
-reveal
-rose
-rosé
-review
-round
-revise
-reward
-route
-routine
-row
-sand
-royal
-sandwich
-rubber
-rubbish
-satellite
-satisfaction
-rude
-satisfy
-rugby
-saturday
-ruin
-saucer
-rule
-sausage
-ruler
-save
-run
-saving
--saving
-rural
-say
-rush
-saying
-russia
-scare
-russian
-scarf
-o, o
-scene
-schedule
-sad
-scholarship
-safe
-school
-safety
-schoolbag
-science
-sail
-salad
-scientific
-salary
-scientist
-scissors
-sale
-salesman
-saleswoman
-score
-scream
-salt
-salty
-screen
-sculpture
-same
-sea
-sample
-search
-serve
-season
-service
-seat
--seat
-session
-second
-set
-secondary
-setting
-secret
-settle
-secretary
-seven
-section
-seventeen
-secure
-seventh
-security
-seventy
-see
-several
-seed
-seek
-severe
-sew
-seem
-sex
-seize
-shade
-seldom
-shadow
-select
-shake
-sell
-shall
-send
-shallow
-senior
-shame
-sense
-shape
-sensitive
-share
-sentence
-shark
-separate
-sharp
-september
-shave
-series
-she
-serious
-sheep
-sheet
-servant
-shelf
-shelter
-silent
-shift
-silk
-shine
-silly
-silver
-ship
--ship
-similar
-simple
-shock
-since
-shoe
-sincerely
-shoot
-sing
-sing.
-shop
-single
-shore
-sink
-sir
-short
-short-
-shortage
-sister
-sit
-shorts
-should
-site
-shoulder
-situation
-shout
-six
-show
-sixth
-sixteen
-shower
-sixty
-shut
-size
-shy
--shy
-skate
-sick
-skateboard
-side
-ski
-sight
-skill
-skin
-sign
-skip
-signal
-significant
-silence
-sky
-soft
-sleep
-software
-sleepy
-slice
-soil
-solar
-slide
-soldier
-slightly
-solid
-solution
-slip
-solve
-slow
-some
-small
-somebody
-smell
-smart
-somehow
-someone
-smile
-something
--something
-smog
-sometimes
-smoke
-somewhat
-smooth
-somewhere
-snack
-son
-snake
-song
-sneeze
-soon
-snow
-sorrow
-snowy
-sorry
-sort
-soccer
-social
-soul
-sound
-socialist
-soup
-society
-sock
-sour
-source
-sofa
-south
-southern
-stair
-sow
-space
-stamp
-spare
-stand
-standard
-speak
--speak
-speaker
-star
--star
-special
-stare
-start
-specialist
-species
-starve
-specific
-state
-station
-statistic
-speech
-statue
-speed
-stay
-spell
-steak
-spend
-steal
-spirit
-steam
-splendid
-steel
-sponsor
-spoon
-step
-step-
-sport
-stick
-spot
-still
-spread
-stimulate
-spring
-stomach
-spy
-stone
-square
-stop
-stability
-stadium
-store
-staff
-storm
--storm
-stage
-story
-straight
-subscribe
-straightforward
-subsequent
-substance
-strait
-strange
-substantial
-stranger
-suburb
-strategy
-subway
-strawberry
-succeed
-stream
-success
-street
-successful
-strength
-such
-strengthen
-sudden
-stretch
-suffer
-sufficient
-stress
-strict
-sugar
-strike
-suggest
-string
-suggestion
-strong
-structure
-suit
-suitable
-struggle
-student
-sum
-summary
-studio
-summer
-study
-stuff
-sun
-sun.
-sunday
-stupid
-sunny
-style
--style
-subject
-super
-super-
-superb
-subjective
-superior
-submit
-supermarket
-supply
-suppose
-table
-sure
-surf
-tablet
-tackle
-surface
-surgeon
-tail
-tailor
-surgery
-take
-surprise
-tale
-surround
-talent
-talk
-survey
-tall
-tank
-survive
-suspect
-tape
-target
-suspend
-sustain
-task
-sweat
-taste
-tax
-sweater
-sweep
-taxi
-sweet
-tea
-swim
-teach
-teacher
-swing
-teapot
-switch
-symbol
-tear
-sympathy
-technique
-symphony
-technology
-system
-teenager
-then
-telephone
-theory
-television
-tv
-there
-tell
-therefore
-temperature
-these
-temple
-they
-temporary
-thick
-ten
-thin
-tend
-thing
-tendency
-think
-tennis
-thinking
-tension
-third
-tenth
-thirsty
-term
--term
-thirteen
-terrible
-thirty
-territory
-this
-test
-thorough
-text
-those
-than
-though
-thank
-thought
-that
-thousand
-the
-threat
-theft
-theatre
-threaten
-their
-three
-through
-them
-throughout
-theme
-throw
-themselves
-thunder
-thus
-thursday
-toothache
-top
-top-
-ticket
-topic
-tidy
-total
-tie
-touch
-tiger
-tough
-tight
-tour
-time
--time
-tourist
-tiny
-tournament
-tip
-towards
-tired
-towel
-tissue
-tower
-title
-town
-toy
-track
-toast
-tobacco
-trade
-today
-tradition
-together
-traditional
-toilet
-traffic
-tolerate
-train
-training
-tomato
-tomorrow
-transform
-translate
-ton
-tone
-transport
-trap
-tonight
-travel
-too
-tool
-treasure
-tooth
-teeth
-treat
-wallet
-weekend
-wander
-weekly
-want
-weep
-war
-weigh
-weight
-ward
--ward
-warm
-welcome
-warn
-welfare
-well
-we'll
-wash
-west
-washroom
-western
-waste
-wet
-watch
-whale
-water
--water
-what
-watermelon
-whatever
-wave
-wheat
-way
-wheel
-we
-when
-weak
-whenever
-wealth
-where
-weapon
-whether
-wear
-which
-weather
-while
-website
-whisper
-wedding
-white
-weed
-wednesday
-who
-the who
-whole
-week
-whom
-weekday
-whose
-wool
-why
-wide
-word
-widespread
-work
--work
-wife
-worker
-the wi
-wi
-hi-fi
-world
-wild
-worry
-worse
-will
-win
-worst
-wind
-worth
-window
-worthwhile
-windy
-worthy
--worthy
-wine
-would
-wing
-wound
-wrap
-winner
-wrestle
-winter
-wire
-wrinkle
-wisdom
-wrist
-wise
--wise
-write
-wish
-writer
-with
-wrong
-withdraw
-within
-without
-x
-witness
-woman
--woman
-women
-wonder
-yard
-wonderful
-year
--year
-wood
-yellow
-yourself
-yes
-yesterday
-youth
-yet
-yogurt
-z, z
-you
-zero
-zone
-young
-your
-yours
-up
-up-
-era
-energy
-household
-housework
-laugh
-slim
-altogether
-ankle
-apart
-atlantic
-cartoon
-cattle
-chest
-chairman
-children
-choose
-clay
-clock
-conflict
-consequence
-cruel
-enable
-journey
-republic
-telescope
-warning
-blog
-count
-fifteen
-hers
-mean
-partner
-pretend
-skirt
-support
-team
-plot
-refer to sb/sth
-consist in sth
-devote sth to sth/sb
-rely on/upon sb/sth
-a
-above
-abroad
-absence
-absent
-absolutely
-absorb
-abstract
-abuse
-academic
-aboard
-able
--able
-ability
--ability
-abandon
-about

二進制
resource/template/base.db


+ 0 - 0
resource/English-World.db → resource/template/high_school.db


+ 0 - 0
static/base.css


+ 39 - 0
templates/base.html

@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+
+    {% block font %}
+        <link rel="preconnect" href="https://fonts.googleapis.com">
+        <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
+        <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@100;400&display=swap" rel="stylesheet">
+    {% endblock %}
+
+    {% block style %}
+        <link href="https://cdn.staticfile.org/bootstrap/4.6.1/css/bootstrap.min.css" rel="stylesheet">
+        <link href="{{ url_for("static", filename="base.css") }}" rel="stylesheet">
+        <style>
+            html {
+                font-family: 'Noto Sans SC', sans-serif;
+            }
+        </style>
+    {% endblock %}
+
+    <title> {{ title }} </title>
+
+</head>
+<body>
+
+<h1 class="text-center mt-2"> Welcome to {{ title }} ! </h1>
+
+{% block body %} {% endblock %}
+
+{% block javascript %}
+    <script src="https://cdn.staticfile.org/popper.js/0.2.0/popper.min.js"></script>
+    <script src="https://cdn.staticfile.org/jquery/1.10.0/jquery.min.js"></script>
+    <script src="https://cdn.staticfile.org/bootstrap/4.6.1/js/bootstrap.min.js"></script>
+{% endblock %}
+
+</body>
+</html>

+ 78 - 13
templates/index.html

@@ -1,13 +1,78 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
-    <meta charset="UTF-8">
-    <title> {{ title }} </title>
-</head>
-<body>
-
-<h1> Welcome to {{ title }} ! </h1>
-<p> {{ about }} </p>
-
-</body>
-</html>
+{% extends "base.html" %}
+
+{% block body %}
+    <article class="container mt-2 mb--2">
+        <p class="col-8 offset-2 text-center" > {{ about }} </p>
+        <section class="mt-2 text-center">
+            <ul id="auth" class="nav nav-tabs justify-content-center mb-2">
+                <li class="active nav-item"> <a href="#login" data-toggle="tab" class="nav-link"> login </a> </li>
+                <li class="nav-item"> <a href="#register" data-toggle="tab" class="nav-link"> register </a> </li>
+            </ul>
+
+            <div id="authContent" class="tab-content">
+                <div class="tab-pane fade" id="login">
+                    <div class="col-12 col-lg-6 offset-lg-3">
+                        <form method="post" action="{{ url_for("home.login") }}" class="login-form">
+                            {{ login_form.hidden_tag() }}
+
+                            <div class="form-group text-left">
+                                {{ login_form.name.label }}
+                                {{ login_form.name(class="form-control") }}
+                            </div>
+
+                            <div class="form-group text-left">
+                                {{ login_form.passwd.label }}
+                                {{ login_form.passwd(class="form-control") }}
+                            </div>
+
+                            <div class="text-left">
+                                {{ login_form.submit(class='btn btn-info mr-2') }}
+                                {{ login_form.remember() }} {{ login_form.remember.label }}
+                            </div>
+                        </form>
+                    </div>
+                </div>
+                <div class="tab-pane fade" id="register">
+                    <div class="col-12 col-lg-6 offset-lg-3">
+                        <form method="post" action="{{ url_for("home.register") }}" class="register-form">
+                            {{ register_form.hidden_tag() }}
+
+                            <div class="form-group text-left">
+                                {{ register_form.name.label }}
+                                {{ register_form.name(class="form-control") }}
+                            </div>
+
+                            <div class="form-group text-left">
+                                {{ register_form.template.label }}
+                                {{ register_form.template(class="form-control") }}
+                            </div>
+
+                            <div class="form-group text-left">
+                                {{ register_form.passwd.label }}
+                                {{ register_form.passwd(class="form-control") }}
+                            </div>
+
+                            <div class="form-group text-left">
+                                {{ register_form.passwd_again.label }}
+                                {{ register_form.passwd_again(class="form-control") }}
+                            </div>
+
+                            <div class="text-left">
+                                {{ register_form.submit(class='btn btn-info mr-2') }}
+                            </div>
+                        </form>
+                    </div>
+                </div>
+            </div>
+        </section>
+
+    </article>
+
+{% endblock %}
+
+{% block javascript %}
+    {{ super() }}
+    <script>
+        $('#auth .active a').tab('show');  // 显示第一个 tab
+    </script>
+{% endblock %}

+ 9 - 0
templates/not_word.html

@@ -0,0 +1,9 @@
+{% extends "base.html" %}
+
+{% block body %}
+    <article class="container mt-2 mb--2">
+        <p class="col-8 offset-2 text-center" > {{ about }} </p>
+        <p> Sorry, there not any word. </p>
+    </article>
+
+{% endblock %}

+ 70 - 0
templates/test.html

@@ -0,0 +1,70 @@
+{% extends "base.html" %}
+
+{% block body %}
+    <article class="container mt-2 mb--2">
+        <p class="col-8 offset-2 text-center" > {{ about }} </p>
+        <section class="mt-2 text-center">
+            <ul id="test" class="nav nav-tabs justify-content-center mb-2">
+                <li class="active nav-item"> <a href="#question" data-toggle="tab" class="nav-link"> question </a> </li>
+                <li class="nav-item"> <a href="#info" data-toggle="tab" class="nav-link"> info </a> </li>
+                <li class="nav-item"> <a href="#answer" data-toggle="tab" class="nav-link"> answer </a> </li>
+            </ul>
+
+            <div id="testContent" class="tab-content">
+                <div class="tab-pane fade" id="question">
+                    <p class="text-center h2"> <u> {{ word.name }} </u> </p>
+                </div>
+                <div class="tab-pane fade" id="info">
+                    <div class="col-12 col-lg-6 offset-lg-3">
+                        {% for w in word.comment %}
+                            <h6 class="text-left">
+                                {{ word.comment[w].part }}
+                            </h6>
+
+                            <ul class="text-left">
+                                {% for e in word.comment[w].eg %}
+                                    <li> <p> {{ e.split('##')[0] }} </p> </li>
+                                {% endfor %}
+                            </ul>
+                        {% endfor %}
+                    </div>
+                </div>
+                <div class="tab-pane fade" id="answer">
+                    <div class="col-12 col-lg-6 offset-lg-3">
+                        {% for w in word.comment %}
+                            <h5 class="text-left">
+                                {{ word.comment[w].chinese }}
+                            </h5>
+
+                            <h6 class="text-left">
+                                {{ word.comment[w].english }}
+                            </h6>
+
+                            <h6 class="text-left">
+                                ({{ word.comment[w].part }})
+                            </h6>
+
+                            <ul class="text-left">
+                                {% for e in word.comment[w].eg %}
+                                    <li>
+                                        <p> {{ e.split('##')[0] }} </p>
+                                        <p> {{ e.split('##')[1] }} </p>
+                                    </li>
+                                {% endfor %}
+                            </ul>
+                        {% endfor %}
+                    </div>
+                </div>
+            </div>
+        </section>
+
+    </article>
+
+{% endblock %}
+
+{% block javascript %}
+    {{ super() }}
+    <script>
+        $('#test .active a').tab('show');  // 显示第一个 tab
+    </script>
+{% endblock %}