Compare commits
20 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
a0cfe48862 | ||
|
07a741f454 | ||
|
342ad493d1 | ||
|
1f573ead23 | ||
|
d51a63ff55 | ||
|
baf2c983d4 | ||
|
f7d10f2ec4 | ||
|
fa4ee3faae | ||
|
c8c4ba6221 | ||
|
fcc790ffd7 | ||
|
ce69142949 | ||
|
f72b6694c8 | ||
|
50bad00c90 | ||
|
e8f554c576 | ||
|
c81a26eebb | ||
|
1100460530 | ||
|
3d01b9d6b4 | ||
|
df5682f0c2 | ||
|
8f51170cc1 | ||
|
0ce854bb02 |
@ -440,19 +440,31 @@ class Poobrain(flask.Flask):
|
|||||||
peewee.DoesNotExist: 404
|
peewee.DoesNotExist: 404
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setup_funcs = None
|
||||||
cronjobs = None
|
cronjobs = None
|
||||||
|
|
||||||
|
_setup_done = False
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
|
||||||
if not 'root_path' in kwargs:
|
if not 'root_path' in kwargs:
|
||||||
kwargs['root_path'] = str(pathlib.Path('.').absolute()) #TODO: pathlib probably isn't really needed here
|
kwargs['root_path'] = str(pathlib.Path('.').absolute()) #TODO: pathlib probably isn't really needed here
|
||||||
|
|
||||||
|
if 'DEBUG' in dir(config) and config.DEBUG:
|
||||||
|
# There's some shitty overriding going on based on FLASK_ENV.
|
||||||
|
# Set the env var to override the override and enforce what
|
||||||
|
# the config says.
|
||||||
|
os.environ['FLASK_ENV'] = 'development'
|
||||||
|
else:
|
||||||
|
os.environ['FLASK_ENV'] = 'production'
|
||||||
|
|
||||||
super(Poobrain, self).__init__(*args, **kwargs)
|
super(Poobrain, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
self.setup_funcs = []
|
||||||
self.cronjobs = []
|
self.cronjobs = []
|
||||||
|
|
||||||
@click.group(cls=flask.cli.FlaskGroup, create_app=lambda x: self)
|
@click.group(cls=flask.cli.FlaskGroup, create_app=lambda x=None: self)
|
||||||
@click.option('--database', default=f"sqlite:///{project_name}.db")
|
@click.option('--database', default=f"sqlite:///{project_name}.db")
|
||||||
def cli(database):
|
def cli(database):
|
||||||
self.db = db_url.connect(database)
|
self.db = db_url.connect(database)
|
||||||
@ -537,6 +549,14 @@ class Poobrain(flask.Flask):
|
|||||||
self.admin = Pooprint('admin', 'admin')
|
self.admin = Pooprint('admin', 'admin')
|
||||||
|
|
||||||
|
|
||||||
|
def full_dispatch_request(self):
|
||||||
|
|
||||||
|
if not self._setup_done:
|
||||||
|
self.run_setup()
|
||||||
|
|
||||||
|
return super().full_dispatch_request()
|
||||||
|
|
||||||
|
|
||||||
def main(self):
|
def main(self):
|
||||||
#self.cli(obj={})
|
#self.cli(obj={})
|
||||||
self.cli()
|
self.cli()
|
||||||
@ -546,18 +566,28 @@ class Poobrain(flask.Flask):
|
|||||||
return True # autoescape everything
|
return True # autoescape everything
|
||||||
|
|
||||||
|
|
||||||
def try_trigger_before_first_request_functions(self):
|
def setup(self, f):
|
||||||
|
|
||||||
if not self.setup in self.before_first_request_funcs:
|
self.setup_funcs.append(f)
|
||||||
self.before_first_request_funcs.append(self.setup)
|
|
||||||
super(Poobrain, self).try_trigger_before_first_request_functions()
|
|
||||||
|
|
||||||
|
return f
|
||||||
|
|
||||||
def setup(self):
|
def run_setup(self):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Global runtime setup. Calls all @app.setup decorated functions
|
||||||
|
and registers site and admin blueprints.
|
||||||
|
Called by request_setup on first request.
|
||||||
|
"""
|
||||||
|
|
||||||
|
for f in self.setup_funcs:
|
||||||
|
f()
|
||||||
|
|
||||||
self.register_blueprint(self.site)
|
self.register_blueprint(self.site)
|
||||||
self.register_blueprint(self.admin, url_prefix='/admin/')
|
self.register_blueprint(self.admin, url_prefix='/admin/')
|
||||||
|
|
||||||
|
self._setup_done = True
|
||||||
|
|
||||||
|
|
||||||
@locked_cached_property
|
@locked_cached_property
|
||||||
def theme_paths(self):
|
def theme_paths(self):
|
||||||
@ -612,7 +642,6 @@ class Poobrain(flask.Flask):
|
|||||||
except jinja2.exceptions.TemplateNotFound:
|
except jinja2.exceptions.TemplateNotFound:
|
||||||
abort(404)
|
abort(404)
|
||||||
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
||||||
paths = [os.path.join(path, resource) for path in app.theme_paths]
|
paths = [os.path.join(path, resource) for path in app.theme_paths]
|
||||||
@ -765,7 +794,7 @@ class Poobrain(flask.Flask):
|
|||||||
except LookupError:
|
except LookupError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
raise LookupError("Failed generating URL for {cls.__name__}[{url_params.get('handle', None)}]-{mode}. No matching route found.")
|
raise LookupError(f"Failed generating URL for {cls.__name__}[{url_params.get('handle', None)}]-{mode}. No matching route found.")
|
||||||
|
|
||||||
def get_related_view_url(self, cls, handle, related_field, add=None):
|
def get_related_view_url(self, cls, handle, related_field, add=None):
|
||||||
|
|
||||||
|
@ -576,6 +576,8 @@ class Dataset(EphemeralDataset, poobrains.commenting.Commentable):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
||||||
|
database = app.db
|
||||||
|
|
||||||
modes = collections.OrderedDict([
|
modes = collections.OrderedDict([
|
||||||
('add', 'create'),
|
('add', 'create'),
|
||||||
('teaser', 'read'),
|
('teaser', 'read'),
|
||||||
|
@ -77,12 +77,15 @@ class FileFieldset(poobrains.formapp.MultistateFieldset):
|
|||||||
|
|
||||||
self['file'] = poobrains.form.fields.File()
|
self['file'] = poobrains.form.fields.File()
|
||||||
|
|
||||||
self['consumer'] = poobrains.form.fields.Select(choices=(
|
self['consumer'] = poobrains.form.fields.Select(choices=(
|
||||||
('csv', "CSV"),
|
('csv', "CSV"),
|
||||||
('geojson', "geojson"),
|
('geojson', "geojson"),
|
||||||
))
|
))
|
||||||
|
|
||||||
elif self.state == 'csv':
|
if self.state == 'csv':
|
||||||
|
|
||||||
|
self['consumer'].value = 'csv'
|
||||||
|
self['consumer'].readonly = True
|
||||||
|
|
||||||
csv_options = self.session['csv_options']
|
csv_options = self.session['csv_options']
|
||||||
|
|
||||||
@ -102,13 +105,14 @@ class FileFieldset(poobrains.formapp.MultistateFieldset):
|
|||||||
flash(f"Full error message: {e}", 'error')
|
flash(f"Full error message: {e}", 'error')
|
||||||
else:
|
else:
|
||||||
|
|
||||||
|
self.session['csv_options'] = csv_options
|
||||||
table = poobrains.rendering.Table(title='CSV preview')
|
table = poobrains.rendering.Table(title='CSV preview')
|
||||||
for idx, row in enumerate(reader):
|
for idx, row in enumerate(reader):
|
||||||
if idx == 5:
|
if idx == 5:
|
||||||
break
|
break
|
||||||
table.append(*row)
|
table.append(*row)
|
||||||
|
|
||||||
self['table'] = poobrains.form.fields.RenderableWrapper(value=table)
|
self['table'] = poobrains.form.fields.RenderableWrapper(table)
|
||||||
self.approve = poobrains.form.Button('submit', label='Approve')
|
self.approve = poobrains.form.Button('submit', label='Approve')
|
||||||
|
|
||||||
escaped = {}
|
escaped = {}
|
||||||
@ -134,21 +138,46 @@ class FileFieldset(poobrains.formapp.MultistateFieldset):
|
|||||||
|
|
||||||
def process(self, submit):
|
def process(self, submit):
|
||||||
|
|
||||||
if submit == 'change_csv_options':
|
if self.state == 'csv':
|
||||||
unescape = lambda x: bytes(x, 'utf-8').decode('unicode_escape')
|
if submit == 'change_csv_options':
|
||||||
self.session['csv_options'] = {
|
unescape = lambda x: bytes(x, 'utf-8').decode('unicode_escape')
|
||||||
'delimiter': unescape(self['delimiter'].value),
|
self.session['csv_options'] = {
|
||||||
'doublequote': self['doublequote'].value,
|
'delimiter': unescape(self['delimiter'].value or ''),
|
||||||
'escapechar': unescape(self['escapechar'].value),
|
'doublequote': self['doublequote'].value,
|
||||||
'lineterminator': unescape(self['lineterminator'].value),
|
'escapechar': unescape(self['escapechar'].value or ''),
|
||||||
'quotechar': unescape(self['quotechar'].value),
|
'lineterminator': unescape(self['lineterminator'].value),
|
||||||
'quoting': self['quoting'].value,
|
'quotechar': unescape(self['quotechar'].value or ''),
|
||||||
'skipinitialspace': self['skipinitialspace'].value,
|
'quoting': self['quoting'].value,
|
||||||
}
|
'skipinitialspace': self['skipinitialspace'].value,
|
||||||
|
}
|
||||||
|
|
||||||
flash("Changed CSV dialect options.")
|
flash("Changed CSV dialect options.")
|
||||||
|
else:
|
||||||
|
dialect = dialect_from_dict(self.session['csv_options'])
|
||||||
|
|
||||||
else: # means parent form wasn't submitting via cancel button – i.e. the "load" button was clicked
|
try:
|
||||||
|
reader = csv.reader(io.StringIO(self.session['raw']), dialect)
|
||||||
|
except csv.Error as e:
|
||||||
|
flash("Can't read file as CSV with supplied options.", 'error')
|
||||||
|
if app.debug:
|
||||||
|
flash(f"Full error message: {e}", 'error')
|
||||||
|
|
||||||
|
ds = self.owner()
|
||||||
|
ds['csv_col_fixme'] = {
|
||||||
|
'title': "CSV Column",
|
||||||
|
'description': 'FIXME: CSV has no type recognition, everything is float64',
|
||||||
|
'dtype': 'float64',
|
||||||
|
'color': None,
|
||||||
|
'observations': {}
|
||||||
|
}
|
||||||
|
|
||||||
|
for idx, row in enumerate(reader):
|
||||||
|
ds['csv_col_fixme']['observations'][idx] = util.float64.string_numpy(row[0]);
|
||||||
|
|
||||||
|
self.parent.session['other'] = ds.to_dict(whole=True)
|
||||||
|
self.parent.state = 'merge'
|
||||||
|
|
||||||
|
else: # submitted via load button with file upload
|
||||||
|
|
||||||
consumer = self['consumer'].value
|
consumer = self['consumer'].value
|
||||||
raw = self['file'].value.read()
|
raw = self['file'].value.read()
|
||||||
@ -184,7 +213,7 @@ class FileFieldset(poobrains.formapp.MultistateFieldset):
|
|||||||
|
|
||||||
elif consumer == 'csv':
|
elif consumer == 'csv':
|
||||||
self.state = 'csv'
|
self.state = 'csv'
|
||||||
self.session['data_action_info']['csv_options'] = None
|
self.session['csv_options'] = None
|
||||||
|
|
||||||
else:
|
else:
|
||||||
flash("Unhandled", 'error')
|
flash("Unhandled", 'error')
|
||||||
|
@ -39,7 +39,7 @@ def enforce_tls():
|
|||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
@app.before_first_request
|
@app.setup
|
||||||
def admin_setup():
|
def admin_setup():
|
||||||
|
|
||||||
if not app._got_first_request:
|
if not app._got_first_request:
|
||||||
|
@ -331,18 +331,13 @@ def add(storable):
|
|||||||
|
|
||||||
default = None
|
default = None
|
||||||
|
|
||||||
if field.default:
|
if callable(field.default):
|
||||||
|
default = field.default()
|
||||||
|
else:
|
||||||
|
default = field.default
|
||||||
|
|
||||||
if callable(field.default):
|
if field.null and default is None:
|
||||||
default = field.default()
|
default = '' # None interpreted as no default, '' treated as no value
|
||||||
else:
|
|
||||||
default = field.default
|
|
||||||
|
|
||||||
elif field.type == types.DATETIME:
|
|
||||||
default = datetime.datetime.now()
|
|
||||||
|
|
||||||
elif field.type == types.BOOL:
|
|
||||||
default = False
|
|
||||||
|
|
||||||
value = click.prompt(field.name, type=field.type, default=default)
|
value = click.prompt(field.name, type=field.type, default=default)
|
||||||
|
|
||||||
|
@ -321,7 +321,7 @@ class BaseField(object, metaclass=poobrains.helpers.MetaCompatibility):
|
|||||||
return 'true' if value == True else 'false'
|
return 'true' if value == True else 'false'
|
||||||
|
|
||||||
elif isinstance(value, datetime.datetime):
|
elif isinstance(value, datetime.datetime):
|
||||||
return value.strftime('%Y-%m-%d %H:%M:%S')
|
return value.strftime('%Y-%m-%dT%H:%M:%S')
|
||||||
|
|
||||||
elif inspect.isclass(value):
|
elif inspect.isclass(value):
|
||||||
return value.__name__
|
return value.__name__
|
||||||
@ -545,3 +545,8 @@ class File(Field):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
|
def bind(self, value):
|
||||||
|
# simple passthrough because this is filled with object(s) from
|
||||||
|
# request.files and shouldn't be converted to a string.
|
||||||
|
self.value = value
|
||||||
|
@ -49,7 +49,7 @@ class DateTimeParamType(ParamType):
|
|||||||
return value # apparently we need this function to be idempotent.
|
return value # apparently we need this function to be idempotent.
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return datetime.datetime.strptime(value, '%Y-%m-%d %H:%M:%S')
|
return datetime.datetime.strptime(value, '%Y-%m-%dT%H:%M:%S')
|
||||||
|
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ class DateTimeParamType(ParamType):
|
|||||||
else:
|
else:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return datetime.datetime.strptime(value, '%Y-%m-%d %H:%M:%S.%f')
|
return datetime.datetime.strptime(value, '%Y-%m-%dT%H:%M:%S.%f')
|
||||||
|
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
|
|
||||||
@ -71,7 +71,7 @@ class DateTimeParamType(ParamType):
|
|||||||
self.fail("We dun goof'd, this field isn't working.")
|
self.fail("We dun goof'd, this field isn't working.")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.fail(f"'{value}' is not a valid datetime. Expected format '%Y-%m-%d %H:%M:%S' or '%Y-%m-%d %H:%M:%S.%f'")
|
self.fail(f"'{value}' is not a valid datetime. Expected format '%Y-%m-%dT%H:%M:%S' or '%Y-%m-%dT%H:%M:%S.%f'")
|
||||||
|
|
||||||
DATETIME = DateTimeParamType()
|
DATETIME = DateTimeParamType()
|
||||||
|
|
||||||
|
@ -263,7 +263,7 @@ def pretty_bytes(bytecount):
|
|||||||
|
|
||||||
value /= 1024.0
|
value /= 1024.0
|
||||||
|
|
||||||
return "{value:.2f} {unit}"
|
return f"{value:.2f} {unit}"
|
||||||
|
|
||||||
|
|
||||||
def levenshtein_distance(s1, s2):
|
def levenshtein_distance(s1, s2):
|
||||||
@ -329,6 +329,7 @@ class FakeMetaOptions(object):
|
|||||||
modes = None
|
modes = None
|
||||||
permission_class = None
|
permission_class = None
|
||||||
schema = None # needed by peewee.ModelBase.__new__
|
schema = None # needed by peewee.ModelBase.__new__
|
||||||
|
database = None # needed py peewee.ModelBase.__new__ at least from 3.15.0 on
|
||||||
_additional_keys = None # needed by peewee.ModelBase.__new__
|
_additional_keys = None # needed by peewee.ModelBase.__new__
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -71,7 +71,7 @@ class SVG(poobrains.auth.Protected):
|
|||||||
return poobrains.helpers.ThemedPassthrough(super(SVG, self).view(mode=mode, handle=handle))
|
return poobrains.helpers.ThemedPassthrough(super(SVG, self).view(mode=mode, handle=handle))
|
||||||
|
|
||||||
|
|
||||||
@app.before_first_request
|
@app.setup
|
||||||
def register_svg_raw():
|
def register_svg_raw():
|
||||||
for cls in set(SVG.class_children()):
|
for cls in set(SVG.class_children()):
|
||||||
rule = os.path.join("/svg/", cls.__name__.lower(), '<handle>', 'raw')
|
rule = os.path.join("/svg/", cls.__name__.lower(), '<handle>', 'raw')
|
||||||
|
@ -207,7 +207,7 @@ y
|
|||||||
if name.isupper():
|
if name.isupper():
|
||||||
poobrains.app.config[name] = getattr(config, name)
|
poobrains.app.config[name] = getattr(config, name)
|
||||||
|
|
||||||
client.get('/') # first request that triggers before_first_request to finish booting poobrains
|
client.get('/') # first request that triggers app.run_setup to finish booting poobrains
|
||||||
|
|
||||||
|
|
||||||
def test_cli_minica(client):
|
def test_cli_minica(client):
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
$color_background_dark: rgba(8,8,8, 0.8);
|
$color_background_dark: rgba(8,8,8, 0.85);
|
||||||
$color_background_light: rgba(255,255,255, 0.8);
|
$color_background_light: rgba(255,255,255, 0.85);
|
||||||
$color_highlight: rgba(0,128,255, 0.8);
|
$color_highlight: rgba(0,128,255, 0.85);
|
||||||
/*$color_highlight: transparentize(rebeccapurple, 20%);*/
|
/*$color_highlight: transparentize(rebeccapurple, 20%);*/
|
||||||
$color_danger: rgba(255, 0, 128, 0.8);
|
$color_danger: rgba(255, 0, 128, 0.85);
|
||||||
$color_font_dark: opacify($color_background_dark, 10%);
|
$color_font_dark: opacify($color_background_dark, 10%);
|
||||||
$color_font_light: opacify($color_background_light, 10%);
|
$color_font_light: opacify($color_background_light, 10%);
|
||||||
$color_background_form: opacify($color_background_light, -0.3);
|
$color_background_form: opacify($color_background_light, -0.3);
|
||||||
|
@ -104,7 +104,8 @@
|
|||||||
@media (min-width: 56rem) {
|
@media (min-width: 56rem) {
|
||||||
|
|
||||||
#logo-link {
|
#logo-link {
|
||||||
display: flex !important;
|
display: block !important;
|
||||||
|
padding: 4rem 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
body > header {
|
body > header {
|
||||||
@ -113,7 +114,6 @@
|
|||||||
.sticky {
|
.sticky {
|
||||||
width: 13rem;
|
width: 13rem;
|
||||||
top: 11.5rem !important; /* 7.5rem logo height + 2rem space at top and bottom */
|
top: 11.5rem !important; /* 7.5rem logo height + 2rem space at top and bottom */
|
||||||
margin-bottom: 4rem; /* needed at least in firefox, to avoid vertical cutoff. should be the same as vertical padding for logo */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,10 +133,10 @@ html {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
/*overflow-y: scroll;*/ /* always show vertical scrollbar, viewport dependant widths stay the same */
|
/*overflow-y: scroll;*/ /* always show vertical scrollbar, viewport dependant widths stay the same */
|
||||||
background-image: url('/theme/bg.svg'), linear-gradient(45deg, lighten(opacify($color_background_dark, 100%), 15%), mix($color_highlight, $color_background_dark, 25%));
|
/*background-image: url('/theme/bg.svg'), linear-gradient(45deg, lighten(opacify($color_background_dark, 100%), 15%), mix($color_highlight, $color_background_dark, 25%));*/
|
||||||
|
background-image: url('/theme/bg.svg');
|
||||||
/*background-image: url('/theme/pooscape-probablyold.svg'), linear-gradient(to bottom, opacify($color_background_dark, 0.2), darken(opacify($color_highlight, 0.2), 40%) 100%);*/
|
/*background-image: url('/theme/pooscape-probablyold.svg'), linear-gradient(to bottom, opacify($color_background_dark, 0.2), darken(opacify($color_highlight, 0.2), 40%) 100%);*/
|
||||||
/*background-image: url('/theme/test.png');*/
|
background-color: opacify($color_background_dark, 100%);
|
||||||
background-color: #333;
|
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
background-attachment: fixed;
|
background-attachment: fixed;
|
||||||
@ -173,7 +173,6 @@ body {
|
|||||||
line-height: 3rem;
|
line-height: 3rem;
|
||||||
display: inherit;
|
display: inherit;
|
||||||
background: $color_background_light;
|
background: $color_background_light;
|
||||||
backdrop-filter: blur($backdrop_blur);
|
|
||||||
color: $color_font_dark;
|
color: $color_font_dark;
|
||||||
font-family: 'Orbitron', sans;
|
font-family: 'Orbitron', sans;
|
||||||
font-weight: 100;
|
font-weight: 100;
|
||||||
@ -226,25 +225,18 @@ body {
|
|||||||
flex-basis: 15rem;
|
flex-basis: 15rem;
|
||||||
flex-shrink: 1;
|
flex-shrink: 1;
|
||||||
flex-grow: 15;
|
flex-grow: 15;
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-self: stretch;
|
align-self: stretch;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-around;
|
|
||||||
max-height: 100vh;
|
max-height: 100vh;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
z-index: 200;
|
z-index: 200;
|
||||||
background-color: $color_background_dark;
|
background-color: $color_background_dark;
|
||||||
backdrop-filter: blur($backdrop_blur);
|
|
||||||
/*border-left: 0.25rem solid;
|
|
||||||
border-right: 0.25rem solid;
|
|
||||||
border-bottom: 0.25rem solid;
|
|
||||||
border-color: $color_border;*/
|
|
||||||
|
|
||||||
/*-webkit-clip-path: polygon(0 0, 0 calc(100% - 3rem), 50% 100%, 100% calc(100% - 3rem), 100% 0);*/
|
/*-webkit-clip-path: polygon(0 0, 0 calc(100% - 3rem), 50% 100%, 100% calc(100% - 3rem), 100% 0);*/
|
||||||
|
|
||||||
overflow: hidden;
|
overflow: auto;
|
||||||
|
|
||||||
&:nth-child(2) { /* means dashbar is rendered */
|
&:nth-child(2) { /* means dashbar is rendered */
|
||||||
margin-top: 3rem;
|
margin-top: 3rem;
|
||||||
@ -320,6 +312,8 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#logo {
|
#logo {
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
height: 7.5rem;
|
height: 7.5rem;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
@ -350,7 +344,6 @@ main {
|
|||||||
top: 0;
|
top: 0;
|
||||||
padding: 2rem 1rem;
|
padding: 2rem 1rem;
|
||||||
background: $color_background_light;
|
background: $color_background_light;
|
||||||
backdrop-filter: blur($backdrop_blur);
|
|
||||||
color: $color_font_dark;
|
color: $color_font_dark;
|
||||||
z-index: 110;
|
z-index: 110;
|
||||||
|
|
||||||
@ -510,7 +503,6 @@ main {
|
|||||||
& article.content-type-tag.mode-full > .content > .description {
|
& article.content-type-tag.mode-full > .content > .description {
|
||||||
margin-top: 0.5rem;
|
margin-top: 0.5rem;
|
||||||
background: $color_background_dark;
|
background: $color_background_dark;
|
||||||
backdrop-filter: blur($backdrop_blur);
|
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -533,7 +525,6 @@ main {
|
|||||||
margin: 0.25rem 0;
|
margin: 0.25rem 0;
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
background: $color_background_dark;
|
background: $color_background_dark;
|
||||||
backdrop-filter: blur($backdrop_blur);
|
|
||||||
|
|
||||||
&, a {
|
&, a {
|
||||||
color: opacify($color_font_light, -0.3);
|
color: opacify($color_font_light, -0.3);
|
||||||
@ -606,7 +597,6 @@ nav.menu {
|
|||||||
a {
|
a {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
background: $color_background_light;
|
background: $color_background_light;
|
||||||
backdrop-filter: blur($backdrop_blur);
|
|
||||||
width: 2rem;
|
width: 2rem;
|
||||||
height: 2rem;
|
height: 2rem;
|
||||||
line-height: 2.3rem; /* +0.3rem based on fiddling around in ff inspector */
|
line-height: 2.3rem; /* +0.3rem based on fiddling around in ff inspector */
|
||||||
@ -642,7 +632,6 @@ nav.menu {
|
|||||||
background-color: $color_background_dark;
|
background-color: $color_background_dark;
|
||||||
background-size: 32px 32px;
|
background-size: 32px 32px;
|
||||||
background-position: 4px 4px;
|
background-position: 4px 4px;
|
||||||
backdrop-filter: blur($backdrop_blur);
|
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
|
|
||||||
transition: background 0.3s linear, color 0.3s linear;
|
transition: background 0.3s linear, color 0.3s linear;
|
||||||
@ -677,7 +666,6 @@ ul {
|
|||||||
& > div.comment {
|
& > div.comment {
|
||||||
/* comments have transparent bg by default, avoid breaking the design when showing them outside of an article */
|
/* comments have transparent bg by default, avoid breaking the design when showing them outside of an article */
|
||||||
background: $color_background_dark;
|
background: $color_background_dark;
|
||||||
backdrop-filter: blur($backdrop_blur);
|
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -827,7 +815,6 @@ form {
|
|||||||
& > header {
|
& > header {
|
||||||
|
|
||||||
background: $color_background_light;
|
background: $color_background_light;
|
||||||
backdrop-filter: blur($backdrop_blur);
|
|
||||||
padding: 0.5rem 1rem;
|
padding: 0.5rem 1rem;
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
@ -856,7 +843,6 @@ form {
|
|||||||
|
|
||||||
& > div.content {
|
& > div.content {
|
||||||
background: $color_background_dark;
|
background: $color_background_dark;
|
||||||
backdrop-filter: blur($backdrop_blur);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -906,7 +892,6 @@ article {
|
|||||||
|
|
||||||
padding: 0.25rem 1rem;
|
padding: 0.25rem 1rem;
|
||||||
background: $color_background_light;
|
background: $color_background_light;
|
||||||
backdrop-filter: blur($backdrop_blur);
|
|
||||||
color: $color_font_dark;
|
color: $color_font_dark;
|
||||||
|
|
||||||
&::after {
|
&::after {
|
||||||
|
@ -69,14 +69,14 @@ svg#hexascroll {
|
|||||||
animation: decorotion 5s linear infinite;
|
animation: decorotion 5s linear infinite;
|
||||||
|
|
||||||
use {
|
use {
|
||||||
/*animation: scroll 10s linear infinite; /* apply the animation to every hexagon instead of the g so we don't get perspective fuckups */*/
|
animation: scroll 10s linear infinite; /* apply the animation to every hexagon instead of the g so we don't get perspective fuckups */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use {
|
use {
|
||||||
fill: opacify($color_background_dark, -0.2);
|
fill: opacify($color_background_dark, -0.2);
|
||||||
stroke: $color_background_light;
|
stroke: darken($color_highlight, 30%);
|
||||||
stroke-width: 2;
|
stroke-width: 2;
|
||||||
|
|
||||||
&.hexagon {
|
&.hexagon {
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
width="100%"
|
width="100%"
|
||||||
height="100%"
|
height="100%"
|
||||||
|
|
||||||
viewBox="0 0 100 100"
|
viewBox="0 0 100% 100%"
|
||||||
preserveAspectRatio="xMinYMin meet"
|
preserveAspectRatio="xMinYMin meet"
|
||||||
id="{{ content.dataset.ref_id }}"
|
id="{{ content.dataset.ref_id }}"
|
||||||
class="plot {{ content.__class__.__name__.lower()}}"
|
class="plot {{ content.__class__.__name__.lower()}}"
|
||||||
|
@ -57,7 +57,7 @@ class UploadForm(poobrains.auth.AutoForm):
|
|||||||
upload_file = self.fields['upload'].value
|
upload_file = self.fields['upload'].value
|
||||||
filename = self.fields['filename'].value
|
filename = self.fields['filename'].value
|
||||||
|
|
||||||
if filename is not '':
|
if filename != '':
|
||||||
|
|
||||||
file_path = os.path.join(self.instance.path, filename)
|
file_path = os.path.join(self.instance.path, filename)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user