HTML로 개인 운영 체제 만들기
Wikiprompt, 무료 프롬프트 백과사전에서
HTML로 개인 운영 체제 만들기 개인용 OS를 단일 파일로 생성하기 위한 포괄적인 프롬프트로, 대시보드, 메모, 프로젝트, 작업, 회의, 데이터 영속성을 포함하며, 생산성 애호가에게 이상적입니다.
프롬프트 내용저장
🌐
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Personal OS • hub</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--bg: #f5f4f8; --surface: #ffffff; --text: #1e1e2a; --muted: #6b7280;
--primary: #4f46e5; --accent: #d946ef; --border: #e2e8f0;
--shadow: 0 4px 12px rgba(0,0,0,0.06); --radius: 16px;
--font: 'Inter', system-ui, sans-serif;
}
[data-theme="dark"] {
--bg: #0f1117; --surface: #1a1d27; --text: #e5e7eb; --muted: #9ca3af;
--primary: #818cf8; --accent: #e879f9; --border: #2d333d;
--shadow: 0 6px 16px rgba(0,0,0,0.4);
}
body {
font-family: var(--font); background: var(--bg); color: var(--text);
display: grid; grid-template-columns: 240px 1fr; min-height: 100vh;
transition: background 0.2s;
}
/* sidebar */
.sidebar {
background: var(--surface); border-right: 1px solid var(--border);
padding: 1.2rem 1rem; display: flex; flex-direction: column; gap: 0.5rem;
position: sticky; top: 0; height: 100vh; overflow-y: auto;
}
.logo { font-weight: 800; font-size: 1.3rem; letter-spacing: -0.02em; }
.logo span { color: var(--primary); }
.nav-item {
display: flex; align-items: center; gap: 0.6rem; padding: 0.6rem 0.8rem;
border-radius: 10px; color: var(--muted); cursor: pointer; font-size: 0.9rem;
transition: 0.1s; border: none; background: transparent;
}
.nav-item:hover { background: color-mix(in srgb, var(--primary) 12%, transparent); color: var(--text); }
.nav-item.active { background: color-mix(in srgb, var(--primary) 18%, transparent); color: var(--text); font-weight: 600; }
.nav-item .emoji { font-size: 1.1rem; width: 1.8rem; }
.sidebar .footer { margin-top: auto; font-size: 0.7rem; color: var(--muted); }
/* main */
.main {
padding: 2rem 2.5rem; max-width: 1200px; margin: 0 auto;
display: flex; flex-direction: column; gap: 1.8rem;
}
.topbar {
display: flex; align-items: center; gap: 1rem; flex-wrap: wrap;
}
.topbar h1 { font-size: 1.8rem; font-weight: 650; }
.btn {
background: var(--primary); color: white; border: none; padding: 0.5rem 1.2rem;
border-radius: 30px; font-weight: 600; cursor: pointer; font-size: 0.85rem;
box-shadow: var(--shadow);
}
.btn-outline {
background: transparent; border: 1px solid var(--border); color: var(--text);
}
.btn-sm { padding: 0.3rem 0.8rem; font-size: 0.75rem; }
.card {
background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
padding: 1.2rem 1.5rem; box-shadow: var(--shadow);
}
.grid-2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 1.2rem; }
.grid-3 { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 1.2rem; }
.section-title { font-size: 1.1rem; font-weight: 600; margin-bottom: 0.5rem; display: flex; align-items: center; gap: 0.5rem; }
.muted { color: var(--muted); font-size: 0.85rem; }
.tag { background: color-mix(in srgb, var(--primary) 15%, transparent); color: var(--text); padding: 0.2rem 0.6rem; border-radius: 20px; font-size: 0.7rem; }
.progress { height: 8px; background: var(--border); border-radius: 20px; overflow: hidden; }
.progress-bar { height: 100%; background: var(--primary); width: 40%; border-radius: 20px; }
input, textarea, select {
background: var(--surface); border: 1px solid var(--border); color: var(--text);
padding: 0.5rem 0.8rem; border-radius: 10px; font-size: 0.9rem; width: 100%;
}
textarea { min-height: 80px; resize: vertical; }
.modal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.4); z-index: 100; justify-content: center; align-items: center; }
.modal-content { background: var(--surface); padding: 2rem; border-radius: 20px; width: 90%; max-width: 500px; max-height: 80vh; overflow-y: auto; }
.modal.show { display: flex; }
.close { float: right; cursor: pointer; font-size: 1.5rem; }
.checkbox { width: 18px; height: 18px; border: 2px solid var(--primary); border-radius: 4px; display: inline-block; cursor: pointer; }
.checkbox.checked { background: var(--primary); }
.flex { display: flex; gap: 0.5rem; align-items: center; }
.hidden { display: none; }
.theme-toggle { background: none; border: none; font-size: 1.2rem; cursor: pointer; }
.accent-picker { display: flex; gap: 0.3rem; }
.color-dot { width: 20px; height: 20px; border-radius: 50%; cursor: pointer; border: 2px solid transparent; }
.color-dot.selected { border-color: var(--text); }
.data-actions { display: flex; gap: 0.5rem; }
.toast { position: fixed; bottom: 20px; right: 20px; background: var(--primary); color: white; padding: 0.8rem 1.2rem; border-radius: 30px; opacity: 0; transition: 0.3s; z-index: 200; }
.toast.show { opacity: 1; }
.link { color: var(--primary); cursor: pointer; text-decoration: underline; }
.calendar { display: grid; grid-template-columns: repeat(7, 1fr); gap: 0.2rem; font-size: 0.7rem; }
.cal-day { aspect-ratio: 1; display: flex; align-items: center; justify-content: center; border-radius: 50%; }
.cal-day.today { background: var(--primary); color: white; }
.connections { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.node { background: var(--surface); border: 1px solid var(--border); padding: 0.3rem 0.8rem; border-radius: 20px; font-size: 0.75rem; }
.edge { color: var(--muted); font-size: 1rem; }
@media (max-width: 800px) {
body { grid-template-columns: 1fr; }
.sidebar { display: none; }
.main { padding: 1rem; }
}
</style>
</head>
<body>
<aside class="sidebar" id="sidebar">
<div class="logo">⚡<span>personal</span>OS</div>
<button class="nav-item active" data-view="dashboard"><span class="emoji">🏠</span>Dashboard</button>
<button class="nav-item" data-view="notes"><span class="emoji">📝</span>Notes & Ideas</button>
<button class="nav-item" data-view="projects"><span class="emoji">📁</span>Projects</button>
<button class="nav-item" data-view="tasks"><span class="emoji">✅</span>Tasks</button>
<button class="nav-item" data-view="meetings"><span class="emoji">📅</span>Meetings</button>
<button class="nav-item" data-view="review"><span class="emoji">🧠</span>Daily Review</button>
<button class="nav-item" data-view="map"><span class="emoji">🕸️</span>Connections</button>
<div class="footer">v1.0 • local</div>
</aside>
<main class="main" id="main-content">
<div class="topbar">
<h1 id="view-title">Dashboard</h1>
<div class="flex" style="margin-left:auto">
<button class="btn-outline btn-sm" id="themeToggle">🌙</button>
<button class="btn-outline btn-sm" id="exportBtn">⇩ JSON</button>
<button class="btn-outline btn-sm" id="importBtn">⇪</button>
<input type="file" id="importFile" accept=".json" hidden>
<button class="btn" id="quickAddBtn">+ Quick add</button>
</div>
</div>
<!-- views -->
<div id="view-dashboard" class="view">
<div class="grid-2">
<div class="card">
<div class="section-title">📌 Today's focus</div>
<div id="focusList" class="muted">Set 1-3 priorities</div>
</div>
<div class="card">
<div class="section-title">💬 Daily prompt</div>
<p class="muted">"What is the one thing that would make today a success?"</p>
</div>
</div>
<div class="card">
<div class="section-title">⚡ Quick capture</div>
<textarea id="quickCapture" placeholder="Capture a thought..."></textarea>
<button class="btn btn-sm" id="captureBtn">Capture</button>
</div>
<div class="grid-2">
<div class="card"><div class="section-title">📅 Today's agenda</div><div id="agendaList" class="muted">No meetings</div></div>
<div class="card"><div class="section-title">🕘 Recent activity</div><div id="recentList" class="muted">Nothing yet</div></div>
</div>
<div class="card"><div class="section-title">📁 Key projects</div><div id="projectPreview" class="muted">No projects</div></div>
</div>
<div id="view-notes" class="view hidden">
<div class="flex" style="margin-bottom:1rem">
<input id="noteSearch" placeholder="Search notes...">
<button class="btn btn-sm" id="newNoteBtn">+ Note</button>
</div>
<div id="notesList" class="grid-3"></div>
</div>
<div id="view-projects" class="view hidden">
<button class="btn" id="newProjectBtn">+ New Project</button>
<div id="projectsGrid" class="grid-2" style="margin-top:1rem"></div>
</div>
<div id="view-tasks" class="view hidden">
<button class="btn" id="newTaskBtn">+ New Task</button>
<div id="tasksList" style="margin-top:1rem"></div>
</div>
<div id="view-meetings" class="view hidden">
<button class="btn" id="newMeetingBtn">+ Log Meeting</button>
<div id="meetingsList" style="margin-top:1rem"></div>
</div>
<div id="view-review" class="view hidden">
<div class="card"><div class="section-title">🌅 Morning intention</div><textarea id="morningIntention" placeholder="What matters most today?"></textarea></div>
<div class="card"><div class="section-title">🌙 Evening reflection</div><textarea id="eveningReflection" placeholder="What got done?"></textarea></div>
<div class="card"><div class="section-title">📊 Weekly review</div><textarea id="weeklyReview" placeholder="What worked? what didn't?"></textarea></div>
<button class="btn" id="saveReviewBtn">Save review</button>
</div>
<div id="view-map" class="view hidden">
<div class="card">
<div class="section-title">🕸️ Connections map</div>
<div id="connectionMap" class="connections"></div>
</div>
</div>
<!-- modal for quick add -->
<div class="modal" id="quickModal">
<div class="modal-content">
<span class="close" id="closeModal">×</span>
<h3>Quick add</h3>
<select id="quickType">
<option value="note">Note</option>
<option value="task">Task</option>
<option value="meeting">Meeting</option>
</select>
<input id="quickTitle" placeholder="Title">
<textarea id="quickDesc" placeholder="Description / content"></textarea>
<button class="btn" id="saveQuick">Save</button>
</div>
</div>
</main>
<div class="toast" id="toast">Saved</div>
<script>
(function(){
// ---------- state ----------
const defaultData = {
notes: [
{ id: 'n1', title: 'Welcome note', content: 'This is your **wiki** note. Double-click to edit.', tags: ['intro'], project: 'p1', createdAt: new Date().toISOString() },
{ id: 'n2', title: 'Idea: voice UI', content: 'Explore voice commands for OS.', tags: ['idea'], project: 'p2', createdAt: new Date().toISOString() }
],
projects: [
{ id: 'p1', name: 'Personal OS', description: 'Build the hub', status: 'active', deadline: '2025-12-31', progress: 40 },
{ id: 'p2', name: 'Research', description: 'Explore AI', status: 'active', deadline: '2025-10-01', progress: 70 }
],
tasks: [
{ id: 't1', title: 'Design dashboard', desc: 'Wireframe', due: '2025-04-10', priority: 'high', project: 'p1', done: false, subtasks: [] },
{ id: 't2', title: 'Write spec', desc: 'For OS', due: '2025-04-12', priority: 'medium', project: 'p1', done: false, subtasks: [] }
],
meetings: [
{ id: 'm1', title: 'Kickoff', date: '2025-04-08', attendees: ['you'], notes: 'Intro', actionItems: ['create repo'], project: 'p1' }
],
review: { morning: '', evening: '', weekly: '' },
settings: { theme: 'light', accent: '#4f46e5' }
};
let state = load();
function load() {
try {
const raw = localStorage.getItem('pos_data');
if (raw) return JSON.parse(raw);
} catch(e) {}
return JSON.parse(JSON.stringify(defaultData));
}
function save() {
localStorage.setItem('pos_data', JSON.stringify(state));
showToast('Saved');
}
function showToast(msg) {
const t = document.getElementById('toast');
t.textContent = msg; t.classList.add('show');
setTimeout(()=>t.classList.remove('show'), 1500);
}
// ---------- helpers ----------
const $ = (s) => document.querySelector(s);
const $$ = (s) => [...document.querySelectorAll(s)];
const uid = () => 'id_' + Math.random().toString(36).slice(2,9);
const fmtDate = (d) => d ? new Date(d).toLocaleDateString('en-CA') : '';
// ---------- navigation ----------
const views = ['dashboard','notes','projects','tasks','meetings','review','map'];
function switchView(v) {
views.forEach(vw => {
const el = document.getElementById('view-'+vw);
if (el) el.classList.toggle('hidden', vw !== v);
});
document.querySelectorAll('.nav-item').forEach(b => b.classList.toggle('active', b.dataset.view === v));
const titles = { dashboard:'Dashboard', notes:'Notes & Ideas', projects:'Projects & Goals', tasks:'Tasks', meetings:'Meetings', review:'Daily Review', map:'Connections' };
$('#view-title').textContent = titles[v] || 'Dashboard';
}
// ---------- render ----------
function renderAll() {
renderDashboard();
renderNotes();
renderProjects();
renderTasks();
renderMeetings();
renderReview();
renderMap();
}
function renderDashboard() {
// focus
const focus = state.tasks.filter(t=>!t.done && t.priority==='high').slice(0,3);
$('#focusList').innerHTML = focus.length ? focus.map(t=>`<div>• ${t.title}</div>`).join('') : '<span class="muted">No high priority tasks</span>';
// agenda
const today = new Date().toISOString().slice(0,10);
const meetingsToday = state.meetings.filter(m=>m.date===today);
$('#agendaList').innerHTML = meetingsToday.length ? meetingsToday.map(m=>`<div>${m.title} @ ${m.date}</div>`).join('') : '<span class="muted">No meetings today</span>';
// recent
const recent = [...state.notes].sort((a,b)=>b.createdAt.localeCompare(a.createdAt)).slice(0,3);
$('#recentList').innerHTML = recent.length ? recent.map(n=>`<div>📝 ${n.title}</div>`).join('') : '<span class="muted">No notes yet</span>';
// projects preview
$('#projectPreview').innerHTML = state.projects.slice(0,3).map(p=>`<div>📁 ${p.name} <span class="muted">${p.progress}%</span></div>`).join('') || '<span class="muted">No projects</span>';
}
function renderNotes() {
const q = ($('#noteSearch')?.value || '').toLowerCase();
const notes = state.notes.filter(n => n.title.toLowerCase().includes(q) || n.content.toLowerCase().includes(q) || n.tags.some(t=>t.toLowerCase().includes(q)));
$('#notesList').innerHTML = notes.map(n => `
<div class="card" style="padding:1rem">
<div class="flex"><b>${n.title}</b> ${n.tags.map(t=>`<span class="tag">${t}</span>`).join('')}</div>
<div class="muted" style="white-space:pre-wrap">${n.content.slice(0,80)}</div>
<div class="flex"><span class="link" data-id="${n.id}" data-action="edit-note">✎ edit</span> <span class="link" data-id="${n.id}" data-action="delete-note">🗑</span></div>
</div>`).join('') || '<div class="muted">No notes found</div>';
}
function renderProjects() {
$('#projectsGrid').innerHTML = state.projects.map(p => `
<div class="card">
<div class="flex"><b>${p.name}</b> <span class="tag">${p.status}</span></div>
<div class="muted">${p.description}</div>
<div class="progress"><div class="progress-bar" style="width:${p.progress}%"></div></div>
<div class="muted">Deadline: ${p.deadline}</div>
<div class="flex"><span class="link" data-id="${p.id}" data-action="edit-project">✎</span> <span class="link" data-id="${p.id}" data-action="delete-project">🗑</span></div>
</div>`).join('') || '<div class="muted">No projects</div>';
}
function renderTasks() {
const groups = { 'Today': [], 'This Week': [], 'Later': [] };
const today = new Date().toISOString().slice(0,10);
state.tasks.forEach(t => {
if (t.due === today) groups['Today'].push(t);
else if (t.due && t.due > today) groups['This Week'].push(t);
else groups['Later'].push(t);
});
let html = '';
Object.keys(groups).forEach(g => {
if (groups[g].length) {
html += `<div class="card"><div class="section-title">${g}</div>`;
groups[g].forEach(t => {
html += `<div class="flex"><span class="checkbox ${t.done?'checked':''}" data-id="${t.id}" data-action="toggle-task"></span> <span class="${t.done?'muted':''}">${t.title}</span> <span class="tag">${t.priority}</span> <span class="link" data-id="${t.id}" data-action="delete-task">🗑</span></div>`;
});
html += `</div>`;
}
});
$('#tasksList').innerHTML = html || '<div class="muted">No tasks</div>';
}
function renderMeetings() {
$('#meetingsList').innerHTML = state.meetings.map(m => `
<div class="card">
<div class="flex"><b>${m.title}</b> <span class="muted">${m.date}</span></div>
<div class="muted">👥 ${m.attendees.join(', ')}</div>
<div class="muted">${m.notes}</div>
<div class="flex"><span class="link" data-id="${m.id}" data-action="delete-meeting">🗑</span></div>
</div>`).join('') || '<div class="muted">No meetings</div>';
}
function renderReview() {
$('#morningIntention').value = state.review.morning;
$('#eveningReflection').value = state.review.evening;
$('#weeklyReview').value = state.review.weekly;
}
function renderMap() {
const nodes = [];
state.projects.forEach(p=>nodes.push(`<span class="node">📁 ${p.name}</span>`));
state.notes.forEach(n=>nodes.push(`<span class="node">📝 ${n.title}</span>`));
state.tasks.forEach(t=>nodes.push(`<span class="node">✅ ${t.title}</span>`));
state.meetings.forEach(m=>nodes.push(`<span class="node">📅 ${m.title}</span>`));
$('#connectionMap').innerHTML = nodes.join(' <span class="edge">→</span> ');
}
// ---------- actions ----------
function addNote(title, content, tags, project) {
state.notes.push({ id: uid(), title, content, tags: tags||[], project: project||'', createdAt: new Date().toISOString() });
save(); renderAll();
}
function addTask(title, desc, due, priority, project) {
state.tasks.push({ id: uid(), title, desc, due, priority, project, done:false, subtasks:[] });
save(); renderAll();
}
function addMeeting(title, date, attendees, notes, project) {
state.meetings.push({ id: uid(), title, date, attendees: attendees.split(',').map(s=>s.trim()), notes, project });
save(); renderAll();
}
function addProject(name, desc, deadline) {
state.projects.push({ id: uid(), name, description: desc, status:'active', deadline, progress: 0 });
save(); renderAll();
}
// ---------- event handlers ----------
function setup() {
// nav
document.querySelectorAll('.nav-item').forEach(b => b.addEventListener('click', () => switchView(b.dataset.view)));
// theme
$('#themeToggle').addEventListener('click', () => {
const cur = document.documentElement.dataset.theme === 'dark' ? 'light' : 'dark';
document.documentElement.dataset.theme = cur;
state.settings.theme = cur;
save();
});
// apply theme
if (state.settings.theme === 'dark') document.documentElement.dataset.theme = 'dark';
// quick add modal
$('#quickAddBtn').addEventListener('click', ()=>$('#quickModal').classList.add('show'));
$('#closeModal').addEventListener('click', ()=>$('#quickModal').classList.remove('show'));
$('#saveQuick').addEventListener('click', () => {
const type = $('#quickType').value;
const title = $('#quickTitle').value.trim();
const desc = $('#quickDesc').value.trim();
if (!title) return;
if (type === 'note') addNote(title, desc, ['quick'], '');
else if (type === 'task') addTask(title, desc, new Date().toISOString().slice(0,10), 'medium', '');
else if (type === 'meeting') addMeeting(title, new Date().toISOString().slice(0,10), 'you', desc, '');
$('#quickTitle').value=''; $('#quickDesc').value='';
$('#quickModal').classList.remove('show');
});
// capture
$('#captureBtn').addEventListener('click', () => {
const content = $('#quickCapture').value.trim();
if (content) { addNote('Captured '+new Date().toLocaleDateString(), content, ['capture'], ''); $('#quickCapture').value=''; }
});
// new note
$('#newNoteBtn').addEventListener('click', () => {
const title = prompt('Note title') || 'Untitled';
addNote(title, '', ['note'], '');
});
// new project
$('#newProjectBtn').addEventListener('click', () => {
const name = prompt('Project name');
if (name) addProject(name, '', '');
});
// new task
$('#newTaskBtn').addEventListener('click', () => {
const title = prompt('Task title');
if (title) addTask(title, '', new Date().toISOString().slice(0,10), 'medium', '');
});
// new meeting
$('#newMeetingBtn').addEventListener('click', () => {
const title = prompt('Meeting title');
if (title) addMeeting(title, new Date().toISOString().slice(0,10), 'you', '', '');
});
// save review
$('#saveReviewBtn').addEventListener('click', () => {
state.review.morning = $('#morningIntention').value;
state.review.evening = $('#eveningReflection').value;
state.review.weekly = $('#weeklyReview').value;
save(); showToast('Review saved');
});
// export
$('#exportBtn').addEventListener('click', () => {
const blob = new Blob([JSON.stringify(state, null, 2)], {type:'application/json'});
const url = URL.createObjectURL(blob);
const a = document.createElement('a'); a.href=url; a.download='personal_os_backup.json'; a.click();
URL.revokeObjectURL(url);
});
// import
$('#importBtn').addEventListener('click', ()=>$('#importFile').click());
$('#importFile').addEventListener('change', (e) => {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.readAsText(file).then(text => {
try { state = JSON.parse(text); save(); renderAll(); showToast('Imported'); }
catch { alert('Invalid JSON'); }
});
});
// global click for edit/delete/toggle
document.addEventListener('click', (e) => {
const target = e.target;
if (target.dataset.action === 'toggle-task') {
const id = target.dataset.id;
const task = state.tasks.find(t=>t.id===id);
if (task) { task.done = !task.done; save(); renderAll(); }
} else if (target.dataset.action === 'delete-note') {
state.notes = state.notes.filter(n=>n.id!==target.dataset.id); save(); renderAll();
} else if (target.dataset.action === 'delete-project') {
state.projects = state.projects.filter(p=>p.id!==target.dataset.id); save(); renderAll();
} else if (target.dataset.action === 'delete-task') {
state.tasks = state.tasks.filter(t=>t.id!==target.dataset.id); save(); renderAll();
} else if (target.dataset.action === 'delete-meeting') {
state.meetings = state.meetings.filter(m=>m.id!==target.dataset.id); save(); renderAll();
} else if (target.dataset.action === 'edit-note') {
const note = state.notes.find(n=>n.id===target.dataset.id);
if (note) {
const newTitle = prompt('Edit title', note.title);
if (newTitle) { note.title = newTitle; save(); renderAll(); }
}
} else if (target.dataset.action === 'edit-project') {
const proj = state.projects.find(p=>p.id===target.dataset.id);
if (proj) {
const np = prompt('Edit name', proj.name);
if (np) { proj.name = np; save(); renderAll(); }
}
}
});
// search
$('#noteSearch').addEventListener('input', renderNotes);
}
// init
document.documentElement.dataset.theme = state.settings.theme || 'light';
setup();
renderAll();
switchView('dashboard');
})();
</script>
</body>
</html>
전체 프롬프트를 보려면 로그인하세요
Continue with:
By logging in, you agree to our Terms of Use and Privacy Policy
사용법
이 프롬프트는 productivity와 함께 사용하도록 설계되었습니다. 위의 프롬프트 내용을 복사하여 원하는 AI 도구에 붙여넣으세요.
최상의 결과를 얻으려면 자리 표시자(대괄호 또는 대문자로 표시)를 특정 요구 사항으로 사용자 지정할 수 있습니다.
토론
댓글 0개