backup
This commit is contained in:
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"liveServer.settings.port": 5501
|
||||
}
|
||||
56
edit_script/add_entry.py
Normal file
56
edit_script/add_entry.py
Normal file
@@ -0,0 +1,56 @@
|
||||
import datetime
|
||||
FIELDS = ['title', 'subtitle', 'content', 'displayall']
|
||||
def add_entry(file_path, title, subtitle, content, display_all=False):
|
||||
# 1. Import the current list to get the latest ID
|
||||
# We use a namespace to avoid path issues
|
||||
namespace = {}
|
||||
with open(file_path, 'r') as f:
|
||||
exec(f.read(), namespace)
|
||||
|
||||
posts = namespace.get('BLOG_POSTS', [])
|
||||
new_id = max([p['id'] for p in posts], default=0) + 1
|
||||
print("new id", new_id)
|
||||
# 2. Format the new entry string
|
||||
date_str = datetime.datetime.now().strftime("%B %d, %Y")
|
||||
|
||||
new_post_str = f"""
|
||||
{{
|
||||
'id': {new_id},
|
||||
'title': '{title}',
|
||||
'content': \"\"\"
|
||||
{content}
|
||||
\"\"\",
|
||||
'subtitle': '{subtitle}',
|
||||
'date': '{date_str}',
|
||||
"displayall": {display_all}
|
||||
}},
|
||||
"""
|
||||
|
||||
# 3. Append to the file
|
||||
# Note: This appends to the END of the file.
|
||||
# If your file ends with ']', we need to strip that first.
|
||||
with open(file_path, 'r+') as f:
|
||||
content_full = f.read().strip()
|
||||
# Find the last closing bracket of the list
|
||||
if content_full.endswith(']'):
|
||||
content_full = content_full.rsplit(']', 1)[0]
|
||||
|
||||
f.seek(0)
|
||||
f.write(content_full + new_post_str + "\n]")
|
||||
f.truncate()
|
||||
|
||||
print(f"Successfully added Post #{new_id}: {title}")
|
||||
|
||||
# Usage
|
||||
if __name__ == "__main__":
|
||||
#t = input("Title: ")
|
||||
#s = input("Subtitle: ")
|
||||
#c = input("Content (HTML): ")
|
||||
|
||||
# title
|
||||
t = "I have a solution but it only works for spherical chickens in a vacuum!"
|
||||
# subtitle
|
||||
s = ""
|
||||
# content
|
||||
c = "no content"
|
||||
add_entry('content/posts.py', t, s, c)
|
||||
158
edit_script/edit_entry.ipynb
Normal file
158
edit_script/edit_entry.ipynb
Normal file
@@ -0,0 +1,158 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "090c7992",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"\n",
|
||||
" im still struggling:\n",
|
||||
" </p>\n",
|
||||
" <p>sudo pacman -S archlinux-keyring</p>\n",
|
||||
" <p>melange:</p>\n",
|
||||
" <ul>\n",
|
||||
" <li><a href=\"/page2/line/lineplot.html\">machine learning with failed hyperparams</a></li>\n",
|
||||
" <li><a href=\"/page2/dblp/bar/index.html\">the dblp dataset in bar plot</a></li>\n",
|
||||
" <li><a href=\"/page2/dblp/edge/index.html\">the dblp dataset with an example of community</a></li>\n",
|
||||
" <li><a href=\"/page2/dblp/full/index.html\">the dblp dataset of 5 years as a graph</a></li>\n",
|
||||
" <li><a href=\"/page2/dblp/time/index.html\">the generated links as a graph</a></li>\n",
|
||||
"\n",
|
||||
" </ul>\n",
|
||||
"\n",
|
||||
"Post 3 updated successfully.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import datetime\n",
|
||||
"\n",
|
||||
"def get_entry(file_path, id):\n",
|
||||
"\n",
|
||||
" # 1. Import the current list to get the latest ID\n",
|
||||
"\n",
|
||||
" # We use a namespace to avoid path issues\n",
|
||||
"\n",
|
||||
" namespace = {}\n",
|
||||
"\n",
|
||||
" with open(file_path, 'r') as f:\n",
|
||||
"\n",
|
||||
" exec(f.read(), namespace)\n",
|
||||
"\n",
|
||||
" posts = namespace.get('BLOG_POSTS', [])\n",
|
||||
"\n",
|
||||
" for items in posts:\n",
|
||||
"\n",
|
||||
" if items.get(\"id\") == id:\n",
|
||||
"\n",
|
||||
" content = items.get('content')\n",
|
||||
"\n",
|
||||
" print(content)\n",
|
||||
"\n",
|
||||
" return items \n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def update_entry(file_path, post_id, new_content):\n",
|
||||
" # 1. Load the existing data into memory\n",
|
||||
" namespace = {}\n",
|
||||
" with open(file_path, 'r') as f:\n",
|
||||
" exec(f.read(), namespace)\n",
|
||||
" \n",
|
||||
" posts = namespace.get('BLOG_POSTS', [])\n",
|
||||
" \n",
|
||||
" # 2. Find and update the specific post\n",
|
||||
" found = False\n",
|
||||
" for post in posts:\n",
|
||||
" if post.get(\"id\") == post_id:\n",
|
||||
" post['content'] = new_content\n",
|
||||
" # Optional: Update the date or add an \"updated\" field\n",
|
||||
" # post['subtitle'] += \" (Updated)\" \n",
|
||||
" found = True\n",
|
||||
" break\n",
|
||||
" \n",
|
||||
" if not found:\n",
|
||||
" print(f\"Error: Post {post_id} not found.\")\n",
|
||||
" return\n",
|
||||
"\n",
|
||||
" # 3. Write the entire list back to the file\n",
|
||||
" # Using repr() or a loop to format it cleanly\n",
|
||||
" with open(file_path, 'w') as f:\n",
|
||||
" f.write(\"BLOG_POSTS = [\\n\")\n",
|
||||
" for p in posts:\n",
|
||||
" # Use .get() to provide a default value if the key is missing\n",
|
||||
" display_val = p.get('displayall', False) \n",
|
||||
" data_val = p.get('date', \"?\") \n",
|
||||
" subtitle_val = p.get('subtitle', \"\") \n",
|
||||
" \n",
|
||||
" entry = f\"\"\" {{\n",
|
||||
" 'id': {p['id']},\n",
|
||||
" 'title': \"{p['title']}\",\n",
|
||||
" 'subtitle': \"{subtitle_val}\",\n",
|
||||
" 'date': \"{data_val}\",\n",
|
||||
" 'content': \\\"\\\"\\\"{p['content']}\\\"\\\"\\\",\n",
|
||||
" \"displayall\": {display_val}\n",
|
||||
" }},\\n\"\"\"\n",
|
||||
" f.write(entry)\n",
|
||||
" f.write(\"]\\n\")\n",
|
||||
" \n",
|
||||
" print(f\"Post {post_id} updated successfully.\")\n",
|
||||
"\n",
|
||||
"# --- Usage Example ---\n",
|
||||
"if __name__ == \"__main__\":\n",
|
||||
" file = '../content/posts.py'\n",
|
||||
" target_id = 3\n",
|
||||
" \n",
|
||||
" # Get the old one first to see it\n",
|
||||
" old_post = get_entry(file, target_id)\n",
|
||||
" \n",
|
||||
" if old_post:\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
" new_text=\"\"\"\n",
|
||||
" <p>sudo pacman -S archlinux-keyring</p>\n",
|
||||
" <p>sudo pacman -Sc</p>\n",
|
||||
" <p>melange:</p>\n",
|
||||
" <ul>\n",
|
||||
" <li><a href=\"/page2/line/lineplot.html\">machine learning with failed hyperparams</a></li>\n",
|
||||
" <li><a href=\"/page2/dblp/bar/index.html\">the dblp dataset in bar plot</a></li>\n",
|
||||
" <li><a href=\"/page2/dblp/edge/index.html\">the dblp dataset with an example of community</a></li>\n",
|
||||
" <li><a href=\"/page2/dblp/full/index.html\">the dblp dataset of 5 years as a graph</a></li>\n",
|
||||
" <li><a href=\"/page2/dblp/time/index.html\">the generated links as a graph</a></li>\n",
|
||||
"\n",
|
||||
" </ul>\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" \"\"\"\n",
|
||||
" \n",
|
||||
" \n",
|
||||
" update_entry(file, target_id, new_text)\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "base",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.7"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
230
edit_script/note.html
Normal file
230
edit_script/note.html
Normal file
@@ -0,0 +1,230 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Pro Sticky Board (Safe Mode)</title>
|
||||
<style>
|
||||
body {
|
||||
background-color: #f0f0f0;
|
||||
font-family: sans-serif;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
#controls {
|
||||
margin-bottom: 30px;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
background: white;
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 10px 15px;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
font-weight: bold;
|
||||
transition: 0.2s;
|
||||
}
|
||||
|
||||
.add-btn {
|
||||
background-color: #4caf50;
|
||||
color: white;
|
||||
}
|
||||
.export-btn {
|
||||
background-color: #2196f3;
|
||||
color: white;
|
||||
}
|
||||
.import-btn {
|
||||
background-color: #9c27b0;
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* The Safety Toggle Button */
|
||||
.lock-btn {
|
||||
background-color: #ff9800;
|
||||
color: white;
|
||||
margin-left: auto; /* Push to the right */
|
||||
}
|
||||
.lock-btn.active {
|
||||
background-color: #f44336;
|
||||
}
|
||||
|
||||
.board {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.sticky-note {
|
||||
width: 220px;
|
||||
height: 220px;
|
||||
padding: 15px;
|
||||
background-color: #fff740;
|
||||
box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.sticky-note textarea {
|
||||
background: transparent;
|
||||
border: none;
|
||||
resize: none;
|
||||
flex-grow: 1;
|
||||
font-size: 16px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* Hidden by default */
|
||||
.delete-btn {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 8px;
|
||||
cursor: pointer;
|
||||
color: #d32f2f;
|
||||
font-size: 22px;
|
||||
display: none;
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
border-radius: 50%;
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
text-align: center;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
/* Only show when the board has the 'edit-mode' class */
|
||||
.board.edit-mode .delete-btn {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#fileInput {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="controls">
|
||||
<button class="add-btn" onclick="addNote()">+ New Note</button>
|
||||
<button class="export-btn" onclick="exportNotes()">Dump JSON</button>
|
||||
<button
|
||||
class="import-btn"
|
||||
onclick="document.getElementById('fileInput').click()"
|
||||
>
|
||||
Load JSON
|
||||
</button>
|
||||
<input
|
||||
type="file"
|
||||
id="fileInput"
|
||||
accept=".json"
|
||||
onchange="importNotes(event)"
|
||||
/>
|
||||
|
||||
<button id="lockBtn" class="lock-btn" onclick="toggleEditMode()">
|
||||
🔓 Enable Deletion
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="board" id="board"></div>
|
||||
|
||||
<script>
|
||||
const board = document.getElementById("board");
|
||||
const lockBtn = document.getElementById("lockBtn");
|
||||
let isEditMode = false;
|
||||
|
||||
document.addEventListener("DOMContentLoaded", loadFromStorage);
|
||||
|
||||
function toggleEditMode() {
|
||||
isEditMode = !isEditMode;
|
||||
board.classList.toggle("edit-mode", isEditMode);
|
||||
|
||||
if (isEditMode) {
|
||||
lockBtn.innerHTML = "🔒 Lock Deletion";
|
||||
lockBtn.classList.add("active");
|
||||
} else {
|
||||
lockBtn.innerHTML = "🔓 Enable Deletion";
|
||||
lockBtn.classList.remove("active");
|
||||
}
|
||||
}
|
||||
|
||||
function createNoteElement(content) {
|
||||
const element = document.createElement("div");
|
||||
element.classList.add("sticky-note");
|
||||
|
||||
const textarea = document.createElement("textarea");
|
||||
textarea.value = content;
|
||||
textarea.placeholder = "Type here...";
|
||||
|
||||
const deleteBtn = document.createElement("span");
|
||||
deleteBtn.classList.add("delete-btn");
|
||||
deleteBtn.innerHTML = "×";
|
||||
deleteBtn.onclick = () => {
|
||||
if (confirm("Delete this note?")) {
|
||||
element.remove();
|
||||
saveToStorage();
|
||||
}
|
||||
};
|
||||
|
||||
textarea.addEventListener("input", saveToStorage);
|
||||
|
||||
element.appendChild(deleteBtn);
|
||||
element.appendChild(textarea);
|
||||
return element;
|
||||
}
|
||||
|
||||
function addNote(text = "") {
|
||||
board.appendChild(createNoteElement(text));
|
||||
saveToStorage();
|
||||
}
|
||||
|
||||
function saveToStorage() {
|
||||
const notes = Array.from(
|
||||
document.querySelectorAll(".sticky-note textarea")
|
||||
).map((n) => n.value);
|
||||
localStorage.setItem("sticky-notes", JSON.stringify(notes));
|
||||
}
|
||||
|
||||
function loadFromStorage() {
|
||||
const notes = JSON.parse(localStorage.getItem("sticky-notes") || "[]");
|
||||
notes.forEach((text) => board.appendChild(createNoteElement(text)));
|
||||
}
|
||||
|
||||
function exportNotes() {
|
||||
const notes = Array.from(
|
||||
document.querySelectorAll(".sticky-note textarea")
|
||||
).map((n) => n.value);
|
||||
const blob = new Blob([JSON.stringify(notes, null, 2)], {
|
||||
type: "application/json",
|
||||
});
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.download = `my-notes-${new Date().toISOString().slice(0, 10)}.json`;
|
||||
a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
function importNotes(event) {
|
||||
const file = event.target.files[0];
|
||||
if (!file) return;
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
try {
|
||||
const notes = JSON.parse(e.target.result);
|
||||
if (confirm("Replace current board?")) {
|
||||
board.innerHTML = "";
|
||||
notes.forEach((text) => addNote(text));
|
||||
}
|
||||
} catch (err) {
|
||||
alert("Invalid JSON file.");
|
||||
}
|
||||
};
|
||||
reader.readAsText(file);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
31
static/css/components/timeline.css
Normal file
31
static/css/components/timeline.css
Normal file
@@ -0,0 +1,31 @@
|
||||
.timeline-button {
|
||||
position: absolute;
|
||||
left: -0.375rem;
|
||||
|
||||
width: 0.75rem;
|
||||
height: 0.75rem;
|
||||
|
||||
border-radius: 9999px;
|
||||
|
||||
background: #d1d5db;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
font-size: 10px;
|
||||
line-height: 1;
|
||||
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
/* hover only when expanded */
|
||||
.timeline-button:hover:not(.collapsed) {
|
||||
background: #6b7280;
|
||||
}
|
||||
|
||||
/* collapsed state */
|
||||
.timeline-button.collapsed {
|
||||
background: transparent !important;
|
||||
color: #6b7280;
|
||||
}
|
||||
90
test_style/expand_style.html
Normal file
90
test_style/expand_style.html
Normal file
@@ -0,0 +1,90 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="description" content="" />
|
||||
<meta name="author" content="" />
|
||||
|
||||
<title>Home</title>
|
||||
|
||||
<!-- Bootstrap Core CSS -->
|
||||
<link href="../static/css/bootstrap.min.css" rel="stylesheet" />
|
||||
|
||||
<!-- Custom CSS -->
|
||||
<link href="../static/css/simple-blog-template.css" rel="stylesheet" />
|
||||
|
||||
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
|
||||
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
|
||||
<!--[if lt IE 9]>
|
||||
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
|
||||
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
|
||||
<![endif]-->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- Navigation -->
|
||||
<nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
|
||||
<div class="container">
|
||||
<!-- Brand and toggle get grouped for better mobile display -->
|
||||
<div class="navbar-header">
|
||||
<button
|
||||
type="button"
|
||||
class="navbar-toggle"
|
||||
data-toggle="collapse"
|
||||
data-target="#bs-example-navbar-collapse-1"
|
||||
>
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="index.html"
|
||||
>Index Page - Under Construction</a
|
||||
>
|
||||
</div>
|
||||
<!-- Collect the nav links, forms, and other content for toggling -->
|
||||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li>
|
||||
<a href="about.html">About</a>
|
||||
</li>
|
||||
<!--li>
|
||||
<a href="login.html">Login</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="signup.html">Sign up</a>
|
||||
</li-->
|
||||
</ul>
|
||||
</div>
|
||||
<!-- /.navbar-collapse -->
|
||||
</div>
|
||||
<!-- /.container -->
|
||||
</nav>
|
||||
|
||||
<!-- Page Content -->
|
||||
<div class="container">{% block content %} {% endblock %}</div>
|
||||
|
||||
<!-- /.container -->
|
||||
|
||||
<!-- Footer -->
|
||||
<footer>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<p>Last Update: October 2024</p>
|
||||
</div>
|
||||
<!-- /.col-lg-12 -->
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<!-- jQuery -->
|
||||
<script src="../static/js/jquery.js"></script>
|
||||
|
||||
<!-- Bootstrap Core JavaScript -->
|
||||
<script src="../static/js/bootstrap.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user