Code-Input was updated to 1.2.2 and currently works! I have the upload functionality working and have begun working on an undo button. It currently saves all the files to a dir everytime you access /templates but I haven't implemented a full undo yet.
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
57
app/forms.py
57
app/forms.py
@ -1,10 +1,55 @@
|
|||||||
from flask_wtf import FlaskForm
|
from flask_wtf import FlaskForm
|
||||||
from wtforms.fields import SubmitField
|
from wtforms.fields import (SubmitField,
|
||||||
|
PasswordField,
|
||||||
|
StringField,
|
||||||
|
TextAreaField,
|
||||||
|
IntegerField,
|
||||||
|
BooleanField,
|
||||||
|
RadioField)
|
||||||
|
from wtforms.validators import InputRequired, Length
|
||||||
|
from flask_wtf.file import FileField, FileRequired
|
||||||
|
from werkzeug.utils import secure_filename
|
||||||
from flask_codemirror.fields import CodeMirrorField
|
from flask_codemirror.fields import CodeMirrorField
|
||||||
|
|
||||||
class TemplateForm(FlaskForm):
|
|
||||||
template_code = CodeMirrorField(
|
class ApiKey(FlaskForm):
|
||||||
language='htmlembedded',
|
api_key = PasswordField('Api Key',
|
||||||
config={'lineNumbers': 'true'})
|
validators=[InputRequired(),
|
||||||
submit = SubmitField('Submit')
|
Length(min=20, max=25)]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TemplateForm(FlaskForm):
|
||||||
|
name = StringField("Template File Name",
|
||||||
|
validators=[InputRequired()])
|
||||||
|
|
||||||
|
body = TextAreaField("Template Code",
|
||||||
|
validators=[InputRequired()])
|
||||||
|
|
||||||
|
submit = SubmitField('Upload Templates')
|
||||||
|
|
||||||
|
# template_code = CodeMirrorField( language='htmlembedded',
|
||||||
|
# config={'lineNumbers': 'true'})
|
||||||
|
|
||||||
|
class CsvForm(FlaskForm):
|
||||||
|
file = FileField(validators=[FileRequired()])
|
||||||
|
all_or_some = RadioField("All or Some",
|
||||||
|
choices=['All learners in all groups',
|
||||||
|
'Learners only in adjacent groups'],
|
||||||
|
validators=[InputRequired()])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class CourseForm(FlaskForm):
|
||||||
|
title = StringField('Title',
|
||||||
|
validators=[InputRequired(),
|
||||||
|
Length(min=10, max=100)])
|
||||||
|
description = TextAreaField('Course Description',
|
||||||
|
validators=[InputRequired(),
|
||||||
|
Length(max=200)])
|
||||||
|
price = IntegerField('Price', validators=[InputRequired()])
|
||||||
|
level = RadioField('Level',
|
||||||
|
choices=['Beginner', 'Intermediate', 'Advanced'],
|
||||||
|
validators=[InputRequired()])
|
||||||
|
available = BooleanField('Available', default='checked')
|
||||||
|
|
||||||
|
|||||||
143
app/routes.py
143
app/routes.py
@ -13,6 +13,7 @@ from flask import (
|
|||||||
session,
|
session,
|
||||||
make_response,
|
make_response,
|
||||||
url_for,
|
url_for,
|
||||||
|
g,
|
||||||
)
|
)
|
||||||
from werkzeug.utils import secure_filename
|
from werkzeug.utils import secure_filename
|
||||||
from app import app, forms
|
from app import app, forms
|
||||||
@ -26,6 +27,7 @@ ALLOWED_EXTENSIONS = {"csv"}
|
|||||||
# Global Variables
|
# Global Variables
|
||||||
url = "https://api.northpass.com/"
|
url = "https://api.northpass.com/"
|
||||||
|
|
||||||
|
|
||||||
def download_csv():
|
def download_csv():
|
||||||
if request.method == "GET":
|
if request.method == "GET":
|
||||||
download = make_response(session["dfcsv"])
|
download = make_response(session["dfcsv"])
|
||||||
@ -57,11 +59,13 @@ def allowed_file(filename):
|
|||||||
def key_required(check):
|
def key_required(check):
|
||||||
@wraps(check)
|
@wraps(check)
|
||||||
def decorated_function(*args, **kwargs):
|
def decorated_function(*args, **kwargs):
|
||||||
if session.get('key') is None:
|
if session.get("key") is None:
|
||||||
return redirect('/',code=302)
|
return redirect("/", code=302)
|
||||||
return check(*args, **kwargs)
|
return check(*args, **kwargs)
|
||||||
|
|
||||||
return decorated_function
|
return decorated_function
|
||||||
|
|
||||||
|
|
||||||
@app.route("/", methods=["GET", "POST"])
|
@app.route("/", methods=["GET", "POST"])
|
||||||
def ask_key():
|
def ask_key():
|
||||||
"""This is the main function that asks for the API Key.
|
"""This is the main function that asks for the API Key.
|
||||||
@ -71,8 +75,9 @@ def ask_key():
|
|||||||
specials = '"!@#$%^&*()-+?_=,<>/"'
|
specials = '"!@#$%^&*()-+?_=,<>/"'
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
session["key"] = request.form.get("apikey")
|
session["key"] = request.form.get("apikey")
|
||||||
if (any(char in specials for char in session["key"]) or
|
if any(char in specials for char in session["key"]) or re.search(
|
||||||
re.search(r"[\s]", session["key"])):
|
r"[\s]", session["key"]
|
||||||
|
):
|
||||||
error = "Invalid Key."
|
error = "Invalid Key."
|
||||||
session.clear()
|
session.clear()
|
||||||
return render_template("index.html", title="Home", error=error)
|
return render_template("index.html", title="Home", error=error)
|
||||||
@ -100,7 +105,7 @@ def render_home():
|
|||||||
def clear_session():
|
def clear_session():
|
||||||
if session.get("key"):
|
if session.get("key"):
|
||||||
session.clear()
|
session.clear()
|
||||||
error="Session Cleared!"
|
error = "Session Cleared!"
|
||||||
return render_template("index.html", error=error, title="Home, New session")
|
return render_template("index.html", error=error, title="Home, New session")
|
||||||
return render_template("index.html", title="Home, New session")
|
return render_template("index.html", title="Home, New session")
|
||||||
|
|
||||||
@ -109,6 +114,7 @@ def clear_session():
|
|||||||
def table():
|
def table():
|
||||||
return render_template("table.html", tables=[session["table"]], titles=["Table"])
|
return render_template("table.html", tables=[session["table"]], titles=["Table"])
|
||||||
|
|
||||||
|
|
||||||
@app.route("/upload_file", methods=["GET", "POST"])
|
@app.route("/upload_file", methods=["GET", "POST"])
|
||||||
@key_required
|
@key_required
|
||||||
def upload_file():
|
def upload_file():
|
||||||
@ -133,11 +139,12 @@ def upload_file():
|
|||||||
return divide_values(file)
|
return divide_values(file)
|
||||||
return render_template("home.html", title="Bulk Add")
|
return render_template("home.html", title="Bulk Add")
|
||||||
|
|
||||||
|
|
||||||
def divide_values(file):
|
def divide_values(file):
|
||||||
emails = []
|
emails = []
|
||||||
groups = []
|
groups = []
|
||||||
selection = request.form.get('learner-groups')
|
selection = request.form.get("learner-groups")
|
||||||
if request.form['submit']:
|
if request.form["submit"]:
|
||||||
if selection == "all-groups":
|
if selection == "all-groups":
|
||||||
for item in file[1:]:
|
for item in file[1:]:
|
||||||
emails.append(item[0])
|
emails.append(item[0])
|
||||||
@ -160,13 +167,12 @@ def divide_values(file):
|
|||||||
return api_csv_parse(emails, groups)
|
return api_csv_parse(emails, groups)
|
||||||
return emails
|
return emails
|
||||||
|
|
||||||
if request.form['preview']:
|
if request.form["preview"]:
|
||||||
error="Preview Button Still Under Construction. Try again later."
|
error = "Preview Button Still Under Construction. Try again later."
|
||||||
return render_template("bulk_add.html", error=error, title="Preview Not Yet")
|
return render_template("bulk_add.html", error=error, title="Preview Not Yet")
|
||||||
|
|
||||||
return render_template(
|
return render_template("bulk_add.html", title="Uploaded File")
|
||||||
"bulk_add.html", title="Uploaded File"
|
|
||||||
)
|
|
||||||
|
|
||||||
def api_csv_parse(emails, groups):
|
def api_csv_parse(emails, groups):
|
||||||
if emails and groups:
|
if emails and groups:
|
||||||
@ -175,13 +181,15 @@ def api_csv_parse(emails, groups):
|
|||||||
return api_add_ppl(emails)
|
return api_add_ppl(emails)
|
||||||
elif groups:
|
elif groups:
|
||||||
return api_add_groups(groups)
|
return api_add_groups(groups)
|
||||||
return render_template("bulk_add.html", table=htmlcsv, title="CSV Submission")
|
return render_template("bulk_add.html", title="CSV Submission")
|
||||||
|
|
||||||
|
|
||||||
@app.route("/bulk_add_opts", methods=["GET", "POST"])
|
@app.route("/bulk_add_opts", methods=["GET", "POST"])
|
||||||
@key_required
|
@key_required
|
||||||
def bulk_add_opts():
|
def bulk_add_opts():
|
||||||
return render_template("bulk_add.html", titles="Bulk Add Options")
|
return render_template("bulk_add.html", titles="Bulk Add Options")
|
||||||
|
|
||||||
|
|
||||||
@app.route("/bulk_add", methods=["GET", "POST"])
|
@app.route("/bulk_add", methods=["GET", "POST"])
|
||||||
@key_required
|
@key_required
|
||||||
def bulk_add():
|
def bulk_add():
|
||||||
@ -223,8 +231,8 @@ def api_add_ppl(emails):
|
|||||||
payload2 = []
|
payload2 = []
|
||||||
endpoint = "v2/bulk/people"
|
endpoint = "v2/bulk/people"
|
||||||
for email in emails:
|
for email in emails:
|
||||||
payload2.append({"email": email })
|
payload2.append({"email": email})
|
||||||
payload = {"data": {"attributes": {"people": payload2 }}}
|
payload = {"data": {"attributes": {"people": payload2}}}
|
||||||
headers = {
|
headers = {
|
||||||
"accept": "application/json",
|
"accept": "application/json",
|
||||||
"content-type": "application/json",
|
"content-type": "application/json",
|
||||||
@ -239,8 +247,8 @@ def api_add_groups(groups):
|
|||||||
payload2 = []
|
payload2 = []
|
||||||
endpoint = "v2/bulk/people"
|
endpoint = "v2/bulk/people"
|
||||||
for group in groups:
|
for group in groups:
|
||||||
payload2.append({"groups" : group })
|
payload2.append({"groups": group})
|
||||||
payload = {"data": {"attributes": {"people": payload2 }}}
|
payload = {"data": {"attributes": {"people": payload2}}}
|
||||||
headers = {
|
headers = {
|
||||||
"accept": "application/json",
|
"accept": "application/json",
|
||||||
"content-type": "application/json",
|
"content-type": "application/json",
|
||||||
@ -257,9 +265,7 @@ def api_add_ppl_groups(emails, groups):
|
|||||||
combinations = list(itertools.product(emails, groups))
|
combinations = list(itertools.product(emails, groups))
|
||||||
for combo in combinations:
|
for combo in combinations:
|
||||||
payload2.append({"email": combo[0], "groups": combo[1]})
|
payload2.append({"email": combo[0], "groups": combo[1]})
|
||||||
payload = {
|
payload = {"data": {"attributes": {"people": payload2}}}
|
||||||
"data": {"attributes": {"people": payload2 }}
|
|
||||||
}
|
|
||||||
|
|
||||||
headers = {
|
headers = {
|
||||||
"accept": "application/json",
|
"accept": "application/json",
|
||||||
@ -267,8 +273,8 @@ def api_add_ppl_groups(emails, groups):
|
|||||||
"X-Api-Key": session["key"],
|
"X-Api-Key": session["key"],
|
||||||
}
|
}
|
||||||
return payload
|
return payload
|
||||||
#response = requests.post(url + endpoint, json=payload, headers=headers)
|
# response = requests.post(url + endpoint, json=payload, headers=headers)
|
||||||
#return check_response(response)
|
# return check_response(response)
|
||||||
|
|
||||||
|
|
||||||
def check_response(response):
|
def check_response(response):
|
||||||
@ -286,11 +292,12 @@ def check_response(response):
|
|||||||
error = "Something went wrong, but I'm not sure what."
|
error = "Something went wrong, but I'm not sure what."
|
||||||
return render_template("bulk_add.html", title="Shrug", error=error)
|
return render_template("bulk_add.html", title="Shrug", error=error)
|
||||||
|
|
||||||
|
|
||||||
@app.route("/load_templates", methods=["GET", "POST"])
|
@app.route("/load_templates", methods=["GET", "POST"])
|
||||||
@key_required
|
@key_required
|
||||||
def load_templates():
|
def load_templates():
|
||||||
count = 0
|
count = 0
|
||||||
templates= []
|
templates = []
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
count += 1
|
count += 1
|
||||||
@ -300,33 +307,44 @@ def load_templates():
|
|||||||
"content-type": "application/json",
|
"content-type": "application/json",
|
||||||
"X-Api-Key": session["key"],
|
"X-Api-Key": session["key"],
|
||||||
}
|
}
|
||||||
response = requests.get(url+endpoint, headers=headers)
|
response = requests.get(url + endpoint, headers=headers)
|
||||||
data = response.json()
|
data = response.json()
|
||||||
nextlink = data["links"]
|
nextlink = data["links"]
|
||||||
for response in data["data"]:
|
for response in data["data"]:
|
||||||
name, body = (
|
last_updated = response["attributes"]["updated_at"].split("T")
|
||||||
response["attributes"]["name"], response["attributes"]["body"])
|
last_updated = last_updated[0]
|
||||||
templates.append((name,body))
|
name, body, last_updated = (
|
||||||
|
response["attributes"]["name"],
|
||||||
|
response["attributes"]["body"],
|
||||||
|
last_updated,
|
||||||
|
)
|
||||||
|
templates.append((name, body, last_updated))
|
||||||
|
|
||||||
if "next" not in nextlink:
|
if "next" not in nextlink:
|
||||||
break
|
break
|
||||||
|
|
||||||
return render_template("templates.html",
|
save_templates_backup(templates)
|
||||||
title="Templates",
|
return render_template(
|
||||||
templates=templates,
|
"templates.html",
|
||||||
)
|
title="Templates",
|
||||||
|
templates=templates,
|
||||||
|
)
|
||||||
|
|
||||||
return render_template("options.html")
|
return render_template("options.html")
|
||||||
|
|
||||||
|
|
||||||
@app.route("/templates", methods=["GET", "POST"])
|
@app.route("/templates", methods=["GET", "POST"])
|
||||||
@key_required
|
@key_required
|
||||||
def templates():
|
def templates():
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
if request.form['submit-template']:
|
if request.form["submit-template"]:
|
||||||
name = request.form.get('template_name')
|
name = request.form.get("template_name")
|
||||||
body = request.form.get("loaded-content")
|
body = request.form.get("body")
|
||||||
|
g.last_template = name
|
||||||
if body == "":
|
if body == "":
|
||||||
error = "Ooph. Looks like you didn't load the changes before submitting."
|
error = (
|
||||||
|
"Ooph. Looks like you didn't load the changes before submitting."
|
||||||
|
)
|
||||||
return render_template("templates.html", error=error)
|
return render_template("templates.html", error=error)
|
||||||
else:
|
else:
|
||||||
endpoint = "v2/custom_templates"
|
endpoint = "v2/custom_templates"
|
||||||
@ -335,22 +353,21 @@ def templates():
|
|||||||
"content-type": "application/json",
|
"content-type": "application/json",
|
||||||
"X-Api-Key": session["key"],
|
"X-Api-Key": session["key"],
|
||||||
}
|
}
|
||||||
payload = {"custom_template": {
|
payload = {"custom_template": {"name": name, "body": body}}
|
||||||
"name":name,
|
response = requests.post(url + endpoint, json=payload, headers=headers)
|
||||||
"body":body
|
|
||||||
}}
|
|
||||||
response = requests.post(url+endpoint, json=payload, headers=headers)
|
|
||||||
return check_templates(response)
|
return check_templates(response)
|
||||||
return load_templates()
|
return load_templates()
|
||||||
|
|
||||||
|
|
||||||
def check_templates(response):
|
def check_templates(response):
|
||||||
print(response)
|
print(response)
|
||||||
response = str(response)
|
response = str(response)
|
||||||
if "201" in response:
|
if "201" in response:
|
||||||
error = "Success! Templates Uploaded."
|
error = "Success! Templates Uploaded."
|
||||||
return render_template("templates.html",
|
button = "Undo"
|
||||||
title="Templates Added",
|
return render_template(
|
||||||
error=error)
|
"templates.html", title="Templates Added", error=error, button=button
|
||||||
|
)
|
||||||
elif "403" in response:
|
elif "403" in response:
|
||||||
error = "Uh oh. Looks like you don't have appropriate privileges."
|
error = "Uh oh. Looks like you don't have appropriate privileges."
|
||||||
return render_template("templates.html", error=error)
|
return render_template("templates.html", error=error)
|
||||||
@ -362,28 +379,44 @@ def check_templates(response):
|
|||||||
return render_template("templates.html", title="Shrug", error=error)
|
return render_template("templates.html", title="Shrug", error=error)
|
||||||
|
|
||||||
|
|
||||||
@app.route("/bulk_courses_to_groups", methods=["GET", "POST"])
|
def save_templates_backup(templates):
|
||||||
|
g.client_path = os.path.join(UPLOAD_FOLDER, session["school"])
|
||||||
|
if os.path.exists(g.client_path):
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
os.mkdir(g.client_path)
|
||||||
|
|
||||||
|
for tupe in templates:
|
||||||
|
file_name = tupe[0] + ".liquid"
|
||||||
|
file_body = tupe[1]
|
||||||
|
complete_path = os.path.join(g.client_path, file_name)
|
||||||
|
|
||||||
|
with open(complete_path, "w+") as temp:
|
||||||
|
temp.write(file_body)
|
||||||
|
temp.close
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/undo_template", methods=["POST"])
|
||||||
@key_required
|
@key_required
|
||||||
def bulk_courses_to_groups():
|
def undo_template():
|
||||||
pass
|
print(g.client_path)
|
||||||
|
template_path = os.path.join(g.client_path, g.last_template)
|
||||||
|
if request.method == "POST":
|
||||||
|
if request.form["undo_templates"]:
|
||||||
|
if os.path.exists(template_path):
|
||||||
|
print(template_path)
|
||||||
|
|
||||||
|
|
||||||
@app.route("/bulk_invite_ppl", methods=["GET", "POST"])
|
@app.route("/cmtest", methods=["GET", "POST"])
|
||||||
@key_required
|
|
||||||
def bulk_invite_ppl():
|
|
||||||
pass
|
|
||||||
|
|
||||||
@app.route('/cmtest', methods = ['GET', 'POST'])
|
|
||||||
def cmtest():
|
def cmtest():
|
||||||
form = TemplateForm()
|
form = TemplateForm()
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
text = form.template_code.data
|
text = form.template_code.data
|
||||||
return render_template('templates.html', form=form)
|
return render_template("templates.html", form=form)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
app.secret_key = "@&I\x1a?\xce\x94\xbb0w\x17\xbf&Y\xa2\xc2(A\xf5\xf2\x97\xba\xeb\xfa"
|
app.secret_key = "@&I\x1a?\xce\x94\xbb0w\x17\xbf&Y\xa2\xc2(A\xf5\xf2\x97\xba\xeb\xfa"
|
||||||
|
|
||||||
|
|
||||||
#if __name__ == "__main__":
|
# if __name__ == "__main__":
|
||||||
# ask_key()
|
# ask_key()
|
||||||
|
|||||||
@ -0,0 +1,49 @@
|
|||||||
|
<a class="np-card" href="{% route course_enrollment, code: course.enrollment_code %}">
|
||||||
|
<div class="np-card-container">
|
||||||
|
{% if course.ribbon %}
|
||||||
|
<div class="np-card-ribbon">
|
||||||
|
{{ course.ribbon }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<video class='left-video' autoplay muted loop>
|
||||||
|
<source src="{{course.promo_video_embed_url}}" type="video/mp4" alt="{{ course.name }}">
|
||||||
|
</video>
|
||||||
|
<div class="np-card-content-bottom">
|
||||||
|
<h3 class="np-card-content-title np-color-white">
|
||||||
|
{{ course.name }}
|
||||||
|
</h3>
|
||||||
|
<div class='np-card-content-description'>
|
||||||
|
{{ course.full_description }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="np-card-content-progress np-button-color">
|
||||||
|
{% t shared.progress, count: course.progress %}
|
||||||
|
</div>
|
||||||
|
<div class="np-card-content-category">
|
||||||
|
{{course.categories.first.name}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<style>
|
||||||
|
.np-card {
|
||||||
|
text-decoration: none;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.np-card-content-category {
|
||||||
|
border-top: 1px solid lightgray;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
.np-card-content-description {
|
||||||
|
display: block;
|
||||||
|
color: lightgray;
|
||||||
|
}
|
||||||
|
.np-card-content-bottom {
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
.np-button-color {
|
||||||
|
color: lightslategray;
|
||||||
|
font-size: 15px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,44 @@
|
|||||||
|
<div class="np-card np-no-horizontal-padding">
|
||||||
|
<div class="np-card-container">
|
||||||
|
<div class="np-learning-path np-featured-course">
|
||||||
|
<div class="np-featured-course-img-container" style="overflow: hidden">
|
||||||
|
<video class='featured-video' autoplay muted loop style="margin-left: -60px;">
|
||||||
|
<source id="featured_video" src="{{course.promo_video_embed_url}}" type="video/mp4" alt="{{ course.name }}" />
|
||||||
|
</video>
|
||||||
|
<div class="np-card-image-content-top">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="np-card-text-wrapper">
|
||||||
|
<div class="np-card-content np-card-padding np-card-content-vertical">
|
||||||
|
<h3 class="np-card-content-title">
|
||||||
|
{{ course.name }}
|
||||||
|
</h3>
|
||||||
|
<div class="np-card-content-description">
|
||||||
|
{{ course.full_description }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="np-card-content-footer" style='display: flex; flex-direction: row; justify-content: space-between;'>
|
||||||
|
<a
|
||||||
|
class="np-top-button np-button-font-color np-button" href="{% route course_enrollment, code: course.enrollment_code %}"
|
||||||
|
>
|
||||||
|
{% if course.enrolled? == false %}
|
||||||
|
{% t shared.enroll %}
|
||||||
|
{% elsif course.started? == false %}
|
||||||
|
{% t shared.start, key: current_school.course_vocabulary %}
|
||||||
|
{% elsif course.completed? %}
|
||||||
|
{% t shared.course.view, key: current_school.course_vocabulary %}
|
||||||
|
{% else %}
|
||||||
|
{% t shared.continue %}
|
||||||
|
{% endif %}
|
||||||
|
</a>
|
||||||
|
<div class="np-card-image-content-bottom" style="position: unset;">
|
||||||
|
<div class="np-card-content-progress np-button-color">
|
||||||
|
{% t shared.progress, count: course.progress %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@ -0,0 +1,80 @@
|
|||||||
|
<footer class="np-footer">
|
||||||
|
<div class="np-footer-top">
|
||||||
|
{% if website_footer.show_navigation_links? %}
|
||||||
|
<div class="np-footer-navigation">
|
||||||
|
<ul class="np-footer-navigation-list">
|
||||||
|
{% for website_navigation in navigations.footer_navigations %}
|
||||||
|
{% if website_navigation.external? %}
|
||||||
|
<li class="np-footer-navigation-item">
|
||||||
|
<a
|
||||||
|
class="np-footer-navigation-link np-button-color"
|
||||||
|
href="{{ website_navigation.path }}"
|
||||||
|
{% if website_navigation.external? %} target="_blank" {% endif %}
|
||||||
|
>
|
||||||
|
{{ website_navigation.name }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if current_school.logo_url %}
|
||||||
|
<h2 class="np-footer-logo">
|
||||||
|
<a href="{% route home %}">
|
||||||
|
<img
|
||||||
|
alt="{{ current_school.name }}"
|
||||||
|
class="np-footer-logo-image"
|
||||||
|
src="{{ current_school.logo_url }}"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</h2>
|
||||||
|
{% else %}
|
||||||
|
<div class="np-school-name np-header-font-color">
|
||||||
|
{{ current_school.name }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="np-footer-bottom">
|
||||||
|
<nav class="np-footer-social-links">
|
||||||
|
{% if website_footer.show_social_media_links? %}
|
||||||
|
<ul class="np-footer-social-links-list">
|
||||||
|
{% for social_media_link in website_footer.social_media_links %}
|
||||||
|
<li class="np-footer-social-links-item">
|
||||||
|
<a
|
||||||
|
class="np-footer-social-links-link np-button-color"
|
||||||
|
href="{{ social_media_link.link }}"
|
||||||
|
target="_blank" title="{{ social_media_link.name }}"
|
||||||
|
>
|
||||||
|
<i class="np-footer-social-links-icon
|
||||||
|
np-button-color
|
||||||
|
fab fa-{{ social_media_link.name }}"
|
||||||
|
></i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
{% if website_footer.show_customer_service_email? and
|
||||||
|
website_footer.school_customer_service_email
|
||||||
|
%}
|
||||||
|
<div class="np-footer-support">
|
||||||
|
<div class="np-footer-support-item np-footer-support-help np-fc-white np-opacity-50">
|
||||||
|
{% t .need_help %}
|
||||||
|
</div>
|
||||||
|
<div class="np-footer-support-item np-footer-support-email np-fc-white np-opacity-50">
|
||||||
|
{% t .email %}
|
||||||
|
</div>
|
||||||
|
<a
|
||||||
|
class="np-footer-support-item np-footer-support-link np-button-color"
|
||||||
|
href="mailto:{{ website_footer.school_customer_service_email }}"
|
||||||
|
>
|
||||||
|
support@menlosecurity.com
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
11
app/static/files/[Sandbox] Norm's Academy/_head.html.liquid
Normal file
11
app/static/files/[Sandbox] Norm's Academy/_head.html.liquid
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{% styles default %}
|
||||||
|
{% styles colors %}
|
||||||
|
{% styles custom %}
|
||||||
|
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Raleway:wght@200;300;400;500&display=swap" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.8.1/slick.css" integrity="sha512-wR4oNhLBHf7smjy0K4oqzdWumd+r5/+6QO/vDda76MW5iug4PT7v86FoEkySIJft3XA0Ae6axhIvHrqwm793Nw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
||||||
|
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.8.1/slick.min.js" type="text/javascript"></script>
|
||||||
183
app/static/files/[Sandbox] Norm's Academy/_header.html.liquid
Normal file
183
app/static/files/[Sandbox] Norm's Academy/_header.html.liquid
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
<header class="np-header np-header-color" >
|
||||||
|
<div class="np-header-content">
|
||||||
|
<div class="np-hidden-desktop np-header-mobile-menu-nav">
|
||||||
|
{% if current_person.signed_in? %}
|
||||||
|
<button
|
||||||
|
data-toggle-class="np-hidden"
|
||||||
|
class="np-header-mobile-menu-nav-button fal fa-times np-hidden np-header-font-color"
|
||||||
|
data-toggle-target=".np-header-mobile-avatar-menu,
|
||||||
|
.np-header-mobile-menu-content, .np-main, .np-footer"
|
||||||
|
></button>
|
||||||
|
<button
|
||||||
|
data-test="open-mobile-menu"
|
||||||
|
data-toggle-class="np-hidden"
|
||||||
|
class="np-header-mobile-menu-nav-button np-header-mobile-avatar-menu"
|
||||||
|
data-toggle-target=".fa-times, .np-header-mobile-menu-content, .np-main, .np-footer"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
alt="{{ current_person.name }}"
|
||||||
|
class="np-header-avatar-image"
|
||||||
|
src="{{ current_person.avatar_url }}"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% if current_school.logo_url %}
|
||||||
|
<h1 class="np-header-logo">
|
||||||
|
<a href="{% route home %}">
|
||||||
|
<img
|
||||||
|
alt="{{ current_school.name }}"
|
||||||
|
class="np-header-logo-image"
|
||||||
|
src="{{ current_school.logo_url }}"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</h1>
|
||||||
|
{% else %}
|
||||||
|
<a href="{% route home %}" class="np-school-name np-header-font-color">
|
||||||
|
{{ current_school.name }}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="np-hidden-mobile np-header-desktop-nav">
|
||||||
|
<ul class="np-header-desktop-nav-list">
|
||||||
|
{% for website_navigation in navigations.header_navigations_external %}
|
||||||
|
<li class= "np-header-desktop-nav-item">
|
||||||
|
<a
|
||||||
|
href="{{ website_navigation.path }}"
|
||||||
|
class="np-header-desktop-nav-link np-header-font-color"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
{{ website_navigation.name }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if current_person.signed_in? %}
|
||||||
|
<div class="np-hidden-mobile np-header-search np-header-search-expanded">
|
||||||
|
<form action="{% route search %}" method="get" data-test="desktop-search">
|
||||||
|
<input
|
||||||
|
aria-label="{% t .search %}"
|
||||||
|
class="np-header-search-input np-header-font-background-color"
|
||||||
|
type="text"
|
||||||
|
name="q"
|
||||||
|
placeholder="{% t .search %}"
|
||||||
|
/>
|
||||||
|
<i class="np-header-search-icon far fa-search"></i>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="np-hidden-mobile np-header-avatar">
|
||||||
|
<button
|
||||||
|
class="np-header-avatar-button"
|
||||||
|
data-test="open-desktop-menu"
|
||||||
|
data-toggle-class-on-target="np-hidden"
|
||||||
|
data-toggle-target=".np-header-avatar-tooltip"
|
||||||
|
data-toggle-outside
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
alt="{{ current_person.name }}"
|
||||||
|
class="np-header-avatar-image"
|
||||||
|
src="{{ current_person.avatar_url }}"
|
||||||
|
>
|
||||||
|
</button>
|
||||||
|
<div class="np-header-avatar-tooltip np-hidden" role="tooltip">
|
||||||
|
<span class="np-header-avatar-tooltip-arrow-up"></span>
|
||||||
|
<div class="np-header-avatar-tooltip-learner">
|
||||||
|
<div class="np-header-avatar-tooltip-learner-name">
|
||||||
|
{{ current_person.name }}
|
||||||
|
</div>
|
||||||
|
<div class="np-header-avatar-tooltip-learner-email">
|
||||||
|
{{ current_person.email }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<nav class="np-header-avatar-tooltip-navigation">
|
||||||
|
<a class="np-header-avatar-tooltip-navigation-link" onclick="buildURL(window.location.pathname)" style="cursor:pointer">
|
||||||
|
Default
|
||||||
|
</a>
|
||||||
|
{% unless current_school.sso_active? %}
|
||||||
|
<a
|
||||||
|
class="np-header-avatar-tooltip-navigation-link"
|
||||||
|
href="{% route account %}"
|
||||||
|
>
|
||||||
|
{% t .profile_settings %}
|
||||||
|
</a>
|
||||||
|
{% endunless %}
|
||||||
|
<a
|
||||||
|
class="np-header-avatar-tooltip-navigation-link np-danger"
|
||||||
|
href="{% route logout %}"
|
||||||
|
>
|
||||||
|
{% t .sign_out %}
|
||||||
|
</a>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<a
|
||||||
|
class="np-header-sign-in np-header-desktop-nav-link np-header-font-color"
|
||||||
|
href="{% route login %}"
|
||||||
|
>
|
||||||
|
{% t shared.sign_in %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="np-hidden-desktop">
|
||||||
|
<div class="np-header-mobile-menu-content np-hidden">
|
||||||
|
{% if current_person.signed_in? %}
|
||||||
|
<img
|
||||||
|
alt="{{ current_person.name }}"
|
||||||
|
class="np-header-mobile-menu-content-avatar"
|
||||||
|
src="{{ current_person.avatar_url }}"
|
||||||
|
/>
|
||||||
|
<div class="np-header-mobile-menu-content-name">
|
||||||
|
{{ current_person.name }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="np-header-mobile-menu-content-nav">
|
||||||
|
<form
|
||||||
|
class="np-header-search"
|
||||||
|
data-test="mobile-search"
|
||||||
|
method="get"
|
||||||
|
action="{% route search %}"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
aria-label="{% t .search %}"
|
||||||
|
class="np-header-search-input"
|
||||||
|
type="text"
|
||||||
|
name="q"
|
||||||
|
placeholder="{% t .search %}"
|
||||||
|
/>
|
||||||
|
<i class="np-header-search-icon far fa-search"></i>
|
||||||
|
</form>
|
||||||
|
{% for website_navigation in navigations.header_navigations %}
|
||||||
|
<a
|
||||||
|
href="{{ website_navigation.path }}"
|
||||||
|
class="np-header-mobile-menu-content-button"
|
||||||
|
{% if website_navigation.external? %} target="_blank" {% endif %}
|
||||||
|
>
|
||||||
|
{{ website_navigation.name }}
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
||||||
|
<div class="np-header-mobile-menu-content-line"></div>
|
||||||
|
{% unless current_school.sso_active? %}
|
||||||
|
<a
|
||||||
|
class="np-header-mobile-menu-content-button"
|
||||||
|
href="{% route account %}"
|
||||||
|
>
|
||||||
|
{% t .profile_settings %}
|
||||||
|
</a>
|
||||||
|
{% endunless %}
|
||||||
|
<a
|
||||||
|
class="np-header-mobile-menu-content-button np-danger"
|
||||||
|
href="{% route logout %}"
|
||||||
|
>
|
||||||
|
{% t .sign_out %}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% include "messages" %}
|
||||||
|
|
||||||
@ -0,0 +1,109 @@
|
|||||||
|
<div class="np-homepage-featured np-faq np-max-width">
|
||||||
|
<div class="np-homepage-featured-text">
|
||||||
|
<div class="np-homepage-headline">
|
||||||
|
Frequently Asked Questions
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row np-faqs">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="np-accordion">
|
||||||
|
<div class="accordion-btn">
|
||||||
|
<i class="fal fa-plus"></i>
|
||||||
|
<div class="accordion-title"><strong>Q:</strong> I'm not in shape. Can I still go to a climbing gym?</div>
|
||||||
|
</div>
|
||||||
|
<div class="accordion-panel">
|
||||||
|
<div class="accordion-panel-content">
|
||||||
|
<p><strong>A:</strong> Absolutely. Climbing is a wonderful full-body and full-mind workout. If you're looking to get in shapre but tired of pumping iron, climbing is a fantastic option.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="np-accordion">
|
||||||
|
<div class="accordion-btn">
|
||||||
|
<i class="fal fa-plus"></i>
|
||||||
|
<div class="accordion-title"><strong>Q:</strong> I'm scared of heights. Should I try climbing?</div>
|
||||||
|
</div>
|
||||||
|
<div class="accordion-panel">
|
||||||
|
<div class="accordion-panel-content">
|
||||||
|
<p><strong>A:</strong> Many climbers have a fear of heights! However, it goes away when you use your own strength and technique to get to the top of a wall. Start small by climbing in a gym first.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="np-accordion">
|
||||||
|
<div class="accordion-btn">
|
||||||
|
<i class="fal fa-plus"></i>
|
||||||
|
<div class="accordion-title"><strong>Q:</strong> Should I hire someone to belay me at a gym?</div>
|
||||||
|
</div>
|
||||||
|
<div class="accordion-panel">
|
||||||
|
<div class="accordion-panel-content">
|
||||||
|
<p><strong>A:</strong> You absolutely can as a quick introduction. However, what would be even better is to grab a friend and take a belay class at your local gym.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="np-accordion">
|
||||||
|
<div class="accordion-btn">
|
||||||
|
<i class="fal fa-plus"></i>
|
||||||
|
<div class="accordion-title"><strong>Q:</strong> What is bouldering?</div>
|
||||||
|
</div>
|
||||||
|
<div class="accordion-panel">
|
||||||
|
<div class="accordion-panel-content">
|
||||||
|
<p><strong>A:</strong> Great question! Bouldering is a form of climbing, done on shorter walls. You use a crash pad under your climb to cushion your fall. Be warned, bouldering is much more powerful and has a steeper learning curve.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="np-accordion">
|
||||||
|
<div class="accordion-btn">
|
||||||
|
<i class="fal fa-plus"></i>
|
||||||
|
<div class="accordion-title"><strong>Q:</strong> What are those people with all that gear hanging from their harness doing?</div>
|
||||||
|
</div>
|
||||||
|
<div class="accordion-panel">
|
||||||
|
<div class="accordion-panel-content">
|
||||||
|
<p><strong>A:</strong> Chances are you saw a trad climber! Short for traditional climbing, that gear serves as removable protection. When the climbing pair is done with the climb, nothing is left on the rock.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="np-accordion">
|
||||||
|
<div class="accordion-btn">
|
||||||
|
<i class="fal fa-plus"></i>
|
||||||
|
<div class="accordion-title"><strong>Q:</strong> None of my friends are interested in climbing. How can I find partners?</div>
|
||||||
|
</div>
|
||||||
|
<div class="accordion-panel">
|
||||||
|
<div class="accordion-panel-content">
|
||||||
|
<p><strong>A:</strong>The best way to meet people is to join a gym a start climbing! Climbers are social and you'll start meeting people. You can also use online resources like Mountain Project's Partner Finder.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
/
|
||||||
|
<style>
|
||||||
|
.fa-plus {
|
||||||
|
background-image: unset;
|
||||||
|
background: #0297FA;
|
||||||
|
}
|
||||||
|
.fa-minus {
|
||||||
|
background-image: unset;
|
||||||
|
background: #0297FA; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
let accordions = document.getElementsByClassName("accordion-btn");
|
||||||
|
|
||||||
|
for (let i = 0; i < accordions.length; i++) {
|
||||||
|
accordions[i].addEventListener("click", function() {
|
||||||
|
this.querySelector('.fal').classList.toggle("fa-plus");
|
||||||
|
this.querySelector('.fal').classList.toggle("fa-minus");
|
||||||
|
|
||||||
|
let panel = this.nextElementSibling;
|
||||||
|
panel.classList.toggle("panel-open");
|
||||||
|
if (panel.style.maxHeight) {
|
||||||
|
panel.style.maxHeight = null;
|
||||||
|
} else {
|
||||||
|
panel.style.maxHeight = panel.scrollHeight + "px";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -0,0 +1,91 @@
|
|||||||
|
<div class="np-homepage-featured np-homepage-featured-items np-max-width">
|
||||||
|
<div class="np-homepage-featured-text">
|
||||||
|
<div class="np-homepage-headline">
|
||||||
|
Recommended Gear
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="featured-photography-carousel np-carousel np-carousel-bg-blue" id="featured-photography-carousel">
|
||||||
|
<div class="np-carousel-card">
|
||||||
|
<div>
|
||||||
|
<img src=https://5prq858zcb-flywheel.netdna-ssl.com/wp-content/uploads/2016/12/50823_4WhiteBG-1-600x625.png" alt="Featured Photography" class='customer-carousel-image'/>
|
||||||
|
<div class="slide-label">Misty Mountain Cadillav Harness</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="np-carousel-card">
|
||||||
|
<div>
|
||||||
|
<img src="https://outdoorgearlab-mvnab3pwrvp3t0.stackpathdns.com/photos/18/97/311203_1848_XXXL.jpg" alt="Featured Photography" class='customer-carousel-image'/>
|
||||||
|
<div class="slide-label">Gri-Gri Belay Device</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="np-carousel-card">
|
||||||
|
<div>
|
||||||
|
<img src="https://lcdn.sportiva.com/pub/media/catalog/product/8/0/800_yellow_katanalace_1_7_4.jpg" alt="Featured Photography" class='customer-carousel-image'/>
|
||||||
|
<div class="slide-label">La Sportiva Katana Lace Shoes</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="np-carousel-card">
|
||||||
|
<div>
|
||||||
|
<img src="https://s3.amazonaws.com/static.northpass.com/demos/hsbc-old-logo.png" alt="Featured Photography" class='customer-carousel-image'/>
|
||||||
|
<div class="slide-label">Metolious Helmet</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="np-carousel-card">
|
||||||
|
<div>
|
||||||
|
<img src="https://s3.amazonaws.com/static.northpass.com/demos/sandia-labs-logo.jpg" alt="Featured Photography" class='customer-carousel-image'/>
|
||||||
|
<div class="slide-label">Unknown</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(document).ready(function(){
|
||||||
|
|
||||||
|
$("#featured-photography-carousel").slick({
|
||||||
|
slidesToShow: 3.5,
|
||||||
|
prevArrow: '<i class="fal fa-chevron-left"></i>',
|
||||||
|
nextArrow: '<i class="fal fa-chevron-right"></i>',
|
||||||
|
infinite: false,
|
||||||
|
responsive: [
|
||||||
|
{
|
||||||
|
breakpoint: 1350,
|
||||||
|
settings: {
|
||||||
|
slidesToShow: 2.3,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
breakpoint: 1024,
|
||||||
|
settings: {
|
||||||
|
slidesToShow: 2,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
breakpoint: 768,
|
||||||
|
settings: {
|
||||||
|
slidesToShow: 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.featured-photography-carousel .fa-chevron-right::before {
|
||||||
|
right: -6px !important;
|
||||||
|
}
|
||||||
|
.customer-carousel-image {
|
||||||
|
width: 292px;
|
||||||
|
height: 292px;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
.featured-photography-carousel .slick-initialized .slick-slide {
|
||||||
|
margin: 10px 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
{% include "header" %}
|
||||||
|
{% include "course_version_outdated_alert", courses: courses.in_catalog %}
|
||||||
|
<div class="np-homepage-hero">
|
||||||
|
<div class="np-homepage-hero-image">
|
||||||
|
</div>
|
||||||
|
<div class="np-homepage-hero-content">
|
||||||
|
<div class="np-homepage-headline np-header-font-color">
|
||||||
|
Menlo Security Resrouces
|
||||||
|
</div>
|
||||||
|
<div class="np-homepage-subheadline np-header-font-color">
|
||||||
|
Resources to help you make the most of your Security Training
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% include "sub_navigation" %}
|
||||||
|
{% include "courses_catalog" %}
|
||||||
|
</main>
|
||||||
|
{% include "footer" %}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.np-card-content-description {
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
.np-card-content-title {
|
||||||
|
height: 58px;
|
||||||
|
overflow: clip;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
window.onload = function() {
|
||||||
|
[].slice.call(document.getElementsByClassName("np-card-content-description")).forEach(function(element) {
|
||||||
|
if(element.innerText.length > 150){
|
||||||
|
element.innerText = element.innerText.slice(0,150) + '...'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
{% include 'header' %}
|
||||||
|
<main class="np-main np-homepage">
|
||||||
|
<div class="np-homepage-hero">
|
||||||
|
<h1 class="community-headline">Explore</h1>
|
||||||
|
</div>
|
||||||
|
{% include 'sub_navigation' %}
|
||||||
|
<div class='discussion-container' style="border: 18px solid rgb(0, 0, 0); overflow: hidden; margin-left: 100px; margin-top: 35px; width: 1065px;">
|
||||||
|
<iframe scrolling="yes" src="https://www.mountainproject.com/" style="border: 0px none; margin-left: 15px auto; height: 1954px; margin-top: -100px; width: 1060px;"></iframe>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
{% include 'footer' %}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.discussion-frame {
|
||||||
|
min-width: 100%;
|
||||||
|
margin-left: -10px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.discussion-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.community-headline {
|
||||||
|
font-size: 32px;
|
||||||
|
line-height: 48px;
|
||||||
|
font-family: "Raleway", "Helvetic", "Arial" sans-serif;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
13
app/templates/cmtest.html
Normal file
13
app/templates/cmtest.html
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
{% include 'head.html' %}
|
||||||
|
{% include 'header.html' %}
|
||||||
|
{% include 'logo.html' %}
|
||||||
|
<p> </p>
|
||||||
|
{% if error %}
|
||||||
|
<h3>{{ error }}</h4>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<form method="POST" action="/">
|
||||||
|
{{ form.name.label }} {{ form.name(size=20) }}
|
||||||
|
<input type="submit" value="Go">
|
||||||
|
</form>
|
||||||
@ -17,8 +17,8 @@
|
|||||||
<link rel="stylesheet" href="{{ url_for('static', filename="css/styles.css") }}" />
|
<link rel="stylesheet" href="{{ url_for('static', filename="css/styles.css") }}" />
|
||||||
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
|
||||||
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
|
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@1.2/code-input.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@1.2.2/code-input.min.js"></script>
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@1.2/code-input.min.css">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/WebCoder49/code-input@1.2.2/code-input.min.css">
|
||||||
<link href="{{ url_for('static', filename='css/prism.css')}}" rel="stylesheet" />
|
<link href="{{ url_for('static', filename='css/prism.css')}}" rel="stylesheet" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
<p>
|
<p>
|
||||||
</p>
|
</p>
|
||||||
<form action="{{ url_for("ask_key")}}" method="post">
|
<form action="{{ url_for("ask_key")}}" method="post">
|
||||||
<input id="fields" type="text" name="apikey">
|
<input id="fields" type="password" name="apikey">
|
||||||
<input id="fields" type="submit" value="Submit">
|
<input id="fields" type="submit" value="Submit">
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -6,6 +6,17 @@
|
|||||||
{% if error %}
|
{% if error %}
|
||||||
<h3>{{ error }}</h4>
|
<h3>{{ error }}</h4>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if button %}
|
||||||
|
<br>
|
||||||
|
<form
|
||||||
|
id="undo_template"
|
||||||
|
method="post"
|
||||||
|
action="{{ url_for('undo_template')}}">
|
||||||
|
<input type="submit" name="undo_template" value="Undo Last Upload"></input>
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if templates %}
|
{% if templates %}
|
||||||
<h2> Here are the liquid templates for </h2>
|
<h2> Here are the liquid templates for </h2>
|
||||||
<h2 style="color:#F05323"><strong> {{ session.school }} </strong></h2>
|
<h2 style="color:#F05323"><strong> {{ session.school }} </strong></h2>
|
||||||
@ -18,10 +29,9 @@
|
|||||||
id="templates"
|
id="templates"
|
||||||
action="{{ url_for('templates')}}"
|
action="{{ url_for('templates')}}"
|
||||||
method="post">
|
method="post">
|
||||||
<h2>
|
<h2> {{ templates[0] }}</h2>
|
||||||
{{ templates[0] }}
|
<h3> Last Updated: {{ templates [2] }}</h3>
|
||||||
</h2>
|
<code-input
|
||||||
<code-input
|
|
||||||
lang="HTML"
|
lang="HTML"
|
||||||
value="{{ templates[1] }}"
|
value="{{ templates[1] }}"
|
||||||
id="editor"
|
id="editor"
|
||||||
@ -29,10 +39,6 @@
|
|||||||
template="code-input">
|
template="code-input">
|
||||||
{{ templates[1] }}
|
{{ templates[1] }}
|
||||||
</code-input>
|
</code-input>
|
||||||
<textarea
|
|
||||||
name="loaded-content"
|
|
||||||
id="loaded-content"
|
|
||||||
style="width:100%;"></textarea>
|
|
||||||
<label for="template_name">
|
<label for="template_name">
|
||||||
Create New Template Name (optional):
|
Create New Template Name (optional):
|
||||||
</label>
|
</label>
|
||||||
@ -42,12 +48,6 @@
|
|||||||
value="{{ templates[0] }}">
|
value="{{ templates[0] }}">
|
||||||
</input>
|
</input>
|
||||||
<p> </p>
|
<p> </p>
|
||||||
<div
|
|
||||||
name="load-template"
|
|
||||||
value="Load Changes"
|
|
||||||
onclick="copyToTextArea()"
|
|
||||||
style="cursor:pointer"
|
|
||||||
>Click here to load changes</div>
|
|
||||||
<input
|
<input
|
||||||
type="submit"
|
type="submit"
|
||||||
name="submit-template"
|
name="submit-template"
|
||||||
@ -58,7 +58,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<p> </p>
|
<p> </p>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<!--
|
{% if templates %}
|
||||||
<h3> Advanced users only: create new template </h3>
|
<h3> Advanced users only: create new template </h3>
|
||||||
<p> </p>
|
<p> </p>
|
||||||
<div class="html_code">
|
<div class="html_code">
|
||||||
@ -69,12 +69,12 @@
|
|||||||
<h2>
|
<h2>
|
||||||
Enter the code below
|
Enter the code below
|
||||||
</h2>
|
</h2>
|
||||||
<textarea
|
<code-input
|
||||||
id="body"
|
lang="HTML"
|
||||||
name="body"
|
id="editor"
|
||||||
rows="35"
|
name="body"
|
||||||
cols="100">
|
template="code-input">
|
||||||
</textarea>
|
</code-input>
|
||||||
<p> </p>
|
<p> </p>
|
||||||
<label for="template_name">
|
<label for="template_name">
|
||||||
Template Name:
|
Template Name:
|
||||||
@ -86,7 +86,8 @@
|
|||||||
<p> </p>
|
<p> </p>
|
||||||
<input type="submit" name="submit_template" value="Submit Template"</input>
|
<input type="submit" name="submit_template" value="Submit Template"</input>
|
||||||
</form>
|
</form>
|
||||||
</div> -->
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
codeInput.registerTemplate("code-input", codeInput.templates.hljs(hljs,
|
codeInput.registerTemplate("code-input", codeInput.templates.hljs(hljs,
|
||||||
@ -96,13 +97,3 @@
|
|||||||
<script>
|
<script>
|
||||||
codeInput.registerTemplate("code-input", codeInput.templates.prism(Prism, []));
|
codeInput.registerTemplate("code-input", codeInput.templates.prism(Prism, []));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
|
||||||
function copyToTextArea() {
|
|
||||||
var code = document.getElementById("editor").value;
|
|
||||||
let textarea = document.getElementById("loaded-content");
|
|
||||||
textarea.textContent = code;
|
|
||||||
console.log(code);
|
|
||||||
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|||||||
Reference in New Issue
Block a user