word generation
This commit is contained in:
parent
c91e4de4a8
commit
5b8a8b7572
6 changed files with 428 additions and 235 deletions
BIN
assets/antrag_vorlage.docx
Normal file
BIN
assets/antrag_vorlage.docx
Normal file
Binary file not shown.
|
|
@ -31,7 +31,6 @@
|
|||
jinja2
|
||||
google-generativeai # Dependency for Gemini API
|
||||
grpcio # Required by google-generativeai
|
||||
reportlab # Dependency for PDF generation
|
||||
python-docx # Dependency for Word document generation
|
||||
];
|
||||
|
||||
|
|
|
|||
290
meinantrag.py
290
meinantrag.py
|
|
@ -13,11 +13,7 @@ from jinja2 import Environment, FileSystemLoader
|
|||
import google.generativeai as genai
|
||||
import re
|
||||
from io import BytesIO
|
||||
from reportlab.lib.pagesizes import A4
|
||||
from reportlab.lib.units import cm
|
||||
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
|
||||
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
|
||||
from reportlab.lib.enums import TA_LEFT, TA_JUSTIFY
|
||||
from datetime import datetime
|
||||
try:
|
||||
from docx import Document
|
||||
from docx.shared import Pt, Inches
|
||||
|
|
@ -84,8 +80,8 @@ class MeinAntragApp(BaseTemplateResource):
|
|||
template = self.jinja_env.get_template('index.html')
|
||||
resp.content_type = 'text/html; charset=utf-8'
|
||||
resp.text = template.render(
|
||||
meta_title='MeinAntrag – Anfragelinks für FragDenStaat',
|
||||
meta_description='Erstelle vorausgefüllte Anfragelinks für FragDenStaat.de, suche Behörden, füge Betreff und Text hinzu und teile den Link.',
|
||||
meta_title='MeinAntrag – Anträge an die Karlsruher Stadtverwaltung',
|
||||
meta_description='Erstelle einfach Vorlagen für Anfragen oder Anträge an die Karlsruher Stadtverwaltung zu deinem persönlichen Thema und schicke diese direkt an eine Stadtratsfraktion!',
|
||||
canonical_url=f"{SITE_BASE_URL}/"
|
||||
)
|
||||
|
||||
|
|
@ -301,188 +297,120 @@ WICHTIG:
|
|||
'error': str(e)
|
||||
})
|
||||
|
||||
class GeneratePDFResource:
|
||||
def _generate_pdf(self, title, demand, justification, party_name=""):
|
||||
"""Generate a PDF that looks like a city council proposal"""
|
||||
buffer = BytesIO()
|
||||
doc = SimpleDocTemplate(buffer, pagesize=A4,
|
||||
rightMargin=2.5*cm, leftMargin=2.5*cm,
|
||||
topMargin=2.5*cm, bottomMargin=2.5*cm)
|
||||
|
||||
# Container for the 'Flowable' objects
|
||||
story = []
|
||||
|
||||
# Define styles
|
||||
styles = getSampleStyleSheet()
|
||||
|
||||
# Custom styles for the document
|
||||
title_style = ParagraphStyle(
|
||||
'CustomTitle',
|
||||
parent=styles['Heading1'],
|
||||
fontSize=16,
|
||||
textColor='black',
|
||||
spaceAfter=30,
|
||||
alignment=TA_LEFT,
|
||||
fontName='Helvetica-Bold'
|
||||
)
|
||||
|
||||
heading_style = ParagraphStyle(
|
||||
'CustomHeading',
|
||||
parent=styles['Heading2'],
|
||||
fontSize=12,
|
||||
textColor='black',
|
||||
spaceAfter=12,
|
||||
spaceBefore=20,
|
||||
alignment=TA_LEFT,
|
||||
fontName='Helvetica-Bold'
|
||||
)
|
||||
|
||||
body_style = ParagraphStyle(
|
||||
'CustomBody',
|
||||
parent=styles['Normal'],
|
||||
fontSize=11,
|
||||
textColor='black',
|
||||
spaceAfter=12,
|
||||
alignment=TA_JUSTIFY,
|
||||
fontName='Helvetica'
|
||||
)
|
||||
|
||||
# Header with party name if provided
|
||||
if party_name:
|
||||
party_para = Paragraph(f"<b>Antrag der {party_name}</b>", body_style)
|
||||
story.append(party_para)
|
||||
story.append(Spacer(1, 0.5*cm))
|
||||
|
||||
# Title
|
||||
if title:
|
||||
title_para = Paragraph(f"<b>{title}</b>", title_style)
|
||||
story.append(title_para)
|
||||
|
||||
# Demand section
|
||||
if demand:
|
||||
story.append(Spacer(1, 0.3*cm))
|
||||
demand_heading = Paragraph("<b>Der Gemeinderat möge beschließen:</b>", heading_style)
|
||||
story.append(demand_heading)
|
||||
|
||||
# Process demand text - replace newlines with proper breaks
|
||||
demand_lines = demand.split('\n')
|
||||
for line in demand_lines:
|
||||
if line.strip():
|
||||
demand_para = Paragraph(line.strip(), body_style)
|
||||
story.append(demand_para)
|
||||
|
||||
# Justification section
|
||||
if justification:
|
||||
story.append(Spacer(1, 0.5*cm))
|
||||
justification_heading = Paragraph("<b>Begründung/Sachverhalt</b>", heading_style)
|
||||
story.append(justification_heading)
|
||||
|
||||
# Process justification text
|
||||
justification_lines = justification.split('\n')
|
||||
for line in justification_lines:
|
||||
if line.strip():
|
||||
justification_para = Paragraph(line.strip(), body_style)
|
||||
story.append(justification_para)
|
||||
|
||||
# Build PDF
|
||||
doc.build(story)
|
||||
buffer.seek(0)
|
||||
return buffer
|
||||
|
||||
def on_post(self, req, resp):
|
||||
"""Generate PDF from form data"""
|
||||
try:
|
||||
# Get form data
|
||||
title = req.get_param('title', default='') or ''
|
||||
demand = req.get_param('demand', default='') or ''
|
||||
justification = req.get_param('justification', default='') or ''
|
||||
party_name = req.get_param('party_name', default='') or ''
|
||||
|
||||
# If empty, try to read from stream
|
||||
if not title:
|
||||
try:
|
||||
stream = getattr(req, 'bounded_stream', req.stream)
|
||||
raw_body = stream.read().decode('utf-8')
|
||||
parsed = parse_qs(raw_body)
|
||||
title = parsed.get('title', [''])[0]
|
||||
demand = parsed.get('demand', [''])[0]
|
||||
justification = parsed.get('justification', [''])[0]
|
||||
party_name = parsed.get('party_name', [''])[0]
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Generate PDF
|
||||
pdf_buffer = self._generate_pdf(title, demand, justification, party_name)
|
||||
|
||||
# Return PDF
|
||||
resp.content_type = 'application/pdf'
|
||||
resp.set_header('Content-Disposition', 'inline; filename="antrag.pdf"')
|
||||
resp.data = pdf_buffer.read()
|
||||
|
||||
except Exception as e:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
resp.status = falcon.HTTP_500
|
||||
resp.content_type = 'application/json'
|
||||
resp.text = json.dumps({
|
||||
'success': False,
|
||||
'error': str(e)
|
||||
})
|
||||
|
||||
class GenerateWordResource:
|
||||
def __init__(self):
|
||||
# Get template path
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
self.template_path = os.path.join(script_dir, 'assets', 'antrag_vorlage.docx')
|
||||
# Fallback if not in assets
|
||||
if not os.path.exists(self.template_path):
|
||||
assets_dir = os.path.join(script_dir, '..', 'assets')
|
||||
self.template_path = os.path.join(assets_dir, 'antrag_vorlage.docx')
|
||||
|
||||
def _generate_word(self, title, demand, justification, party_name=""):
|
||||
"""Generate a Word document that looks like a city council proposal"""
|
||||
doc = Document()
|
||||
"""Generate a Word document using the template"""
|
||||
# Load template
|
||||
if os.path.exists(self.template_path):
|
||||
doc = Document(self.template_path)
|
||||
else:
|
||||
# Fallback: create new document if template not found
|
||||
doc = Document()
|
||||
|
||||
# Set default font
|
||||
style = doc.styles['Normal']
|
||||
font = style.font
|
||||
font.name = 'Arial'
|
||||
font.size = Pt(11)
|
||||
# Get current date in DD.MM.YYYY format
|
||||
current_date = datetime.now().strftime("%d.%m.%Y")
|
||||
|
||||
# Header with party name if provided
|
||||
if party_name:
|
||||
party_para = doc.add_paragraph(f"Antrag der {party_name}")
|
||||
party_para.runs[0].bold = True
|
||||
party_para.runs[0].font.size = Pt(11)
|
||||
doc.add_paragraph()
|
||||
# Combine demand for ANTRAGSTEXT (with heading)
|
||||
antragtext = "Der Gemeinderat möge beschließen:\n" + demand
|
||||
|
||||
# Title
|
||||
if title:
|
||||
title_para = doc.add_paragraph(title)
|
||||
title_para.runs[0].bold = True
|
||||
title_para.runs[0].font.size = Pt(16)
|
||||
title_para.paragraph_format.space_after = Pt(30)
|
||||
# Replace placeholders in all paragraphs
|
||||
for paragraph in doc.paragraphs:
|
||||
full_text = paragraph.text
|
||||
if not full_text:
|
||||
continue
|
||||
|
||||
# Demand section
|
||||
if demand:
|
||||
doc.add_paragraph()
|
||||
demand_heading = doc.add_paragraph("Der Gemeinderat möge beschließen:")
|
||||
demand_heading.runs[0].bold = True
|
||||
demand_heading.runs[0].font.size = Pt(12)
|
||||
demand_heading.paragraph_format.space_before = Pt(20)
|
||||
demand_heading.paragraph_format.space_after = Pt(12)
|
||||
# Replace FRAKTION
|
||||
if party_name and 'FRAKTION' in full_text:
|
||||
for run in paragraph.runs:
|
||||
if 'FRAKTION' in run.text:
|
||||
run.text = run.text.replace('FRAKTION', party_name)
|
||||
|
||||
# Process demand text
|
||||
demand_lines = demand.split('\n')
|
||||
for line in demand_lines:
|
||||
if line.strip():
|
||||
doc.add_paragraph(line.strip())
|
||||
# Replace XX.XX.XXXX with current date
|
||||
if 'XX.XX.XXXX' in full_text:
|
||||
for run in paragraph.runs:
|
||||
if 'XX.XX.XXXX' in run.text:
|
||||
run.text = run.text.replace('XX.XX.XXXX', current_date)
|
||||
|
||||
# Justification section
|
||||
if justification:
|
||||
doc.add_paragraph()
|
||||
justification_heading = doc.add_paragraph("Begründung/Sachverhalt")
|
||||
justification_heading.runs[0].bold = True
|
||||
justification_heading.runs[0].font.size = Pt(12)
|
||||
justification_heading.paragraph_format.space_before = Pt(20)
|
||||
justification_heading.paragraph_format.space_after = Pt(12)
|
||||
# Replace ANTRAGSTITEL (bold)
|
||||
if 'ANTRAGSTITEL' in full_text:
|
||||
paragraph.clear()
|
||||
run = paragraph.add_run(title)
|
||||
run.bold = True
|
||||
|
||||
# Process justification text
|
||||
justification_lines = justification.split('\n')
|
||||
for line in justification_lines:
|
||||
if line.strip():
|
||||
doc.add_paragraph(line.strip())
|
||||
# Replace ANTRAGSTEXT
|
||||
if 'ANTRAGSTEXT' in full_text:
|
||||
paragraph.clear()
|
||||
lines = antragtext.split('\n')
|
||||
for i, line in enumerate(lines):
|
||||
if line.strip():
|
||||
run = paragraph.add_run(line.strip())
|
||||
if i == 0: # First line (heading) should be bold
|
||||
run.bold = True
|
||||
if i < len(lines) - 1:
|
||||
paragraph.add_run('\n')
|
||||
|
||||
# Replace BEGRÜNDUNGSTEXT
|
||||
if 'BEGRÜNDUNGSTEXT' in full_text:
|
||||
paragraph.clear()
|
||||
lines = justification.split('\n')
|
||||
for i, line in enumerate(lines):
|
||||
if line.strip():
|
||||
paragraph.add_run(line.strip())
|
||||
if i < len(lines) - 1:
|
||||
paragraph.add_run('\n')
|
||||
|
||||
# Also check tables for placeholders
|
||||
for table in doc.tables:
|
||||
for row in table.rows:
|
||||
for cell in row.cells:
|
||||
for paragraph in cell.paragraphs:
|
||||
full_text = paragraph.text
|
||||
if not full_text:
|
||||
continue
|
||||
|
||||
if party_name and 'FRAKTION' in full_text:
|
||||
for run in paragraph.runs:
|
||||
if 'FRAKTION' in run.text:
|
||||
run.text = run.text.replace('FRAKTION', party_name)
|
||||
|
||||
if 'XX.XX.XXXX' in full_text:
|
||||
for run in paragraph.runs:
|
||||
if 'XX.XX.XXXX' in run.text:
|
||||
run.text = run.text.replace('XX.XX.XXXX', current_date)
|
||||
|
||||
if 'ANTRAGSTITEL' in full_text:
|
||||
paragraph.clear()
|
||||
run = paragraph.add_run(title)
|
||||
run.bold = True
|
||||
|
||||
if 'ANTRAGSTEXT' in full_text:
|
||||
paragraph.clear()
|
||||
lines = antragtext.split('\n')
|
||||
for i, line in enumerate(lines):
|
||||
if line.strip():
|
||||
run = paragraph.add_run(line.strip())
|
||||
if i == 0:
|
||||
run.bold = True
|
||||
if i < len(lines) - 1:
|
||||
paragraph.add_run('\n')
|
||||
|
||||
if 'BEGRÜNDUNGSTEXT' in full_text:
|
||||
paragraph.clear()
|
||||
lines = justification.split('\n')
|
||||
for i, line in enumerate(lines):
|
||||
if line.strip():
|
||||
paragraph.add_run(line.strip())
|
||||
if i < len(lines) - 1:
|
||||
paragraph.add_run('\n')
|
||||
|
||||
# Save to buffer
|
||||
buffer = BytesIO()
|
||||
|
|
@ -583,7 +511,6 @@ meinantrag = MeinAntragApp()
|
|||
impressum = ImpressumResource()
|
||||
datenschutz = DatenschutzResource()
|
||||
generate_antrag = GenerateAntragResource()
|
||||
generate_pdf = GeneratePDFResource()
|
||||
generate_word = GenerateWordResource()
|
||||
robots = RobotsResource()
|
||||
sitemap = SitemapResource()
|
||||
|
|
@ -592,7 +519,6 @@ app.add_route('/', meinantrag)
|
|||
app.add_route('/impressum', impressum)
|
||||
app.add_route('/datenschutz', datenschutz)
|
||||
app.add_route('/api/generate-antrag', generate_antrag)
|
||||
app.add_route('/api/generate-pdf', generate_pdf)
|
||||
app.add_route('/api/generate-word', generate_word)
|
||||
app.add_route('/robots.txt', robots)
|
||||
app.add_route('/sitemap.xml', sitemap)
|
||||
|
|
|
|||
|
|
@ -8,20 +8,20 @@
|
|||
<link href="/static/css/select2.min.css" rel="stylesheet">
|
||||
<link href="/static/css/select2-bootstrap-5-theme.min.css" rel="stylesheet">
|
||||
|
||||
<meta name="description" content="{{ meta_description | default('Erstelle vorausgefüllte FragDenStaat.de-Anfragelinks und teile sie mit Freund:innen. Suche Behörden, füge Betreff und Text hinzu und generiere einen teilbaren Link.') }}">
|
||||
<meta name="description" content="{{ meta_description | default('Erstelle einfach Vorlagen für Anfragen oder Anträge an die Karlsruher Stadtverwaltung zu deinem persönlichen Thema und schicke diese direkt an eine Stadtratsfraktion!') }}">
|
||||
<link rel="canonical" href="{{ canonical_url | default('/') }}">
|
||||
<link rel="alternate" hreflang="de" href="{{ canonical_url | default('/') }}">
|
||||
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="MeinAntrag">
|
||||
<meta property="og:title" content="{{ meta_title | default('MeinAntrag') }}">
|
||||
<meta property="og:description" content="{{ meta_description | default('Erstelle vorausgefüllte FragDenStaat.de-Anfragelinks und teile sie mit Freund:innen.') }}">
|
||||
<meta property="og:description" content="{{ meta_description | default('Erstelle einfach Vorlagen für Anfragen oder Anträge an die Karlsruher Stadtverwaltung zu deinem persönlichen Thema und schicke diese direkt an eine Stadtratsfraktion!') }}">
|
||||
<meta property="og:locale" content="de_DE">
|
||||
<meta property="og:url" content="{{ canonical_url | default('/') }}">
|
||||
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="{{ meta_title | default('MeinAntrag') }}">
|
||||
<meta name="twitter:description" content="{{ meta_description | default('Erstelle vorausgefüllte FragDenStaat.de-Anfragelinks und teile sie mit Freund:innen.') }}">
|
||||
<meta name="twitter:description" content="{{ meta_description | default('Erstelle einfach Vorlagen für Anfragen oder Anträge an die Karlsruher Stadtverwaltung zu deinem persönlichen Thema und schicke diese direkt an eine Stadtratsfraktion!') }}">
|
||||
|
||||
{% if noindex %}<meta name="robots" content="noindex,follow">{% endif %}
|
||||
<meta name="theme-color" content="#667eea">
|
||||
|
|
|
|||
|
|
@ -69,13 +69,6 @@
|
|||
</svg>
|
||||
<span id="mailBtnText">Mail an Fraktion senden</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary" id="pdfBtn">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-file-pdf me-2" viewBox="0 0 16 16">
|
||||
<path d="M8.5 6a.5.5 0 0 0-1 0v1.5H6a.5.5 0 0 0 0 1h1.5V10a.5.5 0 0 0 1 0V8.5H10a.5.5 0 0 0 0-1H8.5z"/>
|
||||
<path d="M14 14V4.5L9.5 0H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2M9.5 3A1.5 1.5 0 0 0 11 4.5h2V14a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1h5.5z"/>
|
||||
</svg>
|
||||
PDF anzeigen
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary" id="wordBtn">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-file-earmark-word me-2" viewBox="0 0 16 16">
|
||||
<path d="M5.485 6.879a.5.5 0 1 0-.97.242l1.5 6a.5.5 0 0 0 .539.314l1.5-.5a.5.5 0 0 0 .186-.596l-.737-2.945 2.679-3.42a.5.5 0 1 0-.758-.652L6.978 8.616l-1.493-.5z"/>
|
||||
|
|
@ -217,46 +210,6 @@
|
|||
}
|
||||
});
|
||||
|
||||
// Handle PDF button click
|
||||
$('#pdfBtn').on('click', function() {
|
||||
const title = $('#antragstitel').val() || '';
|
||||
const demand = $('#forderung').val() || '';
|
||||
const justification = $('#begruendung').val() || '';
|
||||
const partyName = $('#resultFields').data('party-name') || '';
|
||||
|
||||
// Prepare form data
|
||||
const formData = new URLSearchParams();
|
||||
formData.append('title', title);
|
||||
formData.append('demand', demand);
|
||||
formData.append('justification', justification);
|
||||
if (partyName) {
|
||||
formData.append('party_name', partyName);
|
||||
}
|
||||
|
||||
// Open PDF in new window
|
||||
fetch('/api/generate-pdf', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
body: formData.toString()
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error('Fehler beim Generieren des PDFs');
|
||||
}
|
||||
return response.blob();
|
||||
})
|
||||
.then(blob => {
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
window.open(url, '_blank');
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('Fehler beim Generieren des PDFs: ' + error.message);
|
||||
});
|
||||
});
|
||||
|
||||
// Handle Word button click
|
||||
$('#wordBtn').on('click', function() {
|
||||
const title = $('#antragstitel').val() || '';
|
||||
|
|
|
|||
315
vorlage.html
Normal file
315
vorlage.html
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||
<link type="text/css" href="https://pages.github.com/css/pages.css" media="all" rel="stylesheet">
|
||||
|
||||
<!-- Begin Jekyll SEO tag v2.8.0 -->
|
||||
<title>GitHub Pages | Websites for you and your projects, hosted directly from your GitHub repository. Just edit, push, and your changes are live.</title>
|
||||
<meta name="generator" content="Jekyll v3.10.0" />
|
||||
<meta property="og:title" content="GitHub Pages" />
|
||||
<meta property="og:locale" content="en_US" />
|
||||
<meta name="description" content="Websites for you and your projects, hosted directly from your GitHub repository. Just edit, push, and your changes are live." />
|
||||
<meta property="og:description" content="Websites for you and your projects, hosted directly from your GitHub repository. Just edit, push, and your changes are live." />
|
||||
<link rel="canonical" href="https://pages.github.com/" />
|
||||
<meta property="og:url" content="https://pages.github.com/" />
|
||||
<meta property="og:site_name" content="GitHub Pages" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<meta property="twitter:title" content="GitHub Pages" />
|
||||
<meta name="twitter:site" content="@github" />
|
||||
<script type="application/ld+json">
|
||||
{"@context":"https://schema.org","@type":"WebSite","description":"Websites for you and your projects, hosted directly from your GitHub repository. Just edit, push, and your changes are live.","headline":"GitHub Pages","name":"GitHub Pages","url":"https://pages.github.com/"}</script>
|
||||
<!-- End Jekyll SEO tag -->
|
||||
|
||||
</head>
|
||||
|
||||
<body class="home ">
|
||||
|
||||
|
||||
<section id="hero-spot" class="hero-spot">
|
||||
<a href="/"><img src="https://pages.github.com/images/logo.svg" alt="GitHub Pages" class="logo" /></a>
|
||||
|
||||
<h1>Websites for you and your projects.</h1>
|
||||
<h2>Hosted directly from your <a href="https://github.com">GitHub repository</a>. Just edit, push, and your changes are live.</h2>
|
||||
|
||||
<a href="https://help.github.com/pages/" class="help-link">Pages Help</a>
|
||||
|
||||
<div id="slideshow">
|
||||
<img src="https://pages.github.com/images/slideshow/bootstrap.png" alt="Bootstrap" class="slide active" width="893" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="tutorial" class="tutorial">
|
||||
<h1>Ready to get started? Build your own site from scratch or generate one for your project.</h1>
|
||||
<h2>You get one site per GitHub account and organization, <br />and unlimited project sites. Let‘s get started.</h2>
|
||||
|
||||
<ul class="tabs">
|
||||
<li><a href="#user-site" class="selected">User or organization site</a></li>
|
||||
<li><a href="#project-site">Project site</a></li>
|
||||
</ul>
|
||||
|
||||
<!-- ### Start of tutorials -->
|
||||
<ul id="user-site" class="tutorial-list wrapper active">
|
||||
<li id="create-repo-step" class="image-right">
|
||||
<h4>Create a repository</h4>
|
||||
<p>Head over to <a href="https://github.com">GitHub</a> and <a data-proofer-ignore="true" href="https://github.com/new">create a new public repository</a> named <em>username</em>.github.io, where <em>username</em> is your username (or organization name) on GitHub.</p>
|
||||
|
||||
<p class="details">If the first part of the repository doesn’t exactly match your username, it won’t work, so make sure to get it right.</p>
|
||||
</li>
|
||||
|
||||
<li class="question">
|
||||
<h4>What git client are you using?</h4>
|
||||
<ul class="tabs">
|
||||
<li><a id="option-terminal" href="#terminal-step-1" class="selected">A terminal</a></li>
|
||||
<li><a id="option-desktop" href="#setup-in-desktop">GitHub Desktop</a></li>
|
||||
<li><a id="option-newuser" href="#new-user-step-1">I don't know</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li id="new-user-step-1" class="option-newuser">
|
||||
<h4>Download GitHub Desktop</h4>
|
||||
<p>GitHub Desktop is a great way to use Git and GitHub on macOS and Windows.</p>
|
||||
|
||||
<a class="desktop-download" href="https://desktop.github.com"><span class="icon"></span>Download GitHub Desktop</a>
|
||||
|
||||
<img src="https://pages.github.com/images/dashboard@2x.png" width="1054" alt="GitHub Desktop screenshot" class="full-size" />
|
||||
</li>
|
||||
|
||||
<li id="terminal-step-1" class="option-terminal">
|
||||
<h4>Clone the repository</h4>
|
||||
<p>Go to the folder where you want to store your project, and clone the new repository:</p>
|
||||
|
||||
<div class="terminal">
|
||||
<div class="header"></div>
|
||||
<div class="shell">
|
||||
<p><span class="path">~</span><span class="prompt">$</span>git clone https://github.com/<em>username</em>/<em>username</em>.github.io</p>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li id="setup-in-desktop" class="option-desktop image-right">
|
||||
<h4>Clone the repository</h4>
|
||||
<p>Click the "Set up in Desktop" button. When the GitHub desktop app opens, save the project.</p>
|
||||
|
||||
<p class="details">If the app doesn't open, launch it and clone the repository from the app.</p>
|
||||
</li>
|
||||
|
||||
<li id="setup-in-desktop" class="option-newuser image-right">
|
||||
<h4>Clone the repository</h4>
|
||||
<p>After finishing the installation, head back to GitHub.com and refresh the page. Click the "Set up in Desktop" button. When the GitHub desktop app opens, save the project.</p>
|
||||
|
||||
<p class="details">If the app doesn't open, launch it and clone the repository from the app.</p>
|
||||
</li>
|
||||
|
||||
<li class="option-terminal">
|
||||
<h4>Hello World</h4>
|
||||
<p>Enter the project folder and add an index.html file:</p>
|
||||
|
||||
<div class="terminal">
|
||||
<div class="header"></div>
|
||||
<div class="shell">
|
||||
<p><span class="path">~</span><span class="prompt">$</span>cd <em>username</em>.github.io</p>
|
||||
<p><span class="path">~</span><span class="prompt">$</span>echo "Hello World" > index.html</p>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="option-desktop option-newuser">
|
||||
<h4>Create an index file</h4>
|
||||
<p>Grab your favorite text editor and add an index.html file to your project:</p>
|
||||
|
||||
<div class="terminal">
|
||||
<div class="header">index.html</div>
|
||||
<code class="shell">
|
||||
<pre><!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<h1>Hello World</h1>
|
||||
<p>I'm hosted with GitHub Pages.</p>
|
||||
</body>
|
||||
</html></pre>
|
||||
</code>
|
||||
</li>
|
||||
|
||||
<li class="option-terminal">
|
||||
<h4>Push it</h4>
|
||||
<p>Add, commit, and push your changes:</p>
|
||||
|
||||
<div class="terminal">
|
||||
<div class="header"></div>
|
||||
<div class="shell">
|
||||
<p><span class="path">~</span><span class="prompt">$</span>git add --all</p>
|
||||
<p><span class="path">~</span><span class="prompt">$</span>git commit -m "Initial commit"</p>
|
||||
<p><span class="path">~</span><span class="prompt">$</span>git push -u origin main</p>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="option-desktop option-newuser">
|
||||
<h4>Commit & publish</h4>
|
||||
|
||||
<p>Enter the repository, commit your changes, and press the publish button.</p>
|
||||
|
||||
<img src="https://pages.github.com/images/desktop-demo@2x.gif" width="841" alt="Demonstration of steps required to create the initial commit and publish the repository in GitHub Desktop" class="macos-drop-shadow" />
|
||||
</li>
|
||||
|
||||
<li class="option-all">
|
||||
<h4>…and you're done!</h4>
|
||||
<p>Fire up a browser and go to <strong>https://<em>username</em>.github.io</strong>.</p>
|
||||
<div class="hero-octicon">
|
||||
<span class="mega-octicon octicon-check"></span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<!-- End of user site tutorial -->
|
||||
|
||||
<!-- Project Site tutorial -->
|
||||
<ul id="project-site" class="tutorial-list wrapper">
|
||||
<li class="question">
|
||||
<h4>Use a theme, or start from scratch?</h4>
|
||||
<p>You have the option to start with one of the pre-built themes,
|
||||
<br>or to create a site from scratch.
|
||||
<ul class="tabs">
|
||||
<li><a id="option-generate" href="#generate-step-1" class="selected">Choose a theme</a></li>
|
||||
<li><a id="option-vanilla" href="#vanilla-step-1">Start from scratch</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li id="generate-step-1" class="option-generate">
|
||||
<h4>Repository Settings</h4>
|
||||
<p>Head over to <a href="https://github.com/">GitHub.com</a> and create a new repository, or go to an existing one.
|
||||
<br><strong>Click on the Settings tab</strong>.</p>
|
||||
|
||||
<img src="https://pages.github.com/images/repo-settings@2x.png" width="720" alt="Settings for a repository" />
|
||||
</li>
|
||||
|
||||
<li class="option-generate">
|
||||
<h4>Theme chooser</h4>
|
||||
<p>Scroll down to the <strong>GitHub Pages</strong> section. Press <strong>Choose a theme</strong>.</p>
|
||||
<img src="https://pages.github.com/images/launch-theme-chooser@2x.png" width="720" alt="Automatic Generator button on GitHub.com, Settings" />
|
||||
</li>
|
||||
|
||||
<li class="option-generate">
|
||||
<h4>Pick a theme</h4>
|
||||
<p>Choose one of the themes from the carousel at the top.
|
||||
<br>When you're done, click <strong>Select theme</strong> on the right.</p>
|
||||
|
||||
<img src="https://pages.github.com/images/theme-chooser@2x.png" class="full-size" width="720" alt="Choose layout" />
|
||||
</li>
|
||||
|
||||
<li class="option-generate">
|
||||
<h4>Edit content</h4>
|
||||
<p>Use the editor to add content to your site.</p>
|
||||
<img class="full-size" src="https://pages.github.com/images/code-editor@2x.png" width="720" alt="Add content to your GitHub Pages site" />
|
||||
</li>
|
||||
|
||||
<li class="option-generate">
|
||||
<h4>Commit</h4>
|
||||
<p>Enter a commit comment and click on <strong>Commit changes</strong> below the editor.</p>
|
||||
<img class="full-size" src="https://pages.github.com/images/commit-edits@2x.png" width="720" alt="Commit Markdown content to your repository" />
|
||||
</li>
|
||||
|
||||
<!-- Start of vanilla sub tutorial -->
|
||||
<li id="vanilla-step-1" class="option-vanilla">
|
||||
<h4>Create an index file</h4>
|
||||
<p>Head over to <a href="https://github.com/">GitHub.com</a> and <a data-proofer-ignore="true" href="https://github.com/new">create a new repository</a>, or go to an existing one.
|
||||
<br />Click on the <strong>Create new file</strong> button.</p>
|
||||
|
||||
<img src="https://pages.github.com/images/new-create-file@2x.png" width="720" alt="Create a file in your repository" />
|
||||
</li>
|
||||
|
||||
<li class="option-vanilla">
|
||||
<h4>Hello World</h4>
|
||||
<p>Name the file <code>index.html</code> and type some HTML content into the editor.</p>
|
||||
|
||||
<img src="https://pages.github.com/images/new-index-html@2x.png" width="720" alt="Hello World on GitHub.com" />
|
||||
</li>
|
||||
|
||||
<li class="option-vanilla">
|
||||
<h4>Commit the file</h4>
|
||||
<p>Scroll to the bottom of the page, write a commit message, and commit the new file.</p>
|
||||
|
||||
<img src="https://pages.github.com/images/new-commit-file@2x.png" width="720" alt="Commit the file" />
|
||||
</li>
|
||||
|
||||
<li class="option-vanilla">
|
||||
<h4>Repository Settings</h4>
|
||||
<p><strong>Click on the Settings tab</strong> and scroll down to the GitHub Pages section.
|
||||
<br />Then select the <strong>main branch</strong> source and click on the <strong>Save</strong> button.</p>
|
||||
|
||||
<img src="https://pages.github.com/images/source-setting@2x.png" width="720" alt="GitHub Pages Source Setting" />
|
||||
</li>
|
||||
|
||||
<li class="option-all">
|
||||
<h4>…and you're done!</h4>
|
||||
<p>Fire up a browser and go to <strong>http://<em>username</em>.github.io/<em>repository</em></strong>.</p>
|
||||
<div class="hero-octicon">
|
||||
<span class="mega-octicon octicon-check"></span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</section>
|
||||
<!-- End of tutorial section -->
|
||||
|
||||
<section id="next-steps">
|
||||
<h1>Now that you’re up and running, here are a few things you should know.</h1>
|
||||
|
||||
<ul class="next-steps wrapper">
|
||||
<li class="jekyll">
|
||||
<a class="hero-octicon" href="https://docs.github.com/en/pages/setting-up-a-github-pages-site-with-jekyll/about-github-pages-and-jekyll">
|
||||
<span class="mega-octicon octicon-pencil"></span>
|
||||
</a>
|
||||
<h4><a href="https://docs.github.com/en/pages/setting-up-a-github-pages-site-with-jekyll/about-github-pages-and-jekyll">Blogging with Jekyll</a></h4>
|
||||
<p>Using <a href="https://jekyllrb.com">Jekyll</a>, you can blog using beautiful Markdown syntax, and without having to deal with any databases. <a href="https://jekyllrb.com/docs/">Learn how to set up Jekyll</a>.</p>
|
||||
</li>
|
||||
<li class="custom-urls">
|
||||
<a class="hero-octicon" href="https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site">
|
||||
<span class="mega-octicon octicon-link"></span>
|
||||
</a>
|
||||
<h4><a href="https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site">Custom URLs</a></h4>
|
||||
<p>Want to use your own custom domain for a GitHub Pages site? Just create a file named CNAME and include your URL. <a href="https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site">Read more</a>.</p>
|
||||
</li>
|
||||
<li class="guides">
|
||||
<a class="hero-octicon" href="https://docs.github.com/pages">
|
||||
<span class="mega-octicon octicon-book"></span>
|
||||
</a>
|
||||
<h4><a href="https://docs.github.com/pages">Guides</a></h4>
|
||||
<p>Learn how to create custom 404 pages, use submodules, and <a href="https://docs.github.com/pages">learn more about GitHub Pages</a>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<script src="https://pages.github.com/js/jquery.js"></script>
|
||||
<script>window.slides = {"bootstrap":"Bootstrap","yeoman":"Yeoman","facebookdesign":"Facebook Design","foundation":"Foundation","ghtraining":"GitHub Training","adobeos":"Adobe Open Source","jekyllrb":"Jekyll","electron":"Electron","semanticui":"Semantic UI","microsoft":"Microsoft on GitHub"}</script>
|
||||
<script src="https://pages.github.com/js/application.js"></script>
|
||||
|
||||
|
||||
<footer class="page-footer">
|
||||
<ul class="site-footer-links right">
|
||||
<li><a href="https://www.githubstatus.com/">Status</a></li>
|
||||
<li><a href="https://docs.github.com/rest">API</a></li>
|
||||
<li><a href="https://training.github.com">Training</a></li>
|
||||
<li><a href="https://shop.github.com">Shop</a></li>
|
||||
<li><a href="https://github.blog">Blog</a></li>
|
||||
<li><a href="https://github.com/about">About</a></li>
|
||||
</ul>
|
||||
|
||||
<a href="/">
|
||||
<span class="mega-octicon octicon-mark-github"></span>
|
||||
</a>
|
||||
|
||||
<ul class="site-footer-links">
|
||||
<li>© 2025 <span>GitHub</span>, Inc.</li>
|
||||
<li><a href="https://docs.github.com/en/github/site-policy/github-terms-of-service">Terms</a></li>
|
||||
<li><a href="https://docs.github.com/en/github/site-policy/github-privacy-statement">Privacy</a></li>
|
||||
<li><a href="https://github.com/security">Security</a></li>
|
||||
<li><a href="https://support.github.com">Contact</a></li>
|
||||
</ul>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue