Merge pull request #1 from IRUSlan92I/calendar

Calendar
This commit is contained in:
2022-07-13 13:46:39 +03:00
committed by GitHub
40 changed files with 700 additions and 12 deletions
+2
View File
@@ -127,3 +127,5 @@ dmypy.json
# Pyre type checker
.pyre/
.idea/
+15 -3
View File
@@ -10,6 +10,7 @@ For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.0/ref/settings/
"""
import os
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
@@ -32,6 +33,9 @@ ALLOWED_HOSTS = [env('HOST_1')]
# Application definition
INSTALLED_APPS = [
'main',
'links',
'faerun_calendar',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
@@ -76,8 +80,12 @@ WSGI_APPLICATION = 'dnd_db_site.wsgi.application'
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
'ENGINE': 'django.db.backends.mysql',
'NAME': env('DB_NAME'),
'USER': env('DB_USER'),
'PASSWORD': env('DB_PASSWORD'),
'HOST': 'localhost',
'PORT': '',
}
}
@@ -104,7 +112,7 @@ AUTH_PASSWORD_VALIDATORS = [
# Internationalization
# https://docs.djangoproject.com/en/4.0/topics/i18n/
LANGUAGE_CODE = 'en-us'
LANGUAGE_CODE = 'ru-ru'
TIME_ZONE = 'UTC'
@@ -117,6 +125,10 @@ USE_TZ = True
# https://docs.djangoproject.com/en/4.0/howto/static-files/
STATIC_URL = 'static/'
STATIC_ROOT = '/home/ruslan/dnd-db-site.misc/static'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
]
# Default primary key field type
# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field
+6 -2
View File
@@ -15,8 +15,12 @@ Including another URLconf
"""
from django.contrib import admin
from django.urls import include, path
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('helloworld.urls')),
]
path('', include('main.urls')),
path('calendar/', include('faerun_calendar.urls')),
path('links/', include('links.urls')),
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
+6
View File
@@ -0,0 +1,6 @@
from django.apps import AppConfig
class FaerunCalendarConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'faerun_calendar'
@@ -0,0 +1,39 @@
div.calendarpage {
margin: 10px;
padding: 10px;
border: 1px solid black;
border-radius: 20px;
}
table.month, table.month th, table.month td {
border: 1px solid white;
border-collapse: collapse;
padding: 5px;
background: gainsboro;
}
table.month td {
text-align: right;
}
table.month td.current {
background: dimgrey;
color: white;
}
table.month th.subtitle {
font-style: italic;
font-weight: normal;
}
div.calendar {
display: flex;
flex-flow: row wrap;
justify-content: space-around;
}
table.month {
margin: 10px;
width: 350px;
max-width: 350px;
}
@@ -0,0 +1,22 @@
<div class="calendar">
{% include 'faerun_calendar/month.html' with title="Хаммер" subtitle="Глубокозимье" %}
{% include 'faerun_calendar/month.html' with title="Зимний солнцеворот" subtitle="Мертвозимье" oneday=1 %}
{% include 'faerun_calendar/month.html' with title="Альтурик" subtitle="Коготь зимы" %}
{% include 'faerun_calendar/month.html' with title="Чез" subtitle="Коготь закатов" %}
{% include 'faerun_calendar/month.html' with title="Тарсак" subtitle="Коготь бурь" %}
{% include 'faerun_calendar/month.html' with title="Зеленотравье" oneday=1 %}
{% include 'faerun_calendar/month.html' with title="Миртул" subtitle="Таяние" %}
{% include 'faerun_calendar/month.html' with title="Кайторн" subtitle="Время цветов" %}
{% include 'faerun_calendar/month.html' with title="Флеймрул" subtitle="Разгар лета" %}
{% include 'faerun_calendar/month.html' with title="Летний солнцеворот" oneday=1 %}
{% include 'faerun_calendar/month.html' with title="Шильдмит*" oneday=1 %}
{% include 'faerun_calendar/month.html' with title="Элесис" subtitle="Солнцестояние" %}
{% include 'faerun_calendar/month.html' with title="Элейнт" subtitle="Увядание" %}
{% include 'faerun_calendar/month.html' with title="Праздник урожая" oneday=1 %}
{% include 'faerun_calendar/month.html' with title="Марпенот" subtitle="Листопад" %}
{% include 'faerun_calendar/month.html' with title="Уктар" subtitle="Перегной" %}
{% include 'faerun_calendar/month.html' with title="Пир луны" oneday=1 %}
{% include 'faerun_calendar/month.html' with title="Найтал" subtitle="Спячка" %}
</div>
@@ -0,0 +1,19 @@
{% extends 'main/pagetemplate.html' %}
{% load static %}
{% block additional_css %}
<link rel="stylesheet" href="{% static 'faerun_calendar/css/main.css' %}">
{% endblock %}
{% block pagetitle %}
Календарь
{% endblock %}
{% block content %}
<div class="calendarpage">
<h1 class="title">Календарь</h1>
{% include 'faerun_calendar/calendar.html' %}
</div>
{% endblock %}
@@ -0,0 +1,53 @@
<div class="month">
<table class="month">
<tr>
<th colspan="10" class="title">{{title}}</th>
</tr>
{% if subtitle %}
<th colspan="10" class="subtitle">{{subtitle}}</th>
{% endif %}
{% if oneday != 1 %}
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
<td>6</td>
<td>7</td>
<td>8</td>
<td>9</td>
<td>10</td>
</tr>
<tr>
<td>11</td>
<td>12</td>
<td>13</td>
<td>14</td>
<td>15</td>
<td>16</td>
<td>17</td>
<td>18</td>
{% if title == "Миртул" %}
<td class="current">19</td>
{% else %}
<td>19</td>
{% endif %}
<td>20</td>
</tr>
<tr>
<td>21</td>
<td>22</td>
<td>23</td>
<td>24</td>
<td>25</td>
<td>26</td>
<td>27</td>
<td>28</td>
<td>29</td>
<td>30</td>
</tr>
{% endif %}
</table>
</div>
+6
View File
@@ -0,0 +1,6 @@
from django.shortcuts import render
def index(request):
return render(request, 'faerun_calendar/index.html')
-5
View File
@@ -1,5 +0,0 @@
from django.http import HttpResponse
def index(request):
return HttpResponse('<b>Hallo, Welt!</b>')
View File
+6
View File
@@ -0,0 +1,6 @@
from django.contrib import admin
from .models import Link
admin.site.register(Link)
+2 -2
View File
@@ -1,6 +1,6 @@
from django.apps import AppConfig
class HelloworldConfig(AppConfig):
class LinksConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'helloworld'
name = 'links'
View File
+10
View File
@@ -0,0 +1,10 @@
from django.db import models
class Link(models.Model):
order = models.SmallIntegerField('Order')
url = models.CharField('URL', max_length=250)
text = models.CharField('Text', max_length=250)
def __str__(self):
return f'({self.order}, {self.url}, {self.text})'
+12
View File
@@ -0,0 +1,12 @@
div.linkspage {
margin: 10px;
padding: 10px;
border: 1px solid black;
border-radius: 20px;
}
ul {
list-style-type: none;
margin: 0;
padding: 0;
}
+23
View File
@@ -0,0 +1,23 @@
{% extends 'main/pagetemplate.html' %}
{% load static %}
{% block additional_css %}
<link rel="stylesheet" href="{% static 'links/css/main.css' %}">
{% endblock %}
{% block pagetitle %}
Полезные ссылки
{% endblock %}
{% block content %}
<div class="linkspage">
<h1 class="title">Полезные ссылки</h1>
<ul>
{% for link in links %}
<li><a href="{{link.url}}">{{link.text}}</a></li>
{% endfor %}
</ul>
</div>
{% endblock %}
+3
View File
@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.
+8
View File
@@ -0,0 +1,8 @@
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
]
+8
View File
@@ -0,0 +1,8 @@
from django.shortcuts import render
from .models import Link
def index(request):
links = Link.objects.order_by('order')
return render(request, 'links/index.html', {'links': links})
View File
+3
View File
@@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.
+6
View File
@@ -0,0 +1,6 @@
from django.apps import AppConfig
class MainConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'main'
View File
+3
View File
@@ -0,0 +1,3 @@
from django.db import models
# Create your models here.
+44
View File
@@ -0,0 +1,44 @@
div.mainpage {
margin: 10px;
padding: 10px;
border: 1px solid black;
border-radius: 20px;
}
aside.menu {
border: 3px solid black;
border-radius: 10px;
display: flex;
flex-direction: column;
padding: 15px;
margin: 25px;
}
div.menu {
display: flex;
flex-flow: row wrap;
}
aside.menu a {
border-radius: 10px;
text-decoration: none;
color: black;
font-weight: bold;
background: DeepSkyBlue;
padding: 10px;
margin: 10px;
max-width: 100px;
max-width: 200px;
display: flex;
flex: 1 1 0px;
flex-grow: 1;
justify-content: center;
align-items: center;
}
aside.menu a:hover {
background: DodgerBlue;
}
+11
View File
@@ -0,0 +1,11 @@
{% extends 'main/pagetemplate.html' %}
{% block pagetitle %}
Главная страница
{% endblock %}
{% block content %}
<div class="mainpage">
<h1 class="title">Главная страница</h1>
</div>
{% endblock %}
+38
View File
@@ -0,0 +1,38 @@
<!DOCTYPE html>
{% load static %}
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>{% block pagetitle %}{% endblock %}</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous">
<link rel="stylesheet" href="{% static 'main/css/main.css' %}">
{% block additional_css %}
{% endblock %}
<link rel="icon" href="{% static 'iconsmall.png' %}">
<link rel="apple-touch-icon" href="{% static 'iconbig.png' %}">
</head>
<body>
<aside class="menu">
<div class="menu">
<a class="menuitem" href="/">
Главная
</a>
<a class="menuitem" href="/calendar">
Календарь
</a>
<a class="menuitem" href="/links">
Полезные ссылки
</a>
</div>
</aside>
{% block content %}
{% endblock %}
</body>
</html>
+3
View File
@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.
+8
View File
@@ -0,0 +1,8 @@
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
]
+5
View File
@@ -0,0 +1,5 @@
from django.shortcuts import render
def index(request):
return render(request, 'main/index.html')
Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

+339
View File
@@ -0,0 +1,339 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<style>
label {
background: azure;
border: solid black 1px;
border-radius: 5px;
font-weight: bold;
}
input[type=text] {
background: LightYellow;
border: solid black 1px;
border-radius: 5px;
overflow: hidden;
text-align: center;
}
hr {
clear: both;
}
input.error {
background: salmon;
}
div.misc, div.abilities, div.skills {
float: left;
min-height: 30px;
}
div.misc {
min-width: 280px;
}
div.abilities {
min-width: 200px;
}
div.skills {
min-width: 280px;
}
div.misc, div.abilities, div.skills {
margin: 5px 15px;
border: solid black 2px;
border-radius: 5px;
padding: 5px;
display: flex;
align-items: center;
}
div.misc *, div.abilities *, div.skills * {
margin-left: 5px;
margin-right: 5px;
}
div.abilities input, div.skills input {
max-width: 25px;
}
label.skills {
padding: 5px;
}
input[type=checkbox]:checked ~ .skills {
color: white;
background: navy;
}
</style>
<script>
const checkbox_suffix = "_cb";
const message_suffix = "_msg";
const min_ability = 10;
const max_ability = 80;
const max_sum_ability = 80;
class Ability {
constructor(name, short_name_rus, long_name_rus) {
this.name = name;
this.short_name_rus = short_name_rus;
this.long_name_rus = long_name_rus;
}
}
const abilities = [
new Ability("dexterity", "ЛВК", "Ловкость"),
new Ability("strength", "СИЛ", "Сила"),
new Ability("constitution", "ВЫН", "Выносливость"),
new Ability("appearance", "НАР", "Наружность"),
new Ability("charisma", "ХАР", "Харизма"),
new Ability("will", "ВОЛ", "Воля"),
new Ability("wisdom", "МУД", "Мудрость"),
new Ability("intelligence", "ИНТ", "Интеллект"),
]
class Skill {
constructor(name, base, name_rus, dependencies) {
this.name = name;
this.base = base;
this.name_rus = name_rus;
this.dependencies = dependencies;
}
}
const skills = [
new Skill("light_firearm", 5, "Лёгкий огнестрел", {}),
new Skill("medium_firearm", 5, "Средний огнестрел", {}),
new Skill("heavy_firearm", 5, "Тяжёлый огнестрел", {}),
new Skill("recon", 5, "Разведка", {}),
new Skill("gambling", 1, "Азартные игры", {}),
new Skill("artillery", 0, "Артиллерия", {}),
new Skill("barter", 10, "Бартер", {}),
new Skill("blocking", 10, "Блокирование", {}),
new Skill("accounting", 5, "Бухгалтерское дело", {}),
new Skill("riding", 5, "Верховая езда", {}),
new Skill("lockpicking", 1, "Взлом", {}),
new Skill("explosives", 0, "Взрывчатка", {}),
new Skill("pole_weapons", 5, "Древковое оружие", {}),
new Skill("blunt_weapons", 10, "Дробящее оружие", {}),
new Skill("slashing_weapons", 5, "Рубящее оружие", {}),
new Skill("pierce_weapons", 5, "Колющее оружие", {}),
<!-- new Skill("", "", {}),-->
]
function isDataValidForAbility(data) {
var value = parseInt(data);
if (value != value) {
return false;
}
if (value < min_ability || value > max_ability) {
return false;
}
return true;
}
function validateAbilities() {
var sum = 0;
for (const ability of abilities) {
var element = document.getElementById(ability.name);
const value = parseInt(element.value);
if (value == value) {
sum += value;
}
}
const max = 500;
var error_desc_sum = "";
var error_desc_separate = "";
var error_desc_separate_names = [];
const is_sum_error = sum > max || sum != sum;
if (is_sum_error) {
error_desc_sum = `Неверное значение суммы характеристик. Сумма не должна превышать ${max}`;
}
for (const ability of abilities) {
var element = document.getElementById(ability.name);
const is_data_valid = isDataValidForAbility(element.value);
if (!is_data_valid) {
if (!error_desc_separate) {
error_desc_sum = `Неверное значение характеристик. Значение должно быть в диапазоне от ${min_ability} до ${max_ability}`;
}
error_desc_separate_names += ability.name_rus;
}
element.className = !is_sum_error && is_data_valid ? "" : "error";
}
document.getElementById('abilities_result').textContent = max-sum;
const error_text = "";
if (error_desc_sum) {
error_text += error_desc_sum;
}
if (error_desc_separate) {
if (error_text) error_text += "\n";
error_text += error_desc_separate;
}
document.getElementById(`abilities${message_suffix}`).textContent = error_text;
}
function isDataValidForSkill(data, base, is_selected) {
var value = parseInt(data);
if (value != value) {
return false;
}
if (is_selected) {
if (value < 20 || value > 70) {
return false;
}
}
else {
if (value < base || value > 70) {
return false;
}
}
return true;
}
function validateSkills() {
var sum_selected = 0;
var sum_unselected = 0;
var sum_unselected_base = 0;
var count_selected = 0;
for (const skill of skills) {
var element = document.getElementById(skill.name);
var cb = document.getElementById(`${skill.name}${checkbox_suffix}`);
const value = parseInt(element.value);
if (cb.checked) {
count_selected++;
}
if (value == value) {
if (cb.checked) {
sum_selected += value
}
else {
sum_unselected += value
}
}
const base = parseInt(skill.sum_unselected_base);
if (base == base) {
sum_unselected_base += base;
}
}
const max_selected = 500;
const max_unselected = 80;
const max_count_selected = 8;
for (const skill of skills) {
var element = document.getElementById(skill.name);
var cb = document.getElementById(`${skill.name}${checkbox_suffix}`);
const base = parseInt(skill.sum_unselected_base);
if (base == base) {
sum_unselected_base += base;
}
var isValid = count_selected <= max_count_selected;
if (isValid) {
if (cb.checked) {
isValid = sum_selected <= max_selected || sum_selected != sum_selected;
cb.className = "selected";
}
else {
var isValid = (sum_unselected-sum_unselected_base <= max_unselected ||
sum_unselected != sum_unselected);
cb.className = "";
}
}
if (isValid) {
isValid = isDataValidForSkill(element.value, base, cb.checked);
}
element.className = isValid ? "" : "error";
}
document.getElementById('skills_result_selected').textContent = max_selected-sum_selected;
document.getElementById('skills_result_unselected').textContent = max_unselected-sum_unselected;
}
function updateAfterLoading() {
for (const ability of abilities) {
var element = document.getElementById(ability.name);
element.oninput = validateAbilities;
}
for (const skill of skills) {
var element = document.getElementById(skill.name);
var cb = document.getElementById(`${skill.name}${checkbox_suffix}`);
element.oninput = validateSkills;
cb.oninput = validateSkills;
}
validateAbilities();
validateSkills();
}
</script>
</head>
<body>
<h1>Оокона</h1>
<hr>
<p class="misc">
<div class="misc">
Имя: <input id="name" type="text">
</div>
<div class="misc">
Класс: <input id="class" type="text">
</div>
</p>
<hr>
<p class="abilities">
<script>
for (const ability of abilities) {
document.write(`<div class="abilities">`);
document.write(`<input id="${ability.name}" type="text"></input>`);
document.write(`<label class="skills">${ability.long_name_rus}</label>`);
document.write(`</div>`);
}
</script>
<div class="abilities">
Осталось: <span id="abilities_result"></span>
</div>
<script>
document.write(`<p id="abilities${message_suffix}"></p>`);
</script>
</p>
<hr>
<p class="skills">
<script>
for (const skill of skills) {
document.write(`<div class="skills">`);
document.write(`<input class="skills" id="${skill.name}${checkbox_suffix}" type="checkbox">`);
document.write(`<input id="${skill.name}" type="text">`);
document.write(`<label for="${skill.name}${checkbox_suffix}" class="skills">${skill.name_rus}</label>`);
document.write(`</div>`);
}
</script>
<div class="skills">
Осталось (осн/доп): <span id="skills_result_selected"></span>/<span id="skills_result_unselected"></span>
</div>
<script>
document.write(`<p id="skills${message_suffix}"></p>`);
</script>
</p>
<script>
updateAfterLoading();
</script>
</body>
</html>