diff --git a/src/App.vue b/src/App.vue index 1b438a1..28f6cda 100644 --- a/src/App.vue +++ b/src/App.vue @@ -75,6 +75,10 @@ export default Vue.extend({ @import "./styles/responsive.scss"; @import "./styles/variables.scss"; +:root { + font-size: 16px; +} + html { scroll-behavior: smooth; } diff --git a/src/assets/icon-exit.svg b/src/assets/icon-exit.svg new file mode 100644 index 0000000..85a4d05 --- /dev/null +++ b/src/assets/icon-exit.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/ui/List.vue b/src/components/ui/List.vue index 803e439..0ca3ec3 100644 --- a/src/components/ui/List.vue +++ b/src/components/ui/List.vue @@ -273,7 +273,7 @@ export default Vue.extend({ font-size: calc(0.6rem + 0.35vw); @include smallScreen() { - font-size: 0.65rem; + font-size: 0.75rem; } thead th { diff --git a/src/components/ui/Options.vue b/src/components/ui/Options.vue index 1b9e1b7..86f97e9 100644 --- a/src/components/ui/Options.vue +++ b/src/components/ui/Options.vue @@ -37,7 +37,7 @@ export default Vue.extend({ } .button { - font-size: 0.8em; + font-size: 0.9em; img { width: 1.3em; diff --git a/src/components/utils/ListFilter.vue b/src/components/utils/ListFilter.vue index a99bea8..6bcd02f 100644 --- a/src/components/utils/ListFilter.vue +++ b/src/components/utils/ListFilter.vue @@ -1,168 +1,51 @@ @@ -172,119 +55,170 @@ import { mapActions } from "vuex"; export default Vue.extend({ name: "list-filter", - watch: { - gridElements: { - handler: (v1, v2) => {}, - deep: true - } - }, data: () => ({ - oneWay: true, - twoWay: true, - levelFrom: 0, - levelTo: 20, - oneWayCatenary: 0, - oneWayOther: 0, - twoWayCatenary: 0, - twoWayOther: 0, - - gridElements: { - access: { - title: "Dostępność", - type: "checkbox", - items: [ - { - id: "is-default", - value: true, - name: "default", - content: "w paczce z grą" - }, - { - id: "not-default", - value: true, - name: "notDefault", - content: "poza paczką z grą" - }, - { - id: "non-public", - value: true, - name: "nonPublic", - content: "niepubliczna" - } - ] + options: [ + { + id: "is-default", + name: "default", + section: "access", + value: true, + defaultValue: true, + content: "W PACZCE" + }, + { + id: "not-default", + name: "notDefault", + section: "access", + value: true, + defaultValue: true, + content: "POZA PACZKĄ" + }, + { + id: "non-public", + name: "nonPublic", + section: "access", + value: true, + defaultValue: true, + content: "NIEPUBLICZNA" + }, + { + id: "SPK", + name: "SPK", + section: "control", + value: true, + defaultValue: true, + content: "SPK" + }, + { + id: "SCS", + name: "SCS", + section: "control", + value: true, + defaultValue: true, + content: "SCS" + }, + { + id: "by-hand", + name: "ręczne", + section: "control", + value: true, + defaultValue: true, + content: "RĘCZNE" + }, + { + id: "levers", + name: "mechaniczne", + section: "control", + value: true, + defaultValue: true, + content: "MECHANICZNE" + }, + { + id: "modern", + name: "współczesna", + section: "signals", + value: true, + defaultValue: true, + content: "WSPÓŁCZESNA" + }, + { + id: "semaphore", + name: "kształtowa", + section: "signals", + value: true, + defaultValue: true, + content: "KSZTAŁTOWA" + }, + { + id: "mixed", + name: "mieszana", + section: "signals", + value: true, + defaultValue: true, + content: "MIESZANA" + }, + { + id: "historic", + name: "historyczna", + section: "signals", + value: true, + defaultValue: true, + content: "HISTORYCZNA" }, - control: { - title: "Sterowanie", - type: "checkbox", - - items: [ - { - id: "SPK", - value: true, - name: "SPK", - content: "SPK" - }, - { - id: "SCS", - value: true, - name: "SCS", - content: "SCS" - }, - { - id: "by-hand", - value: true, - name: "ręczne", - content: "ręczne" - }, - { - id: "levers", - value: true, - name: "mechaniczne", - content: "mechaniczne" - } - ] + { + id: "free", + name: "free", + section: "status", + value: true, + defaultValue: true, + content: "WOLNA" }, - - signals: { - title: "Sygnalizacja", - type: "checkbox", - - items: [ - { - id: "modern", - value: true, - name: "współczesna", - content: "współczesna" - }, - { - id: "semaphore", - value: true, - name: "kształtowa", - content: "kształtowa" - }, - { - id: "mixed", - value: true, - name: "mieszana", - content: "mieszana" - }, - { - id: "historic", - value: true, - name: "historyczna", - content: "historyczna" - } - ] + { + id: "occupied", + name: "occupied", + section: "status", + value: true, + defaultValue: true, + content: "ZAJĘTA" }, - - status: { - title: "Status", - type: "checkbox", - - items: [] + { + id: "ending", + name: "ending", + section: "status", + value: true, + defaultValue: true, + content: "KOŃCZY" } - } + ], + + sliders: [ + { + id: "min-level", + name: "minLevel", + minRange: 0, + maxRange: 20, + value: 0, + defaultValue: 0, + content: "MINIMALNY WYMAGANY POZIOM DYŻURNEGO" + }, + { + id: "min-oneway-e", + name: "minOneWayCatenary", + minRange: 0, + maxRange: 5, + value: 0, + defaultValue: 0, + content: "MINIMALNA LICZBA SZLAKÓW JEDNOTOROWYCH ZELEKTRYFIKOWANYCH" + }, + { + id: "min-oneway-ne", + name: "minOneWay", + minRange: 0, + maxRange: 5, + value: 0, + defaultValue: 0, + content: "MINIMALNA LICZBA SZLAKÓW JEDNOTOROWYCH NIEZELEKTRYFIKOWANYCH" + }, + { + id: "min-twoway-e", + name: "minTwoWayCatenary", + minRange: 0, + maxRange: 5, + value: 0, + defaultValue: 0, + content: "MINIMALNA LICZBA SZLAKÓW DWUTOROWYCH ZELEKTRYFIKOWANYCH" + }, + { + id: "min-twoway-ne", + name: "minTwoWay", + minRange: 0, + maxRange: 5, + value: 0, + defaultValue: 0, + content: "MINIMALNA LICZBA SZLAKÓW DWUTOROWYCH NIEZELEKTRYFIKOWANYCH" + } + ] }), props: ["exit"], methods: { @@ -299,20 +233,8 @@ export default Vue.extend({ }); }, reset() { - for (const [key, value] of Object.entries(this.gridElements)) { - for (const item of this.gridElements[key].items) { - item.value = true; - } - } - - this.oneWay = true; - this.twoWay = true; - this.levelFrom = 0; - this.levelTo = 20; - this.oneWayCatenary = 0; - this.oneWayOther = 0; - this.twoWayCatenary = 0; - this.twoWayOther = 0; + this.options.forEach(option => (option.value = option.defaultValue)); + this.sliders.forEach(slider => (slider.value = slider.defaultValue)); this.resetFilters(); }, @@ -337,74 +259,249 @@ export default Vue.extend({ opacity: 0; } -.list-filter { +.filter-card { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); + z-index: 0; + overflow: auto; - max-height: 90%; + max-height: 95vh; padding: 0.5em; + max-width: 600px; + width: 65%; - background: rgba(black, 0.85); - white-space: nowrap; - font-size: calc(0.6rem + 0.4vw); + background: #262a2e; + + font-size: calc(0.75rem + 0.4vw); @include smallScreen() { - width: 100vw; + width: 85vw; font-size: 1em; } + box-shadow: 0 0 15px 5px #474747; +} + +.card { + &-exit { + position: absolute; + top: 0; + right: 0; + margin: 0.8em; + + img { + width: 1.1em; + } + + cursor: pointer; + } + + &-title { + font-size: 2em; + font-weight: 700; + color: $accentCol; + + margin: 0.5em 0; + } + + &-options { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(6em, 1fr)); + padding: 0 1.5em; + } + + &-sliders { + margin-top: 1em; + } + + &-reset { + margin-top: 0.7em; + } } -.exit { - position: absolute; - top: 0; - right: 0; - padding: 0.4rem; - font-size: calc(1rem + 0.4vw); +.option { + margin: 0.3em; - cursor: pointer; -} + &-input { + display: none; -.list-filter-title { - text-align: center; - font-size: 1.9em; - font-weight: bold; -} + &:not(:checked) + span { + background-color: #585858; -.grid { - &-row { - display: flex; - justify-content: center; - - @include smallScreen() { - flex-wrap: wrap; + &::before { + box-shadow: none; + } } } - &-col { - padding: 0.3rem; - } - - &-item { + &-content { user-select: none; -moz-user-select: none; -webkit-user-select: none; - } -} -.item { - &-title { + width: 100%; text-align: center; - margin-bottom: 0.5rem; - font-weight: bold; - color: $accentCol; + + cursor: pointer; + + padding: 0.6em 0.5em; + border-radius: 0.4em; + + font-size: 0.65em; + + background-color: #333; + + display: inline-block; + position: relative; + + transition: all 0.2s; + + &.access { + background-color: #e03b07; + + &::before { + box-shadow: 0 0 6px 1px #e03b07; + } + } + + &.control { + background-color: #0085ff; + + &::before { + box-shadow: 0 0 6px 1px #0085ff; + } + } + + &.signals { + background-color: #b000bf; + + &::before { + box-shadow: 0 0 6px 1px #b000bf; + } + } + + &.status { + background-color: #05b702; + + &::before { + box-shadow: 0 0 6px 1px #05b702; + } + } + + &::before { + position: absolute; + content: ""; + top: 0; + left: 0; + + width: 100%; + height: 100%; + + border-radius: inherit; + } } } -button.button { - margin-top: 0.5em; +.slider { + display: flex; + + padding: 0.5em; + + &-value { + display: flex; + justify-content: center; + align-items: center; + + color: $accentCol; + margin-right: 0.3em; + padding: 0.1em 0.2em; + + font-size: 1.1em; + font-weight: 500; + + border-radius: 0.2em; + } + + &-content { + display: flex; + align-items: center; + + font-size: 0.6em; + } + + &-input { + -webkit-appearance: none; + appearance: none; + background: none; + border: none; + outline: none; + + min-width: 25%; + + &::-webkit-slider-thumb { + -webkit-appearance: none; + + height: 20px; + width: 20px; + margin-top: -7px; + + border-radius: 50%; + + background: white; + border: 4px solid $accentCol; + + @include smallScreen() { + width: 15px; + height: 15px; + margin-top: -5px; + border: 3px solid $accentCol; + } + } + + &::-moz-range-thumb { + height: 15px; + width: 15px; + + border-radius: 50%; + + background: white; + border: 4px solid $accentCol; + + cursor: pointer; + + @include smallScreen() { + width: 15px; + height: 15px; + border: 3px solid $accentCol; + } + } + + &::-webkit-slider-runnable-track { + width: 100%; + height: 5px; + cursor: pointer; + background: #ffffff; + border-radius: 1em; + } + + &::-moz-range-track { + width: 100%; + height: 5px; + cursor: pointer; + background: #ffffff; + border-radius: 1em; + } + + &::-ms-track { + width: 100%; + height: 5px; + cursor: pointer; + background: #ffffff; + border-radius: 1em; + } + } } \ No newline at end of file diff --git a/src/store/modules/store.ts b/src/store/modules/store.ts index 880a585..a0b10d2 100644 --- a/src/store/modules/store.ts +++ b/src/store/modules/store.ts @@ -23,9 +23,10 @@ class Store extends VuexModule { signalType: string; controlType: string; default: boolean; - nonPublic: boolean + nonPublic: boolean; routes: { oneWay: { catenary: number; noCatenary: number; }, twoWay: { catenary: number; noCatenary: number; } }; online: boolean; + occupiedTo: string; }[] = []; private filteredStations: {}[] = []; @@ -42,38 +43,19 @@ class Store extends VuexModule { "kształtowa": false, "historyczna": false, "mieszana": false, - "levelFrom": 0, - "levelTo": 20, - "1track-ne": 0, - "2track-ne": 0, - "1track-e": 0, - "2track-e": 0, + "minLevel": 0, + "minOneWayCatenary": 0, + "minOneWay": 0, + "minTwoWayCatenary": 0, + "minTwoWay": 0, "no-1track": false, - "no-2track": false + "no-2track": false, + "free": false, + "occupied": false, + "ending": false } as const; - private filters = { - "default": false, - "notDefault": false, - "nonPublic": false, - "SPK": false, - "SCS": false, - "ręczne": false, - "mechaniczne": false, - "współczesna": false, - "kształtowa": false, - "historyczna": false, - "mieszana": false, - "levelFrom": 0, - "levelTo": 20, - "1track-ne": 0, - "2track-ne": 0, - "1track-e": 0, - "2track-e": 0, - "no-1track": false, - "no-2track": false - } as any; - + private filters: any = this.filterInitStates; get getStationCount(): number { return this.stationCount; @@ -210,21 +192,23 @@ class Store extends VuexModule { if ((station.nonPublic || !station.reqLevel) && this.filters['nonPublic']) return false; if (!station.reqLevel) return true; + if (station.online && this.filters['occupied']) return false; + if (!station.online && this.filters['free']) return false; + if (station.online && station.occupiedTo == "KOŃCZY" && this.filters['ending']) return false; + if (station.default && this.filters['default']) return false; if (!station.default && this.filters['notDefault']) return false; - if (station.reqLevel < this.filters['level-from']) return false; - if (station.reqLevel > this.filters['level-to']) return false; + if (station.reqLevel < this.filters['minLevel']) return false; if (this.filters["no-1track"] && (station.routes.oneWay.catenary != 0 || station.routes.oneWay.noCatenary != 0)) return false; if (this.filters["no-2track"] && (station.routes.twoWay.catenary != 0 || station.routes.twoWay.noCatenary != 0)) return false; - if (station.routes.oneWay.catenary < this.filters['1track-e']) return false; - if (station.routes.oneWay.noCatenary < this.filters['1track-ne']) return false; - - if (station.routes.twoWay.catenary < this.filters['2track-e']) return false; - if (station.routes.twoWay.noCatenary < this.filters['2track-ne']) return false; + if (station.routes.oneWay.catenary < this.filters['minOneWayCatenary']) return false; + if (station.routes.oneWay.noCatenary < this.filters['minOneWay']) return false; + if (station.routes.twoWay.catenary < this.filters['minTwoWayCatenary']) return false; + if (station.routes.twoWay.noCatenary < this.filters['minTwoWay']) return false; if (this.filters[station.controlType]) return false; if (this.filters[station.signalType]) return false; @@ -271,6 +255,7 @@ class Store extends VuexModule { if (!toUpdate) { this.stations[i].online = false; + this.stations[i].occupiedTo = "WOLNA"; continue; } diff --git a/src/styles/variables.scss b/src/styles/variables.scss index bec59b5..08b0f2e 100644 --- a/src/styles/variables.scss +++ b/src/styles/variables.scss @@ -6,5 +6,5 @@ $bgCol: #525252; $errorCol: #ff1919; $warningCol: #ff975b; -$accentCol: #ffc62b; +$accentCol: #ffc014; $accent2Col: #ff3d5d;