Compare commits

...

2 commits

18 changed files with 204 additions and 33 deletions

View file

@ -1,3 +1,7 @@
NAME=Krll
HOST=https://krll.me
CONTACT=mailto:example@gmail.com
POSTGRES_HOST=db:5432 POSTGRES_HOST=db:5432
POSTGRES_DATABASE=postgres POSTGRES_DATABASE=postgres
POSTGRES_USER=postgres POSTGRES_USER=postgres

4
.gitignore vendored
View file

@ -6,4 +6,6 @@ __pycache__/
docker-compose.yml docker-compose.yml
postgres/ postgres/
rule.html

View file

@ -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

32
main.py
View file

@ -7,6 +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
import os
# 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)
@ -32,12 +43,29 @@ app.mount("/static", StaticFiles(directory="./static"), name="static")
@app.get("/", response_class=HTMLResponse) @app.get("/", response_class=HTMLResponse)
def index(request: Request): def index(request: Request):
return templates.TemplateResponse(request=request, name="index.html") return templates.TemplateResponse(
request=request,
name="index.html",
context=DEFAULT_CONTEXT
)
@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(request=request, name="about.html") return templates.TemplateResponse(
request=request,
name="about.html",
context=DEFAULT_CONTEXT
)
app.include_router(url_route.routes) app.include_router(url_route.routes)

5
rule.example.html Normal file
View file

@ -0,0 +1,5 @@
<h1>Rule</h1>
<ul>
<li>Do not use Krll for spam.</li>
<li>Be legal.</li>
</ul>

View file

@ -4,6 +4,10 @@ import os
load_dotenv() load_dotenv()
NAME = os.environ.get("NAME")
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")
POSTGRES_PASSWORD = os.environ.get("POSTGRES_PASSWORD") POSTGRES_PASSWORD = os.environ.get("POSTGRES_PASSWORD")

View file

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 8 KiB

View file

@ -45,7 +45,7 @@ const shorten = async () => {
} }
const data = await response.json(); const data = await response.json();
const result = `https://krll.me/${data.key}` const result = `${host}/${data.key}`;
// show the short url // show the short url
short_url.innerText = result; short_url.innerText = result;

View file

@ -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
View 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");
}
}
}

View file

@ -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
View 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);
}

View file

@ -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 %}

View file

@ -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 %}
@ -21,5 +21,9 @@
</div> </div>
</main> </main>
<script src="{{ url_for('static', path='/script.js') }}"></script> <script>
const host = "{{ host }}";
</script>
<script src="{{ url_for('static', path='/index/script.js') }}"></script>
{% endblock %} {% endblock %}

View file

@ -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 Krll</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
View 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 %}