= {
paths: [
{
style: 'stroke-width:1.5; stroke-linecap:round; stroke-linejoin:round;',
- d: 'M7 12.5L10 15.5L17 8.5',
+ d: 'M7 12.5L10 15.5L17 8.5'
},
{
- d:
- 'M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z',
- },
- ],
+ d: 'M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z'
+ }
+ ]
},
+ chevron: {
+ width: 24,
+ height: 24,
+ paths: [
+ {
+ style: `fill:transparent; stroke:black; stroke-width:${props.strokeWidth}px;`,
+ d: 'M6 9L12 15L18 9'
+ }
+ ]
+ }
}
-const props = defineProps({
- name: {
- type: String,
- default: 'slack',
- },
- scale: {
- type: [Number, String],
- default: 1,
- },
- paths: {
- type: Array,
- default: () => [],
- },
- polygons: {
- type: Array,
- default: () => [],
- },
- width: {
- type: Number,
- default: 24,
- },
- height: {
- type: Number,
- default: 24,
- },
- strokeWidth: {
- type: Number,
- default: 1,
- },
-})
-
-const computedPaths = computed(() => (props.paths.length ? props.paths as any as Path[] : Icons[props.name].paths))
+const computedPaths = computed(() =>
+ props.paths.length ? (props.paths as any as Path[]) : Icons[props.name].paths
+)
const computedPolygons = computed(() =>
- props.polygons.length ? props.polygons as Polygon[] : Icons[props.name].polygons,
+ props.polygons.length ? (props.polygons as Polygon[]) : Icons[props.name].polygons
)
const computedSvgViewbox = computed(() => {
const { width, height } = Icons[props.name]
diff --git a/src/components/legacy/bootstrap/BDropdown.vue b/src/components/legacy/bootstrap/BDropdown.vue
index b5a38cd89..3255cbc67 100644
--- a/src/components/legacy/bootstrap/BDropdown.vue
+++ b/src/components/legacy/bootstrap/BDropdown.vue
@@ -7,7 +7,7 @@
class="btn dropdown-toggle"
:class="{
[`btn-${size}`]: size != undefined,
- [`btn-${variant}`]: variant != undefined,
+ [`btn-${variant}`]: variant != undefined
}"
@click="isOpen = !isOpen"
ref="buttonRef"
@@ -15,6 +15,9 @@
{{ text }}
+
+
+
import { useAttrs, ref, watch } from 'vue'
import { useClickOutside } from '@/composables/useClickOutside'
+import Icon from '@/components/base/Icon.vue'
const props = defineProps({
size: String,
variant: String,
text: String,
right: Boolean,
+ initialIsOpen: Boolean
})
const emit = defineEmits(['shown', 'hidden'])
const attrs = useAttrs()
-const isOpen = ref(false)
+const isOpen = ref(props.initialIsOpen)
const allowedAttrs = ['onClick', 'title', 'class', 'style']
const unknownAttrs = Object.keys(attrs).filter(key => !allowedAttrs.includes(key))
@@ -65,17 +70,28 @@ watch(
emit('hidden')
}
},
- { immediate: true },
+ { immediate: true }
)
defineExpose({
- hide: () => (isOpen.value = false),
+ hide: () => (isOpen.value = false)
})
diff --git a/src/components/modules/vis/stories/PowerVis.stories.js b/src/components/modules/vis/stories/PowerVis.stories.js
index 814a1bba5..c6496d1e2 100644
--- a/src/components/modules/vis/stories/PowerVis.stories.js
+++ b/src/components/modules/vis/stories/PowerVis.stories.js
@@ -1,11 +1,11 @@
import { action } from '@storybook/addon-actions'
import PowerVisBase from '../PowerVisBase.vue'
-import './assets/legacy/bootstrap-impresso-theme.css'
+import '../../../../assets/legacy/bootstrap-impresso-theme.css'
export default {
title: 'Components/Modules/Vis/PowerVis',
- component: PowerVisBase,
+ component: PowerVisBase
}
const Template = args => ({
@@ -14,7 +14,7 @@ const Template = args => ({
return { args }
},
methods: {
- itemClicked: action('item clicked'),
+ itemClicked: action('item clicked')
},
template: `
@@ -27,7 +27,7 @@ const Template = args => ({
- `,
+ `
})
export const TRPassages = Template.bind({})
@@ -36,45 +36,45 @@ TRPassages.args = {
items: [
{
domain: {
- label: 'L\'Express',
- value: 'EXP',
+ label: "L'Express",
+ value: 'EXP'
},
value: {
count: 3186482,
items: [
{
term: 'EXP',
- count: 3186482,
- },
- ],
- },
+ count: 3186482
+ }
+ ]
+ }
},
{
domain: {
- label: 'L\'Impartial',
- value: 'IMP',
+ label: "L'Impartial",
+ value: 'IMP'
},
value: {
count: 2973547,
items: [
{
term: 'IMP',
- count: 2973547,
- },
- ],
- },
- },
+ count: 2973547
+ }
+ ]
+ }
+ }
],
itemsDictionary: {
- EXP: 'L\'Express',
- IMP: 'L\'Impartial',
+ EXP: "L'Express",
+ IMP: "L'Impartial"
},
meta: {
facetType: 'term',
domain: 'newspaper',
- filters: [],
- },
- },
+ filters: []
+ }
+ }
}
export const LineChart = Template.bind({})
@@ -85,26 +85,24 @@ LineChart.args = {
{
domain: 20,
value: {
- count: 3186482,
- },
+ count: 3186482
+ }
},
{
domain: 100,
value: {
- count: 3186482,
- },
- },
+ count: 3186482
+ }
+ }
],
meta: {
facetType: 'numeric',
domain: 'size',
- filters: [],
- },
- },
+ filters: []
+ }
+ }
}
-
-
export const BarChart = Template.bind({})
BarChart.args = {
@@ -112,7 +110,7 @@ BarChart.args = {
items: [
{
domain: {
- label: 'L\'Express',
+ label: "L'Express",
value: 'EXP'
},
value: {
@@ -126,7 +124,7 @@ BarChart.args = {
},
{
domain: {
- label: 'L\'Impartial',
+ label: "L'Impartial",
value: 'IMP'
},
value: {
@@ -175,7 +173,6 @@ BarChart.args = {
}
}
-
export const BarChartHorizontal = Template.bind({})
BarChartHorizontal.args = {
diff --git a/src/components/stories/ComposeSearchQuery.stories.ts b/src/components/stories/ComposeSearchQuery.stories.ts
new file mode 100644
index 000000000..76ef032b7
--- /dev/null
+++ b/src/components/stories/ComposeSearchQuery.stories.ts
@@ -0,0 +1,39 @@
+import type { Meta, StoryObj } from '@storybook/vue3'
+import ComposeSearchQuery from '../ComposeSearchQuery.vue'
+import type { Props } from '../ComposeSearchQuery.vue'
+
+const meta: Meta = {
+ title: 'Components/ComposeSearchQuery',
+ component: ComposeSearchQuery,
+ tags: ['autodocs'],
+ argTypes: {},
+ args: {},
+ render: args => {
+ return {
+ components: { ComposeSearchQuery },
+ setup() {
+ return { args }
+ },
+ template:
+ '
'
+ }
+ },
+ decorators: []
+} satisfies Meta
+
+export default meta
+type Story = StoryObj
+
+export const Default: Story = {
+ args: {
+ filters: [
+ {
+ type: 'string',
+ q: ['lune', 'soleil']
+ },
+ {
+ type: 'isFront'
+ }
+ ]
+ } as Props
+}
diff --git a/src/models/index.d.ts b/src/models/index.d.ts
index 09a1cb04f..15e5f011c 100644
--- a/src/models/index.d.ts
+++ b/src/models/index.d.ts
@@ -1,44 +1,48 @@
export interface Entity {
- uid: string,
+ uid: string
- name?: string,
- language?: string,
- htmlExcerpt?: string,
+ name?: string
+ language?: string
+ htmlExcerpt?: string
creator?: { username?: string }
lastModifiedDate?: Date
- y?: string,
+ y?: string
- firstIssue?: { date: Date },
- lastIssue?: { date: Date },
+ firstIssue?: { date: Date }
+ lastIssue?: { date: Date }
- countArticles?: Number,
- countIssues?: Number,
+ countArticles?: Number
+ countIssues?: Number
- start?: Number,
+ start?: Number
end?: Number
}
export interface Filter {
- q?: string[] | string,
- type: string,
- context?: string,
- precision?: string,
- op?: string,
+ q?: string[] | string
+ type: string
+ context?: string
+ precision?: string
+ op?: string
items?: Entity[]
}
+export interface FilterInterface extends Filter {
+ getQuery(): object
+}
+
export interface Bucket {
- val: string,
- count: number,
+ val: string
+ count: number
item?: Entity
}
export interface Facet {
type: string
- buckets: Bucket[],
- operators?: string[],
+ buckets: Bucket[]
+ operators?: string[]
numBuckets?: number
}
@@ -57,4 +61,4 @@ export interface TextReuseCluster {
timeCoverage: ClusterTimeCoverage
lexicalOverlap: number
connectedClustersCount: number
-}
\ No newline at end of file
+}
diff --git a/src/pages/SearchComposer.vue b/src/pages/SearchComposer.vue
new file mode 100644
index 000000000..ff47cb525
--- /dev/null
+++ b/src/pages/SearchComposer.vue
@@ -0,0 +1,101 @@
+
+
+ Search Query composer
+
+
+
+
+
+
+ serialized:
+
{{ serialized }}
+
+
+
+
+
+
+
diff --git a/src/pages/stories/SearchComposer.stories.ts b/src/pages/stories/SearchComposer.stories.ts
new file mode 100644
index 000000000..46f6bc77d
--- /dev/null
+++ b/src/pages/stories/SearchComposer.stories.ts
@@ -0,0 +1,27 @@
+import type { Meta, StoryObj } from '@storybook/vue3'
+import SearchComposer from '../SearchComposer.vue'
+
+const meta: Meta = {
+ title: 'Pages/SearchComposer',
+ component: SearchComposer,
+ tags: ['autodocs'],
+ argTypes: {},
+ args: {},
+ render: args => {
+ return {
+ components: { SearchComposer },
+ setup() {
+ return { args }
+ },
+ template: '
'
+ }
+ },
+ decorators: []
+} satisfies Meta
+
+export default meta
+type Story = StoryObj
+
+export const Default: Story = {
+ args: {}
+}
diff --git a/src/styles/style.css b/src/styles/style.css
new file mode 100644
index 000000000..aee8e804e
--- /dev/null
+++ b/src/styles/style.css
@@ -0,0 +1,390 @@
+@font-face {
+ font-family: 'Satoshi-Variable';
+ src:
+ url('/assets/fonts/Satoshi-Variable.woff2') format('woff2'),
+ url('/assets/fonts/Satoshi-Variable.woff') format('woff'),
+ url('/assets/fonts/Satoshi-Variable.ttf') format('truetype');
+ font-weight: 300 900;
+ font-display: swap;
+ font-style: normal;
+}
+
+@font-face {
+ font-family: 'Satoshi-VariableItalic';
+ src:
+ url('/assets/fonts/Satoshi-VariableItalic.woff2') format('woff2'),
+ url('/assets/fonts/Satoshi-VariableItalic.woff') format('woff'),
+ url('/assets/fonts/Satoshi-VariableItalic.ttf') format('truetype');
+ font-weight: 300 900;
+ font-display: swap;
+ font-style: italic;
+}
+
+:root {
+ --impresso-color-paper: #fafbf2;
+
+ --impresso-color-yellow-code: 255, 235, 120;
+ --impresso-color-yellow: #ffeb78;
+ --impresso-color-yellow-alpha-20: rgba(255, 235, 120, 0.2);
+ --impresso-color-yellow-alpha-30: rgba(255, 235, 120, 0.3);
+ --impresso-color-yellow-alpha-50: rgba(255, 235, 120, 0.5);
+ --impresso-color-yellow-alpha-80: rgba(255, 235, 120, 0.8);
+
+ --impresso-color-black: #343a40;
+ --impresso-color-black-rgb: 52, 58, 64;
+
+ --impresso-color-pastel-blue: rgba(86, 204, 242);
+ --impresso-color-pastel-blue-alpha-20: rgba(86, 204, 242, 0.2);
+
+ --impresso-border-radius-xs: 5px;
+ --impresso-border-radius-sm: 10px;
+ --impresso-border-radius-md: 15px;
+ --impresso-border-radius-lg: 20px;
+ --impresso-border-radius-xl: 30px;
+ --impresso-font-size-smallcaps: 0.72em;
+ --impresso-letter-spacing-smallcaps: 0.08em;
+ --impresso-letter-spacing-smallcaps-md: 0.12em;
+ --impresso-font-size-smaller: 0.85em;
+ --impresso-wght: 450;
+ --impresso-wght-bold: 700;
+ --impresso-wght-smallcaps: 580;
+ --impresso-wght-smallcaps-bold: 800;
+ --clr-white: #f8f8ff;
+ --clr-white-rgba-20: #ffffff33;
+ --clr-dark: var(--impresso-color-black);
+
+ --clr-grey-100: #3d4146;
+ --clr-grey-200: #5b5e65;
+ --clr-grey-300: #84868e;
+ --clr-grey-400: #a9aab4;
+ --clr-grey-500: #c2c3cb;
+ --clr-grey-600: #d4d5e1;
+ --clr-grey-700: #e1e1ee;
+ --clr-grey-800: #ececfb;
+ --clr-grey-900: #f8f8ff;
+ --clr-grey-100-rgba-20: #464d5333;
+ --clr-grey-200-rgba-20: #585d6633;
+ --clr-grey-300-rgba-20: #7c7f8c33;
+ --clr-grey-400-rgba-20: #a0a1a333;
+ --clr-grey-500-rgba-20: #b1b2c633;
+ --clr-grey-600-rgba-20: #c3c4d933;
+ --clr-grey-700-rgba-20: #d5d5ec33;
+ --clr-grey-800-rgba-20: #e7e7ff33;
+ --clr-grey-900-rgba-20: #f8f8ff33;
+
+ --spacing-1: 0.25rem;
+ --spacing-2: 0.5rem;
+ --spacing-3: 1rem;
+ --spacing-4: 1.5rem;
+ --spacing-5: 3rem;
+ --negative-spacing-1: -0.25rem;
+ --negative-spacing-2: -0.5rem;
+ --negative-spacing-3: -1rem;
+ --negative-spacing-4: -1.5rem;
+ --negative-spacing-5: -3rem;
+
+ --accent: #28a745;
+ --impresso-yellow: #ffeb78;
+ --border-radius-sm: 3px;
+ --border-radius-md: 8px;
+ --border-radius-lg: 12px;
+
+ /* Bootstrap overrides */
+ --bs-font-sans-serif: 'Satoshi-Variable', sans-serif;
+ --bs-font-sans-serif-italic: 'Satoshi-VariableItalic', sans-serif;
+ --bs-font-serif-italic: 'questa', serif;
+ --bs-font-serif: 'questa', serif;
+ --bs-font-monospace: monospace;
+ --bs-border-radius-lg: var(--impresso-border-radius-lg);
+ --bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
+ --bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.125);
+ --bs-box-shadow-md: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
+ --bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);
+ --bs-box-shadow-focus: 0 0 0 0.2rem #ffeb78;
+ --bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);
+
+ --bs-font-size-base: 1rem;
+ --impresso-font-size-3: 1.75rem;
+ --impresso-font-size-4: 1.5rem;
+
+ --impresso-transition-ease: cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+body {
+ font-family: var(--bs-font-sans-serif);
+ font-weight: 450;
+ font-variation-settings: 'wght' 450;
+ text-rendering: optimizeLegibility;
+}
+select {
+ appearance: inherit;
+}
+body,
+html {
+ height: 100%;
+}
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+.h1,
+.h2,
+.h3,
+.h4,
+.h5,
+.h6 {
+ font-family: var(--bs-font-serif);
+ font-weight: 375;
+ font-variation-settings: 'wght' 375;
+
+ i,
+ em {
+ font-family: var(--bs-font-serif-italic);
+ font-weight: 375;
+ font-variation-settings: 'wght' 375;
+ }
+}
+i,
+em {
+ font-style: normal;
+}
+.text-sans,
+.sans,
+legend,
+.small-caps,
+.textbox-fancy .label,
+.heading-top,
+.btn-sm,
+.btn-group-sm > .btn,
+h6.dropdown-header {
+ font-family: var(--bs-font-sans-serif);
+ font-weight: 450;
+ font-variation-settings: 'wght' 450;
+}
+
+label {
+ font-family: var(--bs-font-sans-serif);
+ font-weight: 450;
+ font-variation-settings: 'wght' 450;
+}
+
+.checkbox label,
+.small-caps {
+ text-transform: uppercase;
+ font-size: var(--impresso-font-size-smallcaps);
+ font-variant: normal;
+ letter-spacing: var(--impresso-letter-spacing-smallcaps);
+ font-weight: var(--impresso-wght-smallcaps);
+ font-variation-settings: 'wght' var(--impresso-wght-smallcaps);
+}
+.font-weight-bold {
+ font-weight: 700;
+ font-variation-settings: 'wght' 700;
+}
+.btn-sm,
+.btn-group-sm > .btn {
+ font-size: var(--impresso-font-size-smallcaps);
+ text-transform: uppercase;
+ font-variant: normal;
+ letter-spacing: var(--impresso-letter-spacing-smallcaps);
+ line-height: 2em;
+ font-weight: var(--impresso-wght-smallcaps);
+ font-variation-settings: 'wght' var(--impresso-wght-smallcaps);
+ padding: 0.3em 0.95em 0.25em 0.95em;
+ border-radius: var(--border-radius-sm);
+ white-space: nowrap;
+}
+.input-group .btn,
+.btn-group-sm > .btn {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+}
+.input-group .btn:first-of-type,
+.btn-group-sm > .btn:first-of-type {
+ border-top-left-radius: var(--border-radius-sm);
+ border-bottom-left-radius: var(--border-radius-sm);
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+}
+.input-group .btn:last-of-type,
+.btn-group-sm > .btn:last-of-type {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+ border-top-right-radius: var(--border-radius-sm);
+ border-bottom-right-radius: var(--border-radius-sm);
+}
+.btn-outline-primary,
+.btn-outline-secondary,
+.btn-primary,
+.btn-outline-success {
+ border-radius: var(--border-radius-sm);
+ box-shadow: var(--bs-box-shadow-sm);
+}
+.btn.disabled,
+.btn:disabled {
+ opacity: 0.45 !important;
+}
+.btn-outline-primary.disabled,
+.btn-outline-primary:disabled {
+ background-color: var(--clr-grey-600) !important;
+}
+
+.btn-outline-icon {
+ border-radius: 50%;
+ position: relative;
+ width: 1.5rem;
+ height: 1.5rem;
+ padding: 0;
+ margin: 0;
+ font-size: 1rem;
+ border-color: var(--clr-grey-600);
+ color: var(--clr-grey-600);
+ box-shadow: var(--bs-box-shadow-sm);
+ > span {
+ color: inherit;
+ }
+ &:hover {
+ border-color: #17191c;
+ color: #17191c;
+ }
+}
+
+.btn-outline-icon > span {
+ position: absolute;
+ top: 3px;
+ left: 3px;
+}
+.btn-md {
+ border-radius: var(--border-radius-md);
+ box-shadow: var(--bs-box-shadow-sm);
+ border-width: 0;
+
+ font-variation-settings: 'wght' var(--impresso-wght-smallcaps);
+}
+.shadow-sm {
+ box-shadow: var(--bs-box-shadow-sm);
+}
+.drop-shadow {
+ box-shadow: var(--bs-box-shadow-md);
+}
+
+.navbar-nav label {
+ text-transform: uppercase;
+ font-size: var(--impresso-font-size-smallcaps);
+ font-variant: normal;
+ letter-spacing: var(--impresso-letter-spacing-smallcaps);
+ font-weight: var(--impresso-wght-smallcaps);
+ font-variation-settings: 'wght' var(--impresso-wght-smallcaps);
+}
+
+/* ul nav pills etc...*/
+ul.nav.nav-pills {
+ border-bottom: 1px solid var(--clr-grey-200);
+}
+ul.nav.nav-pills .nav-item .nav-link {
+ background-color: transparent;
+ font-variant: normal;
+ letter-spacing: var(--impresso-letter-spacing-smallcaps);
+ text-transform: uppercase;
+ font-size: var(--impresso-font-size-smallcaps);
+ font-weight: var(--impresso-wght-smallcaps);
+ font-variation-settings: 'wght' var(--impresso-wght-smallcaps);
+ border-bottom: 1px solid transparent;
+}
+ul.nav.nav-pills .nav-item.active .nav-link,
+ul.nav.nav-pills .nav-item .nav-link.active {
+ color: var(--impresso-color-black);
+ font-weight: var(--impresso-wght-smallcaps-bold);
+ font-variation-settings: 'wght' var(--impresso-wght-smallcaps-bold);
+ box-shadow:
+ var(--clr-grey-200) 0px 2px 0px 0px,
+ var(--clr-grey-200) 0px 2px 0px 0px;
+ border-bottom: 1px solid var(--clr-grey-200);
+}
+ul.nav.nav-pills .nav-item:hover .nav-link {
+ color: var(--impresso-color-black);
+ /** box shadow that looks like a border bottom solid */
+ box-shadow: var(--impresso-color-black) 0px 2px 0px 0px;
+}
+
+/* impresso-specific pseudo-bootstrap implementation */
+.btn-icon {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ margin: var(--spacing-2);
+ padding: var(--spacing-1);
+ border-radius: 50%;
+ border: 1px solid transparent;
+ transition: background-color 0.5s var(--impresso-transition-ease);
+}
+.btn-icon > path {
+ fill: transparent;
+}
+.btn-icon:hover,
+.btn-icon.active {
+ background-color: var(--impresso-yellow);
+ border-color: var(--impresso-yellow);
+}
+.btn-icon:hover,
+.btn-icon:focus {
+ box-shadow: var(--bs-box-shadow-focus);
+}
+.btn-icon.active:focus {
+ box-shadow: none;
+}
+
+/* SVGs */
+svg text {
+ font-family: var(--bs-font-sans-serif), sans-serif;
+}
+svg g.tick > line {
+ stroke: var(--clr-grey-300);
+}
+svg path.domain {
+ stroke: var(--clr-grey-300);
+}
+
+/* other utilities */
+
+.rounded {
+ border-radius: var(--border-radius-md) !important;
+}
+.rounded-lg {
+ border-radius: var(--border-radius-lg) !important;
+}
+.bg-medium {
+ background: var(--clr-grey-300);
+}
+.pt-1px {
+ padding-top: 1px;
+}
+.pb-1px {
+ padding-bottom: 1px;
+}
+.mt-1px {
+ margin-top: 1px;
+}
+.mt-2px {
+ margin-top: 2px;
+}
+.mb-1px {
+ margin-bottom: 1px;
+}
+.mr-1px {
+ margin-right: 1px;
+}
+.ml-1px {
+ margin-left: 1px;
+}
+.opacity-50 {
+ opacity: 0.5;
+}
+
+.border-primary {
+ border-color: var(--impresso-color-black) !important;
+}