refactor: Redesign calendar as compact sidebar box with improved layout

- Changed calendar from full sidebar to compact containerized box
- Reduced calendar size (190px width) to minimize space usage
- Increased main container max-width from 600px to 850px for two-column layout
- Added proper styling for .main element (white background, shadow, padding)
- Improved visual hierarchy with matching design patterns
- Updated CSS version for cache busting
This commit is contained in:
Fovway 2025-10-18 00:39:21 +07:00
parent 076bbba2e8
commit 7def129e14
15 changed files with 204 additions and 576 deletions

8
.gitignore vendored
View File

@ -33,4 +33,12 @@ Thumbs.db
dist/ dist/
build/ build/
# Загруженные аватарки пользователей
public/uploads/*
!public/uploads/.gitignore
# Временные файлы
/tmp/
*.tmp
.cursor/ .cursor/

247
app.js
View File

@ -1,247 +0,0 @@
const textInput = document.querySelector(".textInput");
const btnSave = document.querySelector(".btnSave");
const notes = document.querySelector(".notes-container");
// Получаем кнопки
const boldBtn = document.getElementById("boldBtn");
const italicBtn = document.getElementById("italicBtn");
const headerBtn = document.getElementById("headerBtn");
const listBtn = document.getElementById("listBtn");
const quoteBtn = document.getElementById("quoteBtn");
const codeBtn = document.getElementById("codeBtn");
const linkBtn = document.getElementById("linkBtn");
function getFormattedDateTime() {
let now = new Date();
let day = String(now.getDate()).padStart(2, "0");
let month = String(now.getMonth() + 1).padStart(2, "0");
let year = now.getFullYear();
let hours = String(now.getHours()).padStart(2, "0");
let minutes = String(now.getMinutes()).padStart(2, "0");
return {
date: `${day}.${month}.${year}`,
time: `${hours}:${minutes}`,
};
}
// Сохранить заметки в localStorage
function saveNotesToLocalStorage(notesArr) {
localStorage.setItem("notes", JSON.stringify(notesArr));
}
// Получить заметки из localStorage
function getNotesFromLocalStorage() {
return JSON.parse(localStorage.getItem("notes")) || [];
}
// Обновить функцию renderNotes
function renderNotes() {
const notesArr = getNotesFromLocalStorage();
notes.innerHTML = ""; // Очищаем контейнер перед рендерингом
notesArr.forEach(function (content, index) {
const noteHtml = `
<div id="note" class="container">
<div class="date">
${content.date} ${content.time}
<div id="editBtn" class="notesHeaderBtn" data-index="${index}">Редактировать</div>
<div id="deleteBtn" class="notesHeaderBtn" data-index="${index}">Удалить</div>
</div>
<div class="textNote">${marked.parse(content.content)}</div>
</div>
`;
notes.insertAdjacentHTML("afterbegin", noteHtml);
});
deleteNote();
editNote();
}
// Обновить функцию saveNote
function saveNote() {
btnSave.addEventListener("click", function () {
if (textInput.value.trim() !== "") {
let { date, time } = getFormattedDateTime();
const note = {
content: textInput.value,
date: date,
time: time,
};
const notesArr = getNotesFromLocalStorage();
notesArr.push(note);
saveNotesToLocalStorage(notesArr);
textInput.value = "";
textInput.style.height = "auto"; // Сбрасываем размер текстового поля
renderNotes();
}
});
}
// Обновить функцию deleteNote
function deleteNote() {
document.querySelectorAll("#deleteBtn").forEach((btn) => {
btn.addEventListener("click", function (event) {
let index = event.target.dataset.index;
const notesArr = getNotesFromLocalStorage();
notesArr.splice(index, 1);
saveNotesToLocalStorage(notesArr);
renderNotes();
});
});
}
// Обновить функцию editNote
function editNote() {
document.querySelectorAll("#editBtn").forEach((btn) => {
btn.addEventListener("click", function (event) {
let index = event.target.dataset.index;
let noteContainer = event.target.closest("#note");
let noteContent = noteContainer.querySelector(".textNote");
// Создаем textarea с уже существующим классом textInput
let textarea = document.createElement("textarea");
textarea.classList.add("textInput");
textarea.value = noteContent.textContent;
// Привязываем авторасширение к textarea для редактирования
textarea.addEventListener("input", function () {
autoExpandTextarea(textarea);
});
autoExpandTextarea(textarea);
// Кнопка сохранить
let saveEditBtn = document.createElement("button");
saveEditBtn.textContent = "Сохранить";
saveEditBtn.classList.add("btnSave");
// Очищаем текущий контент и вставляем textarea и кнопку сохранить
noteContent.innerHTML = "";
noteContent.appendChild(textarea);
noteContent.appendChild(saveEditBtn);
saveEditBtn.addEventListener("click", function () {
if (textarea.value.trim() !== "") {
let { date, time } = getFormattedDateTime();
const notesArr = getNotesFromLocalStorage();
notesArr[index] = {
content: textarea.value,
date: date,
time: time,
};
saveNotesToLocalStorage(notesArr);
renderNotes();
}
});
});
});
}
// Функция для авторасширения текстового поля
function autoExpandTextarea(textarea) {
textarea.style.height = "auto";
textarea.style.height = textarea.scrollHeight + "px";
}
// Привязываем авторасширение к текстовому полю для создания заметки
textInput.addEventListener("input", function () {
autoExpandTextarea(textInput);
});
// Изначально запускаем для установки правильной высоты
autoExpandTextarea(textInput);
function insertMarkdown(tag) {
const start = textInput.selectionStart;
const end = textInput.selectionEnd;
const text = textInput.value;
const before = text.substring(0, start);
const selected = text.substring(start, end);
const after = text.substring(end);
if (selected.startsWith(tag) && selected.endsWith(tag)) {
// Если теги уже есть, удаляем их
textInput.value = `${before}${selected.slice(
tag.length,
-tag.length
)}${after}`;
textInput.setSelectionRange(start, end - 2 * tag.length);
} else if (selected.trim() === "") {
// Если текст не выделен
if (tag === "[Текст ссылки](URL)") {
// Для ссылок создаем шаблон с двумя кавычками
textInput.value = `${before}[Текст ссылки](URL)${after}`;
const cursorPosition = start + 1; // Помещаем курсор внутрь текста ссылки
textInput.setSelectionRange(cursorPosition, cursorPosition + 12);
} else if (tag === "- " || tag === "> " || tag === "# ") {
// Для списка, цитаты и заголовка помещаем курсор после `- `, `> ` или `# `
textInput.value = `${before}${tag}${after}`;
const cursorPosition = start + tag.length;
textInput.setSelectionRange(cursorPosition, cursorPosition);
} else {
// Для остальных типов создаем два тега
textInput.value = `${before}${tag}${tag}${after}`;
const cursorPosition = start + tag.length;
textInput.setSelectionRange(cursorPosition, cursorPosition);
}
} else {
// Если текст выделен
if (tag === "[Текст ссылки](URL)") {
// Для ссылок используем выделенный текст вместо "Текст ссылки"
textInput.value = `${before}[${selected}](URL)${after}`;
const cursorPosition = start + selected.length + 3; // Помещаем курсор в URL
textInput.setSelectionRange(cursorPosition, cursorPosition + 3);
} else if (tag === "- " || tag === "> " || tag === "# ") {
// Для списка, цитаты и заголовка добавляем `- `, `> ` или `# ` перед выделенным текстом
textInput.value = `${before}${tag}${selected}${after}`;
const cursorPosition = start + tag.length + selected.length;
textInput.setSelectionRange(cursorPosition, cursorPosition);
} else {
// Для остальных типов оборачиваем выделенный текст
textInput.value = `${before}${tag}${selected}${tag}${after}`;
const cursorPosition = start + tag.length + selected.length + tag.length;
textInput.setSelectionRange(cursorPosition, cursorPosition);
}
}
textInput.focus();
}
// Обработчики для кнопок
boldBtn.addEventListener("click", function () {
insertMarkdown("**"); // Вставляем жирный текст
});
italicBtn.addEventListener("click", function () {
insertMarkdown("*"); // Вставляем курсив
});
headerBtn.addEventListener("click", function () {
insertMarkdown("# "); // Вставляем заголовок
});
listBtn.addEventListener("click", function () {
insertMarkdown("- "); // Вставляем элемент списка
});
quoteBtn.addEventListener("click", function () {
insertMarkdown("> "); // Вставляем цитату
});
codeBtn.addEventListener("click", function () {
insertMarkdown("`"); // Вставляем код
});
linkBtn.addEventListener("click", function () {
insertMarkdown("[Текст ссылки](URL)"); // Вставляем ссылку
});
// Удалено дублирование добавления кнопок Markdown в окно сохранения заметки
// Кнопки уже добавлены в HTML (index.html), поэтому их повторное создание не требуется
renderNotes();
saveNote();

BIN
favicon-16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 B

BIN
favicon-32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

BIN
favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 708 B

BIN
icon-192.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 921 B

BIN
icon-512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -1,72 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="style.css" />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"
/>
</head>
<body>
<div class="container">
<header>Заметки</header>
<div class="main">
<div class="markdown-buttons">
<button class="btnMarkdown" id="boldBtn">
<i class="fas fa-bold"></i>
<!-- Иконка для жирного текста -->
</button>
<button class="btnMarkdown" id="italicBtn">
<i class="fas fa-italic"></i>
<!-- Иконка для курсива -->
</button>
<button class="btnMarkdown" id="headerBtn">
<i class="fas fa-heading"></i>
<!-- Иконка для заголовка -->
</button>
<button class="btnMarkdown" id="listBtn">
<i class="fas fa-list-ul"></i>
<!-- Иконка для списка -->
</button>
<button class="btnMarkdown" id="quoteBtn">
<i class="fas fa-quote-right"></i>
<!-- Иконка для цитаты -->
</button>
<button class="btnMarkdown" id="codeBtn">
<i class="fas fa-code"></i>
<!-- Иконка для кода -->
</button>
<button class="btnMarkdown" id="linkBtn">
<i class="fas fa-link"></i>
<!-- Иконка для ссылки -->
</button>
</div>
<textarea
class="textInput"
name=""
id=""
placeholder="Ваша заметка..."
></textarea>
<button class="btnSave">Сохранить</button>
</div>
</div>
<div class="notes-container">
<div id="note" class="container">
<div class="date">
<div class="notesHeaderBtn"></div>
<div class="notesHeaderBtn"></div>
</div>
<div class="textNote"></div>
</div>
</div>
<div class="footer">
<p>Создатель: <span>Fovway</span></p>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/11.1.0/marked.min.js"></script>
<script src="app.js"></script>
</body>
</html>

View File

@ -7,12 +7,12 @@
"theme_color": "#000000", "theme_color": "#000000",
"icons": [ "icons": [
{ {
"src": "project.png", "src": "icon-192.png",
"sizes": "192x192", "sizes": "192x192",
"type": "image/png" "type": "image/png"
}, },
{ {
"src": "project.png", "src": "icon-512.png",
"sizes": "512x512", "sizes": "512x512",
"type": "image/png" "type": "image/png"
} }

View File

@ -1,2 +0,0 @@
✅ 1. Сделать создание заметки по нажатию alt + enter. И написать подсказку возле кнопки Сохранить.
✅ 2. Добавить личный кабинет, который открывается при нажатии на свой ник. В личном кабинете можно менять регистрационные данные, а так же привязать свой эмейл и поставить аватарку. Картинки аватарки загружаются на сервер.

View File

@ -4,7 +4,7 @@
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Заметки</title> <title>Заметки</title>
<link rel="stylesheet" href="/style.css?v=2" /> <link rel="stylesheet" href="/style.css?v=5" />
<link <link
rel="stylesheet" rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"
@ -42,25 +42,23 @@
<div class="main-wrapper"> <div class="main-wrapper">
<!-- Календарь слева --> <!-- Календарь слева -->
<aside class="calendar-sidebar"> <div class="calendar-box">
<div class="calendar-container"> <div class="calendar-header">
<div class="calendar-header"> <button id="prevMonth" class="calendar-nav-btn">&lt;</button>
<button id="prevMonth" class="calendar-nav-btn">&lt;</button> <h3 id="calendarTitle"></h3>
<h3 id="calendarTitle"></h3> <button id="nextMonth" class="calendar-nav-btn">&gt;</button>
<button id="nextMonth" class="calendar-nav-btn">&gt;</button>
</div>
<div class="calendar-weekdays">
<div class="weekday">Пн</div>
<div class="weekday">Вт</div>
<div class="weekday">Ср</div>
<div class="weekday">Чт</div>
<div class="weekday">Пт</div>
<div class="weekday">Сб</div>
<div class="weekday">Вс</div>
</div>
<div id="calendarDays" class="calendar-days"></div>
</div> </div>
</aside> <div class="calendar-weekdays">
<div class="weekday">Пн</div>
<div class="weekday">Вт</div>
<div class="weekday">Ср</div>
<div class="weekday">Чт</div>
<div class="weekday">Пт</div>
<div class="weekday">Сб</div>
<div class="weekday">Вс</div>
</div>
<div id="calendarDays" class="calendar-days"></div>
</div>
<!-- Основной контент с формой заметки --> <!-- Основной контент с формой заметки -->
<div class="main"> <div class="main">

144
public/style-calendar.css Normal file
View File

@ -0,0 +1,144 @@
/* Компактные стили для календаря */
.main-wrapper {
display: flex;
gap: 15px;
align-items: flex-start;
width: 100%;
}
.calendar-box {
flex-shrink: 0;
width: 190px;
background: white;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
border-radius: 8px;
padding: 10px;
}
.calendar-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
gap: 4px;
}
.calendar-header h3 {
margin: 0;
font-size: 11px;
font-weight: 600;
color: #333;
min-width: 75px;
text-align: center;
flex: 1;
}
.calendar-nav-btn {
background: #f0f0f0;
border: 1px solid #ddd;
border-radius: 3px;
padding: 2px 5px;
cursor: pointer;
font-size: 11px;
color: #333;
transition: all 0.2s ease;
}
.calendar-nav-btn:hover {
background: #007bff;
color: white;
border-color: #007bff;
}
.calendar-weekdays {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 1px;
margin-bottom: 5px;
}
.weekday {
text-align: center;
font-size: 8px;
font-weight: 600;
color: #666;
padding: 1px 0;
text-transform: uppercase;
}
.calendar-days {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 1px;
}
.calendar-day {
aspect-ratio: 1;
display: flex;
align-items: center;
justify-content: center;
font-size: 10px;
border-radius: 3px;
cursor: pointer;
background: #f8f9fa;
color: #666;
border: 1px solid transparent;
transition: all 0.2s ease;
position: relative;
}
.calendar-day:hover {
background: #e8f4f8;
border-color: #007bff;
}
.calendar-day.other-month {
color: #ccc;
background: #fafafa;
}
.calendar-day.today {
background: #007bff;
color: white;
font-weight: 600;
border-color: #0056cc;
}
.calendar-day.today:hover {
background: #0056cc;
}
.calendar-day.selected {
background: #28a745;
color: white;
font-weight: 600;
border-color: #1e7e34;
}
.calendar-day.selected:hover {
background: #1e7e34;
}
.main {
flex: 1;
min-width: 300px;
}
/* Адаптация для мобильных устройств */
@media (max-width: 768px) {
.main-wrapper {
flex-direction: column;
}
.calendar-box {
width: 100%;
}
.main {
min-width: auto;
}
.container {
max-width: 100%;
}
}

View File

@ -66,7 +66,7 @@ header {
.container { .container {
width: 90%; width: 90%;
max-width: 600px; max-width: 850px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
border-radius: 8px; border-radius: 8px;
padding: 15px; padding: 15px;
@ -440,41 +440,39 @@ textarea:focus {
text-decoration: underline; text-decoration: underline;
} }
/* Стили для календаря */
/* ========== Стили для компактного календаря ========== */
.main-wrapper { .main-wrapper {
display: flex; display: flex;
gap: 20px; gap: 15px;
align-items: flex-start; align-items: flex-start;
width: 100%; width: 100%;
} }
.calendar-sidebar { .calendar-box {
flex-shrink: 0; flex-shrink: 0;
width: 240px; width: 190px;
}
.calendar-container {
background: white; background: white;
border: 1px solid #e0e0e0; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
border-radius: 8px; border-radius: 8px;
padding: 15px; padding: 10px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
} }
.calendar-header { .calendar-header {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
margin-bottom: 15px; margin-bottom: 8px;
gap: 10px; gap: 4px;
} }
.calendar-header h3 { .calendar-header h3 {
margin: 0; margin: 0;
font-size: 14px; font-size: 11px;
font-weight: 600; font-weight: 600;
color: #333; color: #333;
min-width: 120px; min-width: 75px;
text-align: center; text-align: center;
flex: 1; flex: 1;
} }
@ -482,10 +480,10 @@ textarea:focus {
.calendar-nav-btn { .calendar-nav-btn {
background: #f0f0f0; background: #f0f0f0;
border: 1px solid #ddd; border: 1px solid #ddd;
border-radius: 4px; border-radius: 3px;
padding: 4px 8px; padding: 2px 5px;
cursor: pointer; cursor: pointer;
font-size: 14px; font-size: 11px;
color: #333; color: #333;
transition: all 0.2s ease; transition: all 0.2s ease;
} }
@ -499,23 +497,23 @@ textarea:focus {
.calendar-weekdays { .calendar-weekdays {
display: grid; display: grid;
grid-template-columns: repeat(7, 1fr); grid-template-columns: repeat(7, 1fr);
gap: 2px; gap: 1px;
margin-bottom: 10px; margin-bottom: 5px;
} }
.weekday { .weekday {
text-align: center; text-align: center;
font-size: 11px; font-size: 8px;
font-weight: 600; font-weight: 600;
color: #666; color: #666;
padding: 5px 0; padding: 1px 0;
text-transform: uppercase; text-transform: uppercase;
} }
.calendar-days { .calendar-days {
display: grid; display: grid;
grid-template-columns: repeat(7, 1fr); grid-template-columns: repeat(7, 1fr);
gap: 2px; gap: 1px;
} }
.calendar-day { .calendar-day {
@ -523,8 +521,8 @@ textarea:focus {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
font-size: 12px; font-size: 10px;
border-radius: 4px; border-radius: 3px;
cursor: pointer; cursor: pointer;
background: #f8f9fa; background: #f8f9fa;
color: #666; color: #666;
@ -565,24 +563,6 @@ textarea:focus {
background: #1e7e34; background: #1e7e34;
} }
.calendar-day.has-notes {
font-weight: 600;
color: #007bff;
}
.calendar-day.has-notes::before {
content: '';
display: block;
width: 4px;
height: 4px;
background: #007bff;
border-radius: 50%;
position: absolute;
bottom: 2px;
left: 50%;
transform: translateX(-50%);
}
.main { .main {
flex: 1; flex: 1;
min-width: 300px; min-width: 300px;
@ -594,19 +574,23 @@ textarea:focus {
flex-direction: column; flex-direction: column;
} }
.calendar-sidebar { .calendar-box {
width: 100%; width: 100%;
} }
.calendar-container {
max-width: 100%;
}
.main { .main {
min-width: auto; min-width: auto;
} }
.container { .container {
max-width: 900px; max-width: 100%;
} }
} }
/* Стиль для основного блока заметок */
.main {
background: white;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
border-radius: 8px;
padding: 15px;
}

View File

@ -1,7 +0,0 @@
self.addEventListener("install", (event) => {
console.log("Service Worker установлен.");
});
self.addEventListener("fetch", (event) => {
console.log("Обработан запрос:", event.request.url);
});

178
style.css
View File

@ -1,178 +0,0 @@
body {
font-family: "Open Sans", sans-serif;
padding: 0;
margin: 0;
display: flex;
flex-wrap: wrap;
justify-content: center;
background: #f5f5f5;
}
header {
font-size: 20px;
font-weight: bold;
margin-bottom: 20px;
}
.container {
width: 90%;
max-width: 600px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
border-radius: 8px;
padding: 15px;
margin-top: 20px;
background: white;
}
textarea {
width: 100%;
min-height: 50px; /* Минимальная высота */
resize: none; /* Отключаем возможность ручного изменения размера */
border: none;
background: white;
margin-bottom: 5px;
overflow-y: hidden; /* Отключаем полосу прокрутки по вертикали */
}
textarea:focus {
outline: none; /* Убираем обводку */
}
.btnSave {
padding: 5px;
cursor: pointer;
border-width: 1px;
background: white;
border-radius: 5px;
font-family: "Open Sans", sans-serif;
transition: all 0.3s ease;
}
.date {
font-size: 11px;
color: grey;
}
.notesHeaderBtn {
display: inline-block;
cursor: pointer;
color: black;
font-weight: bold;
}
.textNote {
margin-top: 10px;
white-space: pre-wrap;
}
/* Убираем стандартные отступы для абзацев */
.textNote p {
margin: 0;
padding: 0;
}
/* Убираем маргины у заголовков */
.textNote h1,
.textNote h2,
.textNote h3,
.textNote h4,
.textNote h5,
.textNote h6 {
margin: 0;
padding: 0;
}
/* Убираем отступы у списков */
.textNote ul,
.textNote ol {
margin: 0;
padding-left: 20px;
}
/* Убираем маргины у элементов списка */
.textNote li {
margin: 0;
padding: 0;
}
/* Стили для ссылок */
.textNote a {
color: #007bff;
text-decoration: none;
}
.textNote a:hover {
text-decoration: underline;
}
/* Стили для цитат */
.textNote blockquote {
border-left: 4px solid #007bff;
padding-left: 16px;
margin: 10px 0;
color: #555;
font-style: italic;
background-color: #f8f9fa;
padding: 10px 16px;
border-radius: 0 4px 4px 0;
}
.textNote blockquote p {
margin: 0;
}
/* Стили для кода */
.textNote pre {
background-color: #f5f5f5;
padding: 10px;
border-radius: 5px;
font-size: 14px;
overflow-x: auto;
}
.textNote code {
background-color: #f5f5f5;
padding: 2px 4px;
border-radius: 5px;
font-size: 14px;
}
.notes-container {
width: 100%;
display: flex;
flex-direction: column; /* Располагаем элементы в колонку */
align-items: center; /* Центрируем */
}
.markdown-buttons {
margin-top: 10px;
margin-bottom: 10px;
}
.markdown-buttons .btnMarkdown {
padding: 5px 10px;
margin-right: 5px;
cursor: pointer;
border: 1px solid #ddd;
background-color: #f0f0f0;
border-radius: 5px;
font-size: 14px;
}
.markdown-buttons .btnMarkdown:hover {
background-color: #e0e0e0;
}
.footer {
text-align: center;
font-size: 12px;
color: #999;
position: fixed;
bottom: 0;
width: 100%;
padding: 10px 0;
}
.footer span {
font-weight: bold;
}