Skip to content

Commit d179561

Browse files
authored
Merge pull request #536 from KSP-SpaceDock/alpha
Merge dark mode Alpha into Beta
2 parents 9ba19c5 + 4919f04 commit d179561

17 files changed

Lines changed: 810 additions & 51 deletions

File tree

KerbalStuff/blueprints/admin.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,22 @@ def profiling(page: int) -> Union[str, werkzeug.wrappers.Response]:
3636
if page < 1:
3737
return redirect(url_for('admin.profiling', page=1, **request.args))
3838
prof_dir = _cfg('profile-dir')
39-
profilings = [] if not prof_dir else list(map(
40-
parse_prof_filename,
41-
sorted(Path(prof_dir).glob('*.prof'),
42-
key=lambda p: -p.stat().st_mtime)))
39+
# this directory can hold a huge number of profile files, so do as little
40+
# per file as possible sort on the timestamp that's already in the
41+
# filename (no stat() per file) and on ly parse the page we actually show.
42+
# The old code stat()'d and parsed every file on every load which made
43+
# opening the admin panel hang and tie up workers
44+
files = sorted(Path(prof_dir).glob('*.prof'),
45+
key=lambda p: p.name.split('.')[-2],
46+
reverse=True) if prof_dir else []
4347
query = request.args.get('query', type=str)
4448
if query:
4549
terms = query.split(' ')
46-
profilings = [p for p in profilings
47-
if all(map(lambda t: query_term_matches(t, p), terms))]
48-
total_pages = max(1, math.ceil(len(profilings) / ITEMS_PER_PAGE))
49-
profilings = profilings[(page - 1) * ITEMS_PER_PAGE : page * ITEMS_PER_PAGE]
50+
files = [f for f in files
51+
if all(query_term_matches(t, parse_prof_filename(f)) for t in terms)]
52+
total_pages = max(1, math.ceil(len(files) / ITEMS_PER_PAGE))
53+
page_files = files[(page - 1) * ITEMS_PER_PAGE : page * ITEMS_PER_PAGE]
54+
profilings = [parse_prof_filename(f) for f in page_files]
5055
return render_template("admin-profiling.html",
5156
profilings=profilings, query=query,
5257
page=page, total_pages=total_pages)

KerbalStuff/objects.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,8 @@ class ModListItem(Base): # type: ignore
367367
mod = relationship('Mod', backref=backref('mod_list_items', passive_deletes=True))
368368
mod_list_id = Column(Integer, ForeignKey('modlist.id', ondelete='CASCADE'), nullable=False)
369369
mod_list = relationship('ModList',
370-
backref=backref('mods', passive_deletes=True, order_by="asc(ModListItem.sort_index)"))
370+
backref=backref('mods', passive_deletes=True, cascade="all, delete-orphan",
371+
order_by="asc(ModListItem.sort_index)"))
371372
sort_index = Column(Integer, default=0, nullable=False)
372373

373374
def __repr__(self) -> str:

frontend/coffee/global.coffee

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,42 @@ $('#alert-error').on 'close.bs.alert', () ->
6363
$('#alert-error').addClass 'hidden'
6464
return false
6565

66+
# Dark mode an explicit toggle choice is saved in localStorage (and applied
67+
# early in layout.html) with no saved choice we follow the OS theme
68+
darkModeToggle = document.getElementById('dark-mode-toggle')
69+
if darkModeToggle?
70+
root = document.documentElement
71+
updateDarkModeButton = () ->
72+
active = root.classList.contains('dark-mode')
73+
darkModeToggle.setAttribute('aria-pressed', active.toString())
74+
updateDarkModeButton()
75+
darkModeToggle.addEventListener('click', (e) ->
76+
e.preventDefault()
77+
active = root.classList.toggle('dark-mode')
78+
try
79+
localStorage.setItem('dark-mode', active.toString())
80+
catch error
81+
# localStorage can be blocked (private mode)
82+
updateDarkModeButton()
83+
, false)
84+
85+
# Follow the OS theme live but only until the user makes an explicit choice
86+
if window.matchMedia?
87+
mq = window.matchMedia('(prefers-color-scheme: dark)')
88+
applySystemTheme = (e) ->
89+
explicit = false
90+
try
91+
explicit = localStorage.getItem('dark-mode') isnt null
92+
catch error
93+
explicit = false
94+
unless explicit
95+
root.classList.toggle('dark-mode', e.matches)
96+
updateDarkModeButton()
97+
if mq.addEventListener?
98+
mq.addEventListener('change', applySystemTheme)
99+
else if mq.addListener?
100+
mq.addListener(applySystemTheme)
101+
66102
$('.search-tips-button').on 'click', (e) ->
67103
$('.search-tips').addClass 'search-tips-visible'
68104

frontend/static/css/bootstrap-theme.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
}
5454

5555
html body {
56-
font: 4mm "glacial_indifferenceregular";
56+
font: 4mm "glacial_indifferenceregular", "Helvetica Neue", Helvetica, Arial, sans-serif;
5757
color: #333333;
5858
}
5959

@@ -879,7 +879,7 @@ div.header .vert-text {
879879
}
880880

881881
div.tab-container {
882-
margin: 2.5mm;
882+
margin: 9px 0;
883883

884884
}
885885

frontend/styles/create.scss

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,40 @@
7373
}
7474
}
7575
}
76+
77+
.chosen-container.chosen-container-single .chosen-single {
78+
height: 34px;
79+
line-height: 34px;
80+
padding: 0 12px;
81+
border-radius: 0;
82+
box-shadow: none;
83+
84+
span {
85+
line-height: 34px;
86+
}
87+
88+
div {
89+
height: 34px;
90+
91+
b {
92+
background-position: 0 11px;
93+
}
94+
}
95+
}
96+
.chosen-container.chosen-container-active.chosen-with-drop .chosen-single {
97+
border-radius: 0;
98+
}
99+
.chosen-container.chosen-container-single .chosen-drop {
100+
border-radius: 0;
101+
}
102+
103+
.notification {
104+
font-weight: normal;
105+
106+
input[type="checkbox"] {
107+
margin-right: 8px;
108+
}
109+
.glyphicon {
110+
margin-left: 8px;
111+
}
112+
}

0 commit comments

Comments
 (0)