add menu and make possible for admin to edit rule
This commit is contained in:
parent
c2495565d9
commit
ffdddbd25b
|
@ -1,5 +1,6 @@
|
||||||
NAME=Krll
|
NAME=Krll
|
||||||
HOST=https://krll.me
|
HOST=https://krll.me
|
||||||
|
CONTACT=mailto:example@gmail.com
|
||||||
|
|
||||||
POSTGRES_HOST=db:5432
|
POSTGRES_HOST=db:5432
|
||||||
POSTGRES_DATABASE=postgres
|
POSTGRES_DATABASE=postgres
|
||||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -7,3 +7,5 @@ __pycache__/
|
||||||
docker-compose.yml
|
docker-compose.yml
|
||||||
|
|
||||||
postgres/
|
postgres/
|
||||||
|
|
||||||
|
rule.html
|
19
README.md
19
README.md
|
@ -1,11 +1,22 @@
|
||||||
# Krll
|
# Krll
|
||||||
Krll, a privacy-friendly URL shortener
|
Krll, a privacy-friendly open source URL shortener
|
||||||
|
|
||||||
https://krll.me
|
https://krll.me
|
||||||
|
|
||||||
## Dev
|
## Run
|
||||||
Copy `.env.example` to `.env` and edit it
|
1. Copy `.env.example` to `.env` and edit it
|
||||||
```
|
- NAME: Krll server's name(ex: Krll)
|
||||||
|
- HOST: Krll server's host(ex: https://krll.me)
|
||||||
|
- CONTACT: Server operator's contact info
|
||||||
|
- POSTGRES_...: PostgreSQL setting(If you'll run postgresql with docker compose, you should edit just 'POSTGRES_PASSWORD', if not, you should edit 'POSTGRES_HOST' to your postgresql's host.)
|
||||||
|
|
||||||
|
2. RUN
|
||||||
|
```bash
|
||||||
|
# with docker compose
|
||||||
|
cp docker-compose.example.yml docker-compose.yml
|
||||||
|
docker compose up -d
|
||||||
|
|
||||||
|
# without docker compose
|
||||||
python -m venv venv
|
python -m venv venv
|
||||||
source ./venv/bin/activate/
|
source ./venv/bin/activate/
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
|
|
19
main.py
19
main.py
|
@ -7,11 +7,17 @@ from fastapi.templating import Jinja2Templates
|
||||||
from src.database import engine
|
from src.database import engine
|
||||||
from src import models
|
from src import models
|
||||||
from src.routes.url import url_route
|
from src.routes.url import url_route
|
||||||
|
from src.env import NAME, HOST, CONTACT
|
||||||
|
|
||||||
from src.env import NAME, HOST
|
import os
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_CONTEXT = { "name": NAME, "host": HOST }
|
# server's settings
|
||||||
|
DEFAULT_CONTEXT = { "name": NAME, "host": HOST, "contact": CONTACT }
|
||||||
|
|
||||||
|
# server's rule page
|
||||||
|
rule_f = open(os.path.join(os.path.dirname(os.path.abspath(__file__)), "rule.html"))
|
||||||
|
RULE = "\n".join(rule_f.readlines())
|
||||||
|
|
||||||
|
|
||||||
models.Base.metadata.create_all(bind=engine)
|
models.Base.metadata.create_all(bind=engine)
|
||||||
|
@ -44,6 +50,15 @@ def index(request: Request):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/rule", response_class=HTMLResponse)
|
||||||
|
def rule(request: Request):
|
||||||
|
return templates.TemplateResponse(
|
||||||
|
request=request,
|
||||||
|
name="rule_frame.html",
|
||||||
|
context=DEFAULT_CONTEXT | { "rule": RULE }
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/about", response_class=HTMLResponse)
|
@app.get("/about", response_class=HTMLResponse)
|
||||||
def about(request: Request):
|
def about(request: Request):
|
||||||
return templates.TemplateResponse(
|
return templates.TemplateResponse(
|
||||||
|
|
5
rule.example.html
Normal file
5
rule.example.html
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<h1>Rule</h1>
|
||||||
|
<ul>
|
||||||
|
<li>Do not use Krll for spam.</li>
|
||||||
|
<li>Be legal.</li>
|
||||||
|
</ul>
|
|
@ -6,6 +6,7 @@ load_dotenv()
|
||||||
|
|
||||||
NAME = os.environ.get("NAME")
|
NAME = os.environ.get("NAME")
|
||||||
HOST = os.environ.get("HOST")
|
HOST = os.environ.get("HOST")
|
||||||
|
CONTACT = os.environ.get("CONTACT")
|
||||||
|
|
||||||
POSTGRES_DATABASE = os.environ.get("POSTGRES_DATABASE")
|
POSTGRES_DATABASE = os.environ.get("POSTGRES_DATABASE")
|
||||||
POSTGRES_USER = os.environ.get("POSTGRES_USER")
|
POSTGRES_USER = os.environ.get("POSTGRES_USER")
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
main {
|
main {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction:column;
|
||||||
}
|
}
|
||||||
|
|
||||||
section {
|
section {
|
||||||
|
@ -9,4 +11,5 @@ section {
|
||||||
|
|
||||||
a {
|
a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
color: var(--link-color);
|
||||||
}
|
}
|
BIN
static/images/logo.png
Normal file
BIN
static/images/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8 KiB |
|
@ -1,5 +1,8 @@
|
||||||
main {
|
main {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
padding-top: 100px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction:column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-container {
|
.input-container {
|
14
static/menu.js
Normal file
14
static/menu.js
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
const menu_btn = document.getElementById("menu-btn");
|
||||||
|
const menu = document.getElementById("menu");
|
||||||
|
|
||||||
|
menu_btn.onclick = () => {
|
||||||
|
menu.classList.toggle("show");
|
||||||
|
}
|
||||||
|
|
||||||
|
window.onclick = e => {
|
||||||
|
if (!e.target.matches(".menu-btn")) {
|
||||||
|
if (menu.classList.contains("show")) {
|
||||||
|
menu.classList.remove("show");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
* {
|
* {
|
||||||
font-family: 'Poppins', sans-serif;
|
font-family: 'Poppins', sans-serif;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
|
@ -13,7 +14,7 @@
|
||||||
--text-color: light-dark(black, white);
|
--text-color: light-dark(black, white);
|
||||||
--footer-text-color: light-dark(rgb(90, 90, 90), rgb(173, 173, 173));
|
--footer-text-color: light-dark(rgb(90, 90, 90), rgb(173, 173, 173));
|
||||||
--button-text-color: white;
|
--button-text-color: white;
|
||||||
--link-color: light-dark(#2e2e2e, #7a7a7a);
|
--link-color: light-dark(#797979, #9e9e9e);
|
||||||
|
|
||||||
--border-color: light-dark(lightgray, gray);
|
--border-color: light-dark(lightgray, gray);
|
||||||
--border-highlight-color: darkgray;
|
--border-highlight-color: darkgray;
|
||||||
|
@ -28,14 +29,68 @@ body {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
background-color: var(--background-color);
|
background-color: var(--background-color);
|
||||||
padding-top: 100px;
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
main {
|
header ul {
|
||||||
|
padding: 10px;
|
||||||
|
margin: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction:column;
|
align-items: center;
|
||||||
flex: 1 0 auto;
|
}
|
||||||
|
|
||||||
|
header ul * {
|
||||||
|
margin: 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
header img {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
header button {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu {
|
||||||
|
display: none;
|
||||||
|
flex-direction: column;
|
||||||
|
font-size: 17px;
|
||||||
|
background-color: var(--input-background-color);
|
||||||
|
position: absolute;
|
||||||
|
margin-top: 5px;
|
||||||
|
margin-left: 5px;
|
||||||
|
border-radius: 5px;
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.show {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: var(--text-color);
|
||||||
|
width: 100%;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu a:hover {
|
||||||
|
background-color: rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* @media screen and (max-width: 1000px) {
|
||||||
|
.menu {
|
||||||
|
width: 100vw;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
} */
|
||||||
|
|
||||||
|
main {
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
footer {
|
footer {
|
||||||
|
|
15
static/rule/style.css
Normal file
15
static/rule/style.css
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
main {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
section {
|
||||||
|
width: 90%;
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: var(--link-color);
|
||||||
|
}
|
|
@ -10,26 +10,16 @@
|
||||||
<main>
|
<main>
|
||||||
<section>
|
<section>
|
||||||
<h2>About Krll</h2>
|
<h2>About Krll</h2>
|
||||||
<p>Krll은 개인정보 수집 없이 URL을 단축하는 서비스입니다. 방해꾼 없이 빠르게 URL을 단축하고 공유하세요.</p>
|
<p>Krll은 개인정보 수집이 없는 오픈 소스 링크 단축 서비스입니다.</p>
|
||||||
<p>repository: <a href="https://git.worldc.one/sunwoo1524/krll">https://git.worldc.one/sunwoo1524/krll</a></p>
|
|
||||||
|
|
||||||
<h2>특징</h2>
|
<h3>기여하기</h3>
|
||||||
<ul>
|
<p>Krll은 MIT 라이센스가 적용되어 누구나 코드를 사용하고 이 프로젝트에 기여할 수 있습니다. 하지만 한 가지 부탁 드릴 것이 있습니다. <a href="https://nogithub.codeberg.page/">GitHub에 Krll의 코드를 업로드하지 말아주세요.</a></p>
|
||||||
<li>개인정보 수집과 광고가 없습니다.</li>
|
<p><a href="https://git.worldc.one/sunwoo1524/krll">자체 호스팅 중인 Forgejo</a>에서 기여할 수 있습니다.</p>
|
||||||
<li>단축 시 QR 코드가 함께 생성되어 다른 디바이스로 빠르게 공유할 수 있습니다.</li>
|
|
||||||
<li>크롬, 파이어폭스 확장을 설치하여 웹사이트 내의 하이퍼링크를 우클릭 후 메뉴 선택 만으로 빠르게 단축할 수 있습니다.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h2>브라우저 확장</h2>
|
<h3>브라우저 확장</h3>
|
||||||
|
<p>크롬, 파이어폭스 확장을 설치하여 웹사이트 내의 하이퍼링크를 우클릭 후 메뉴 선택 만으로 빠르게 단축할 수 있습니다.</p>
|
||||||
<p><a href="https://github.com/sunwoo1524/krll-chrome-extension">Chrome(스토어에 올라와있지 않아 직접 압축 파일로 다운로드하고 설치해야합니다.)</a></p>
|
<p><a href="https://github.com/sunwoo1524/krll-chrome-extension">Chrome(스토어에 올라와있지 않아 직접 압축 파일로 다운로드하고 설치해야합니다.)</a></p>
|
||||||
<p><a href="https://addons.mozilla.org/ko/firefox/addon/krll-url-shortener/">Firefox</a></p>
|
<p><a href="https://addons.mozilla.org/ko/firefox/addon/krll-url-shortener/">Firefox</a></p>
|
||||||
|
|
||||||
<h2>규칙</h2>
|
|
||||||
<p>이것들을 막을 방법은 없지만 안정적인 서비스 운영을 위해서 따라주세요.</p>
|
|
||||||
<ul>
|
|
||||||
<li>대한민국 법에 저촉되는 링크를 단축하지 마세요.</li>
|
|
||||||
<li>스팸을 위해서 사용하지 마세요.</li>
|
|
||||||
</ul>
|
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
{% block head %}
|
{% block head %}
|
||||||
{{ super() }}
|
{{ super() }}
|
||||||
<link rel="stylesheet" href="{{ url_for('static', path='/style.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', path='/index/style.css') }}">
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
@ -25,5 +25,5 @@
|
||||||
const host = "{{ host }}";
|
const host = "{{ host }}";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script src="{{ url_for('static', path='/script.js') }}"></script>
|
<script src="{{ url_for('static', path='/index/script.js') }}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -7,14 +7,32 @@
|
||||||
<title>{% block title %}{% endblock %}</title>
|
<title>{% block title %}{% endblock %}</title>
|
||||||
<link rel="icon" href="{{ url_for('static', path='/favicon.ico') }}">
|
<link rel="icon" href="{{ url_for('static', path='/favicon.ico') }}">
|
||||||
<link rel="stylesheet" href="{{ url_for('static', path='/root.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', path='/root.css') }}">
|
||||||
|
|
||||||
|
<!-- Import Google Fonts Icons -->
|
||||||
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,1,0" />
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<header>
|
||||||
|
<ul>
|
||||||
|
<button class="menu-btn" id="menu-btn"><span class="menu-btn material-symbols-outlined">menu</span></button>
|
||||||
|
<a href="/"><img src="{{ url_for('static', path='/images/logo.png') }}" alt="Krll Logo"></a>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="menu" id="menu">
|
||||||
|
<a href="/">Home</a>
|
||||||
|
<a href="/about">About</a>
|
||||||
|
<a href="https://git.worldc.one/sunwoo1524/krll">Git Repository</a>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
{% block content %}{% endblock %}
|
{% block content %}{% endblock %}
|
||||||
|
|
||||||
<footer>
|
<footer>
|
||||||
<p>스팸이나 불법적인 용도로 사용하지 말아주세요.</p>
|
<p><a href="/rule">Rule</a> · <a href="/about">About Krll</a> · <a href="{{ contact }}">Contact</a> · <a href="https://git.worldc.one/sunwoo1524/krll">Git Repository</a></p>
|
||||||
<p><a href="/about">About {{ name }}</a> · <a href="mailto:maengkkong1524@naver.com">Contact</a></p>
|
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<script src="{{ url_for('static', path='/menu.js') }}"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
15
templates/rule_frame.html
Normal file
15
templates/rule_frame.html
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
{% extends "layout.html" %}
|
||||||
|
{% block title %}About Krll{% endblock %}
|
||||||
|
|
||||||
|
{% block head %}
|
||||||
|
{{ super() }}
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static', path='/rule/style.css') }}">
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<main>
|
||||||
|
<section>
|
||||||
|
{{ rule|safe }}
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
{% endblock %}
|
Loading…
Reference in a new issue