Compare commits

...

3 Commits

Author SHA1 Message Date
e797876c16 Merge pull request 'Material Icons' (#17) from material into master
Reviewed-on: #17
2026-06-19 13:58:45 +10:00
1301d19c08 Switched to material icons 2026-06-16 09:18:21 +10:00
ca3effcad1 Fixed my music page 2026-05-29 22:47:33 +10:00
20 changed files with 182 additions and 102 deletions

View File

@ -11,7 +11,8 @@
<script src="{% static 'interface/js/interface.js' %}"></script>
<script src="//unpkg.com/alpinejs" defer></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js" defer></script>
<script src="//kit.fontawesome.com/c837098e5b.js" crossorigin="anonymous" defer></script>
<!-- script src="//kit.fontawesome.com/c837098e5b.js" crossorigin="anonymous" defer></script -->
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined" rel="stylesheet" />
<title>{% block title %}Polyphonic{% endblock %}</title>
{% block media %}{% endblock %}
<style>{% block style %}{% endblock %}</style>
@ -23,7 +24,7 @@
<nav class="navbar" role="navigation">
<div class="navbar-brand has-text-primary">
<a class="navbar-item" href="/">
<span class="icon fancy is-size-2 is-size-4-mobile mx-4"><i class="fas fa-random"></i></span>
<span class="icon fancy mx-4"><span class="material-symbols-outlined is-size-1 is-size-3-mobile">groups</span></span>
<span class="fancy is-size-2 is-size-4-mobile">Polyphonic</span>
</a>
<span class="navbar-item is-hidden-mobile fancy is-size-5">Musical Ensemble Manager</span>

View File

@ -6,7 +6,7 @@
{% crispy_field field 'class' 'file-input'%}
<span class="file-cta">
<span class="file-icon">
<i class="fas fa-upload"></i>
<span class="material-symbols-outlined">file_upload</span>
</span>
<span class="file-label">
Choose a file…

View File

@ -1,19 +1,20 @@
{% extends "interface/project_base.html" %}
{% load md2 %}
{% load polyphonic %}
{% block admin %}
<a href="{% url 'project_create' object.slug %}" class="button is-link">
<span class="icon"><i class="fas fa-plus-circle"></i></span>
{{ "add_notes"|icon }}
<span>Add project</span>
</a>
{% if inactive %}
<a href="?" class="button is-link">
<span class="icon"><i class="fas fa-archive"></i></span>
{{ "preview_off"|icon }}
<span>Hide old</span>
</a>
{% else %}
<a href="?inactive" class="button is-link">
<span class="icon"><i class="fas fa-archive"></i></span>
{{ "preview"|icon }}
<span>Show all</span>
</a>
{% endif %}

View File

@ -5,7 +5,7 @@
{% comment %}
<div class="admin-tools is-pulled-right">
<a class="button is-link" href="{% url 'register' %}">
<span class="icon"><i class="fas fa-plus-circle"></i></span>
{% icon "add_file" %}
<span>Register another</span>
</a>
</div>
@ -25,10 +25,13 @@
<img src="https://www.gravatar.com/avatar/{{ ensemble.email }}?d=mp" alt="Placeholder image">
</figure>
</div>
<div class="media-content" style="min-height: 60px">
<div class="media-content" style="min-height: 100px">
<a href="{% url 'ensemble_detail' ensemble.slug %}">
<p class="title is-4">{{ ensemble.name }}</p>
</a>
<div class="mt-3">
{{ ensemble.details|markdown }}
</div>
</div>
</div>
</div>

View File

@ -4,11 +4,11 @@
{% block admin %}
<a href="{% url 'wiki_create' project=project.pk %}" class="button is-link">
<span class="icon"><i class="fas fa-file"></i></span>
{{ "add_notes"|icon }}
<span>Add Page</span>
</a>
<a href="{% url 'project_edit' project=project.pk %}" class="button is-link">
<span class="icon"><i class="fas fa-edit"></i></span>
{{ "edit"|icon }}
<span>Edit</span>
</a>
{% endblock %}

View File

@ -1,9 +1,10 @@
{% extends "interface/project_base.html" %}
{% load md2 %}
{% load polyphonic %}
{% block admin %}
<a class="button is-link" href="{% url 'resource_create' project=project.pk %}">
<span class="icon"><i class="fas fa-plus-circle"></i></span>
{% icon "add_notes" %}
<span>Add new</span>
</a>
{% endblock %}
@ -27,11 +28,11 @@
<div class="card-header-icon">
{% if request.is_admin %}
<a href="{% url 'resource_upload' project=project.pk pk=resource.pk %}" class="icon" title="Upload">
<i class="fas fa-upload"></i>
<a href="{% url 'resource_upload' project=project.pk pk=resource.pk %}" title="Upload">
{% icon "upload_file" %}
</a>
<a href="{% url 'resource_edit' project=project.pk pk=resource.pk %}" class="icon" title="Edit">
<i class="fas fa-edit"></i>
<a href="{% url 'resource_edit' project=project.pk pk=resource.pk %}" title="Edit">
{% icon "edit" %}
</a>
{% endif %}
</div>

View File

@ -1,8 +1,9 @@
{% extends "interface/project_base.html" %}
{% load polyphonic %}
{% block admin %}
<a href="{% url 'wiki_edit' project=project.pk pk=wikipage.pk %}" class="button is-link">
<span class="icon"><i class="fas fa-edit"></i></span>
{{ "edit"|icon }}
<span>Edit</span>
</a>
{% endblock %}

View File

@ -1,9 +1,27 @@
from django import template
from django.utils import timesince
from django.utils.html import format_html
register = template.Library()
@register.filter("icon", is_safe=True)
def material_icon(value):
return f'<span class="icon"><span class="material-symbols-outlined">{value}</span></span>'
@register.simple_tag
def icon(name, element="span", classes=[]):
classes = ["icon"] + classes
return format_html(
'<{} class="{}"><span class="material-symbols-outlined">{}</span></{}>',
element,
" ".join(classes),
name,
element,
)
def roughtimesince(value):
return timesince.timesince(value, depth=1)

View File

@ -19,6 +19,10 @@ cb Double Bass
mall Mallet Percussion
vln Violin
vla Viola
kit Drumkit
asax Alto Sax
tsax Tenor Sax
bsax Bari Sax
acc Accordion
afl Alto flute

View File

@ -1,4 +1,5 @@
{% extends "interface/project_base.html" %}
{% load polyphonic %}
{% block page %}
<h3 class="title">Library collections for {% firstof request.user.first_name request.user.username %}</h3>
@ -10,7 +11,9 @@
<input class="input" name="q" type="text" placeholder="Find a work" value="{{ request.GET.filter }}"/>
</div>
<div class="control">
<a class="button" href="?"><i class="fas fa-times"></i></a>
<a class="button" href="?">
{% icon "close" %}
</a>
</div>
</div>
</form>
@ -47,4 +50,5 @@
<div>
<small>{{ ensemble.ensemble_code }}</small>
</div>
{% endblock %}

View File

@ -1,11 +1,13 @@
{% extends "interface/project_base.html" %}
{% load polyphonic %}
{% block admin %}
<a href="#" onclick="saveTags()" class="button is-link">
<span class="icon"><i class="fas fa-save"></i></span>
{% icon "save" %}
<span>Save</span>
</a>
<a href="{% url 'work_detail' collection=collection.pk pk=object.work_id %}" class="button is-link is-light">
{% icon "backspace" %}
<span>Cancel</span>
</a>
{% endblock %}
@ -76,7 +78,11 @@
</div>
<ul id="unassigned-area">
{% for tag, inst in document.work.music_tags %}
<li class="is-clickable" onclick="assignInstrument('{{tag}}', this)")>{{ inst }}</li>
<li>
<span class="is-clickable" onclick="assignInstrument('{{tag}}', this)")>{{ inst }}</span>
&nbsp;
<span class="is-clickable" onclick="addNumberedInstrument('{{tag}}', this)">...</span>
</li>
{% endfor %}
</ul>
<a onclick="document.getElementById('add-modal').classList.add('is-active')">Add Tag</a>
@ -276,6 +282,16 @@
document.getElementById('add-instrument-variant').value = "";
}
function addNumberedInstrument(tag, e) {
let modal = document.getElementById('add-modal');
document.getElementById("add-instrument-name").value = data.instruments[tag];
document.getElementById("add-instrument-variant").value = 1;
document.getElementById("add-instrument-variant").focus();
modal.classList.add('is-active');
}
function addInstrument() {
let name = document.getElementById('add-instrument-name');
let variant = document.getElementById('add-instrument-variant');
@ -326,7 +342,7 @@
let setStart = document.createElement('span');
setStart.className = "icon is-action";
setStart.innerHTML = '<i class="fas fa-sort-amount-down" title="Set start page"></i>';
setStart.innerHTML = '<span class="material-symbols-outlined" title="Set start page">vertical_align_top</span>';
setStart.addEventListener('click', () => setTagStart(el));
el.appendChild(setStart);
@ -336,22 +352,20 @@
let name = document.createElement('b');
name.innerHTML = get_instrument(tag);
label.appendChild(name);
el.appendChild(label);
let del = document.createElement('span');
del.className = "icon is-action";
del.innerHTML = '<i class="fas fa-trash-alt" title="Remove this tag"></i>';
del.innerHTML = '<span class="material-symbols-outlined" title="Remove this tag">delete</span>';
del.addEventListener('click', () => {
el.remove();
dirty=true;
});
label.appendChild(del)
el.appendChild(label);
el.appendChild(del)
let setEnd = document.createElement('span');
setEnd.className = "icon is-action";
setEnd.innerHTML = '<i class="fas fa-sort-amount-up" title="Set end page"></i>';
setEnd.innerHTML = '<span class="material-symbols-outlined" title="Set end page">vertical_align_bottom</span>';
setEnd.addEventListener('click', () => setTagEnd(el));
el.appendChild(setEnd);

View File

@ -1,7 +1,10 @@
{% load path_filters %}
{% load polyphonic %}
<tr>
<td><a href="{{ doc.upload.url }}" target="_blank">
{{ doc.upload.name|basename }}</a></td>
<td style="white-space: nowrap">
<a href="{{ doc.upload.url }}" target="_blank">
{{ doc.upload.name|basename }}</a>
</td>
<td>
{% for section in doc.sections.all %}
<a class="tag is-{{ section.bulma_class }}" target="_blank" href="{% url 'part_download' collection.pk section.pk section.filename %}">{{ section.name }}</a>
@ -10,10 +13,13 @@
<td class="has-text-right" style="white-space: nowrap;">
{% if request.is_admin %}
{% if doc.doctype == 1 %}
<a href="{% url 'document_annotate' collection.pk doc.pk %}"><i class="fas fa-tags"
title="Manage Tags"></i></a>
<a href="{% url 'document_annotate' collection.pk doc.pk %}" title="Annotate">
{% icon "toc" %}
</a>
{% endif %}
<a href="{% url 'document_delete' collection.pk doc.pk %}"><i class="fas fa-trash-alt" title="Delete Document"></i></a>
<a href="{% url 'document_delete' collection.pk doc.pk %}" title="Delete">
{% icon "delete" %}
</a>
{% endif %}
</td>
</tr>

View File

@ -1,12 +1,18 @@
{% extends "interface/project_base.html" %}
{% load polyphonic %}
{% block admin %}
<a href="{% url 'work_detail' collection=collection.pk pk=object.pk %}" class="button is-link is-light">
{% icon "backspace" %}
<span>Back to work</span>
</a>
{% endblock %}
{% block page %}
<h2 class="title">
{% icon "add_to_drive" %}
<span>Google Drive - Shared Links
</h2>
<h3 class="subtitle"><a href="{% url 'work_detail' collection.pk object.pk %}">{{ object.name }}</a></h3>
<div class="m-3">
<p>This page lets you link a work to a google drive folder. You can either paste a public link to a folder to enable syncing or a file to add individually</p>
@ -14,25 +20,23 @@
<div class="m-3">
<p>
{% if meta.folderid %}
This work is currently linked to <b>{{ meta.folderid }}</b>. Pasting a new folder link will overwrite this.
This work is currently linked to <b>{{ meta.folderid }}</b>.<br/>
Pasting a new folder link will overwrite this.
{% else %}
There is currently no shared drive folder linked to this work - paste one here to enable syncing.
{% endif %}
</p>
</div>
<div>
<div class="mt-5">
<form method="post">
<div class="field">
<div class="control">
<input name="link" class="input is-expanded" type="text" placeholder="Shared link">
<div class="field has-addons mx-6">
<div class="control is-expanded">
<input class="input" name="link" type="text" placeholder="Paste shared link">
</div>
{% for error in form.errors.link %}
<p class="help is-danger">{{ error }}</p>
{% endfor %}
</div>
<div class="field">
<div class="control">
<button class="button is-info" type="submit">Add</button>
<button class="button" type="submit">
Add
</button>
</div>
</div>
{% csrf_token %}

View File

@ -1,4 +1,5 @@
{% extends "interface/project_base.html" %}
{% load polyphonic %}
{% block page %}
<form action="" method="post" target="_blank">
@ -31,12 +32,6 @@
</span>
</span>
</div>
<span class="control">
<button type="submit" class="button is-primary">
<span class="icon"><i class="fas fa-copy"></i></span>
<span>Get My Parts!</span>
</button>
</span>
</div>
</div>
@ -45,6 +40,7 @@
<tr>
<th/>
<th>Piece</th>
<th>Composer</th>
<th class="is-hidden-mobile">Running time</th>
<th>Part</th>
<th/>
@ -61,6 +57,7 @@
{{ item.work.name }}
{% endif %}
</td>
<td class="is-hidden-mobile">{{ item.work.composer }}</td>
<td class="is-hidden-mobile">{% firstof item.work.running_time "------" %}</td>
<td class="select-cell">
<input type="hidden" name="works" value="{{ item.work.pk }}"/>
@ -74,8 +71,9 @@
</span>
</td>
<td>
<span class="is-action" onclick="downloadPart({{ item.work.collection_id }}, {{ item.work.pk }})">
<i class="fas fa-download" title="Download Part"></i>
<span class="button is-link is-small" onclick="downloadPart({{ item.work.collection_id }}, {{ item.work.pk }})">
{% icon "download" %}
<span>Get</span>
</span>
</td>
</tr>
@ -85,13 +83,17 @@
<tr>
<td/>
<td/>
<td>{% firstof running_time "------" %}</td>
<td/>
<td>
<!--
<button class="button is-link is-small" type="submit"><span class="icon"><i class="fas fa-copy"></i></span><span>Single combined PDF</span></button>
<a class="button is-link is-small"><span class="icon"><i class="fas fa-archive"></i></span><span>Individual files (zipped)</span></a>
-->
<td>{% firstof running_time "------" %}</td>
<td colspan="2">
<button class="button is-link is-small" type="submit" name="action" value="pdf">
{% icon "two_pager" %}
<span>&nbsp;Single combined PDF</span>
</button>
<button class="button is-link is-small" type="submit" name="action" value="zip">
{% icon "folder_zip" %}
<span>&nbsp;Individual files (zipped)</span>
</button>
</td>
</tr>
</tfoot>

View File

@ -1,12 +1,13 @@
{% extends "interface/project_base.html" %}
{% load polyphonic %}
{% block admin %}
<a href="{% url 'item_list_append' project.pk %}" class="button is-link">
<span class="icon"><i class="fas fa-plus-circle"></i></span>
{% icon "add_circle" %}
<span>Add</span>
</a>
<a href="#" onclick="save()" class="button is-link">
<span class="icon"><i class="fas fa-save"></i></span>
{% icon "save" %}
<span>Save</span>
</a>
{% endblock %}
@ -26,9 +27,15 @@
<td>{{ item.work.name }}</td>
<td>{{ item.work.duration }}</td>
<td style="text-align: center;">
<i class="fas fa-arrow-up clickable" title="Move up" onclick="moveItem({{ item.pk }}, -1)"></i>
<i class="fas fa-arrow-down clickable" title="Move down" onclick="moveItem({{ item.pk }}, 1)"></i>
<i class="fas fa-trash clickable" title="Remove" onClick="moveItem({{ item.pk }}, 0)"></i>
<span class="clickable" title="Move up" onclick="moveItem({{ item.pk }}, -1)">
{% icon "arrow_upward" %}
</span>
<span class="clickable" title="Move down" onclick="moveItem({{ item.pk }}, 1)">
{% icon "arrow_downward" %}
</span>
<span class="clickable" title="Remove" onClick="moveItem({{ item.pk }}, 0)">
{% icon "delete" %}
</span>
</td>
</tr>

View File

@ -1,5 +1,6 @@
{% extends 'interface/project_base.html' %}
{% load path_filters %}
{% load polyphonic %}
{% block media %}
<script src="https://unpkg.com/dropzone@5/dist/min/dropzone.min.js"></script>
@ -8,11 +9,11 @@
{% block admin %}
<a href="{% url 'work_edit' collection.pk work.pk %}" class="button is-link">
<span class="icon"><i class="fas fa-edit"></i></span>
{% icon "edit" %}
<span>Edit</span>
</a>
<a href="{% url 'work_add_to_project' collection.pk work.pk %}" class="button is-link">
<span class="icon"><i class="fas fa-plus-circle"></i></span>
{% icon "add_ad" %}
<span>Add to project</span>
</a>
{% endblock %}
@ -68,8 +69,8 @@
<div class="column is-half">
<div class="box">
<h4 class="subtitle is-size-4">
<span class="icon"><i class="fas fa-book"></i></span>
Printed Parts
{% icon "menu_book" %}
<span>Printed Parts</span>
</h4>
<div class="tags">
{% for inst, c in work.physical_parts %}
@ -81,8 +82,8 @@
</div>
<div class="box">
<h4 class="subtitle is-size-4">
<span class="icon"><i class="fas fa-print"></i></span>
Digital Parts
{% icon "file_copy" %}
<span>Digital Parts</span>
</h4>
<div class="tags">
{% with sections=work.digital_parts %}
@ -105,8 +106,8 @@
<div class="box">
<div class="level">
<h4 class="subtitle is-size-4">
<span class="icon"><i class="fas fa-file"></i></span>
Files
{% icon "file_present" %}
<span>Files<span>
</h4>
</div>
<div class="columns">
@ -136,9 +137,9 @@
{% endif %}
{% if "gdrive" in methods %}
<div class="has-text-centered mt-3">
<a class="button button-primary is-size-7" href="{% url 'work_gdrive' collection.pk object.pk %}">
<span class="icon"><i class="fa-brands fa-google-drive"></i></span>
Link Google Drive Files
<a class="button button-is-primary is-size-7" href="{% url 'work_gdrive' collection.pk object.pk %}">
{% icon "add_to_drive" %}
<span>Google Drive</span>
</a><br/>
</div>
{% endif %}
@ -152,12 +153,14 @@
<div class="box">
<div class="level">
<h4 class="is-size-4">
<span class="icon"><i class="fas fa-book-reader"></i></span>
Loans
{{ "folder_open"| icon }}
Projects
</h4>
<span class="level-right">
<a class="icon-text" href="{% url 'work_add_to_project' collection.pk work.pk %}"><span class="icon"><i
class="fas fa-plus-circle"></i></span> Checkout</a>
<a class="icon-text" href="{% url 'work_add_to_project' collection.pk work.pk %}">
{% icon "shopping_cart_checkout" %}
<span>Checkout</span>
</a>
</span>
</div>
<table class="table is-fullwidth">
@ -181,7 +184,7 @@
</tr>
{% empty %}
<tr>
<td>No current loans</td>
<td>No current assignments</td>
</tr>
{% endfor %}
</tbody>

View File

@ -1,10 +1,11 @@
{% extends "interface/project_base.html" %}
{% load url_tools %}
{% load polyphonic %}
{% block admin %}
{% if collection %}
<a href="{% url 'work_add' collection.pk %}" class="button is-link">
<span class="icon"><i class="fas fa-plus-circle"></i></span>
{% icon "add_notes" %}
<span>Add a work</span>
</a>
{% endif %}
@ -18,7 +19,9 @@
<input class="input" name="q" type="text" placeholder="Filter" value="{{ request.GET.q }}"/>
</div>
<div class="control">
<a class="button" href="?"><i class="fas fa-times"></i></a>
<a class="button" href="?">
{% icon "close" %}
</a>
</div>
</div>
</form>
@ -65,6 +68,7 @@
{% else %}
disabled
{% endif %}>
{% icon "arrow_back" %}
Previous</a>
<a class="pagination-next"
{% if page_obj.has_next %}
@ -73,6 +77,7 @@
disabled
{% endif %}>
Next
{% icon "arrow_forward" %}
</a>
<ul class="pagination-list">
{% for page in page_range %}

View File

@ -1,4 +1,5 @@
{% extends "interface/project_base.html" %}
{% load polyphonic %}
@ -35,12 +36,13 @@
<div class="field is-grouped">
<div class="control">
<button class="button is-link">
<span class="icon"><i class="fas fa-print"></i></span>
{% icon "print" %}
<span>Print Set</span>
</button>
</div>
<div class="control">
<a class="button is-link is-light" href="{% url 'work_detail' collection.pk object.pk %}">
{% icon "backspace" %}
<span>Cancel</span>
</a>
</div>

View File

@ -38,7 +38,8 @@ class ProjectItemListView(ProjectMixin, ListView):
project_works = self.project.works.all()
instruments = request.POST.getlist("instruments")
print(request.POST)
instruments = request.POST.getlist("instrument-selection")
works = request.POST.getlist("works")
request.session["part"] = request.POST.get("part", "")
@ -65,14 +66,17 @@ class ProjectItemListView(ProjectMixin, ListView):
(part.doc.upload.path, part.doc.work.name, part.start, part.end, 1)
)
action = request.POST.get("action")
if action == "pdf":
result = extract_and_concat(sections)
download_name = f"{self.project.name}.pdf"
response = FileResponse(result, content_type="application/pdf")
response["Content-Disposition"] = f'inline; filename="{download_name}"'
return response
return HttpResponse(f"Unknown action: {action}", status=400)
def get_queryset(self):
return (
super(ProjectItemListView, self)